From 42fdf2232201a5c2303b32e0ec5025cfaef52670 Mon Sep 17 00:00:00 2001 From: cvs2svn Date: Fri, 17 Sep 2010 08:56:44 +0000 Subject: [PATCH 001/844] This commit was manufactured by cvs2svn to create tag 'v0_5_1'. Sprout from master 2010-09-17 08:56:43 UTC Erik C. Thauvin 'Added "Posted by" attribution in the feed's entry description.' Delete: .cvsignore ChangeLog.txt README.txt ant/jreleaseinfo-1.3.0.jar build.properties build.xml lib/MathEvaluator.jar lib/commons-cli-1.2.jar lib/commons-codec-1.4.jar lib/commons-httpclient-3.1.jar lib/commons-logging-1.1.1.jar lib/commons-net-1.4.1.jar lib/delicious-1.14.jar lib/jakarta-oro-2.0.8.jar lib/jdom-1.1.jar lib/jweather-0.2.5.jar lib/log4j-1.2.16.jar lib/ostermillerutils_1_07_00.jar lib/pircbot.jar lib/rome-1.0.jar lib/rome-fetcher-1.0.jar lib/twitter4j-core-2.1.5-SNAPSHOT.jar licenses/Apache LICENSE.txt licenses/JDOM License.txt licenses/JWeather License.txt licenses/License.txt licenses/OstermillerUtil License.txt licenses/PircBot License.html licenses/ROME License.txt licenses/Twitter4J LICENSE.txt licenses/delicious-java License.txt mobibot.fb mobibot.iml mobibot.ipr properties/fetcher.properties properties/log4j.properties properties/mobibot.properties src/net/thauvin/erik/mobibot/CurrencyConverter.java src/net/thauvin/erik/mobibot/DeliciousPoster.java src/net/thauvin/erik/mobibot/EntryComment.java src/net/thauvin/erik/mobibot/EntryLink.java src/net/thauvin/erik/mobibot/FeedReader.java src/net/thauvin/erik/mobibot/GoogleSearch.java src/net/thauvin/erik/mobibot/Identica.java src/net/thauvin/erik/mobibot/StockQuote.java src/net/thauvin/erik/mobibot/SwingWorker.java src/net/thauvin/erik/mobibot/Twitter.java src/net/thauvin/erik/mobibot/TwitterOAuth.java src/net/thauvin/erik/mobibot/Weather.java website/simple.css --- .cvsignore | 8 - ChangeLog.txt | 294 --------- README.txt | 23 - ant/jreleaseinfo-1.3.0.jar | Bin 23925 -> 0 bytes build.properties | 12 - build.xml | 52 -- lib/MathEvaluator.jar | Bin 5762 -> 0 bytes lib/commons-cli-1.2.jar | Bin 41123 -> 0 bytes lib/commons-codec-1.4.jar | Bin 58160 -> 0 bytes lib/commons-httpclient-3.1.jar | Bin 305001 -> 0 bytes lib/commons-logging-1.1.1.jar | Bin 60841 -> 0 bytes lib/commons-net-1.4.1.jar | Bin 180792 -> 0 bytes lib/delicious-1.14.jar | Bin 23859 -> 0 bytes lib/jakarta-oro-2.0.8.jar | Bin 65261 -> 0 bytes lib/jdom-1.1.jar | Bin 153115 -> 0 bytes lib/jweather-0.2.5.jar | Bin 44542 -> 0 bytes lib/log4j-1.2.16.jar | Bin 481534 -> 0 bytes lib/ostermillerutils_1_07_00.jar | Bin 525947 -> 0 bytes lib/pircbot.jar | Bin 76700 -> 0 bytes lib/rome-1.0.jar | Bin 219671 -> 0 bytes lib/rome-fetcher-1.0.jar | Bin 29876 -> 0 bytes lib/twitter4j-core-2.1.5-SNAPSHOT.jar | Bin 406830 -> 0 bytes licenses/Apache LICENSE.txt | 202 ------ licenses/JDOM License.txt | 56 -- licenses/JWeather License.txt | 340 ---------- licenses/License.txt | 29 - licenses/OstermillerUtil License.txt | 13 - licenses/PircBot License.html | 60 -- licenses/ROME License.txt | 14 - licenses/Twitter4J LICENSE.txt | 26 - licenses/delicious-java License.txt | 29 - mobibot.fb | 21 - mobibot.iml | 166 ----- mobibot.ipr | 586 ------------------ properties/fetcher.properties | 0 properties/log4j.properties | 18 - properties/mobibot.properties | 22 - .../erik/mobibot/CurrencyConverter.java | 231 ------- .../thauvin/erik/mobibot/DeliciousPoster.java | 154 ----- .../thauvin/erik/mobibot/EntryComment.java | 137 ---- src/net/thauvin/erik/mobibot/EntryLink.java | 459 -------------- src/net/thauvin/erik/mobibot/FeedReader.java | 132 ---- .../thauvin/erik/mobibot/GoogleSearch.java | 134 ---- src/net/thauvin/erik/mobibot/Identica.java | 141 ----- src/net/thauvin/erik/mobibot/StockQuote.java | 165 ----- src/net/thauvin/erik/mobibot/SwingWorker.java | 131 ---- src/net/thauvin/erik/mobibot/Twitter.java | 133 ---- .../thauvin/erik/mobibot/TwitterOAuth.java | 81 --- src/net/thauvin/erik/mobibot/Weather.java | 196 ------ website/simple.css | 52 -- 50 files changed, 4117 deletions(-) delete mode 100644 .cvsignore delete mode 100644 ChangeLog.txt delete mode 100644 README.txt delete mode 100644 ant/jreleaseinfo-1.3.0.jar delete mode 100644 build.properties delete mode 100644 build.xml delete mode 100644 lib/MathEvaluator.jar delete mode 100644 lib/commons-cli-1.2.jar delete mode 100644 lib/commons-codec-1.4.jar delete mode 100644 lib/commons-httpclient-3.1.jar delete mode 100644 lib/commons-logging-1.1.1.jar delete mode 100644 lib/commons-net-1.4.1.jar delete mode 100644 lib/delicious-1.14.jar delete mode 100644 lib/jakarta-oro-2.0.8.jar delete mode 100644 lib/jdom-1.1.jar delete mode 100644 lib/jweather-0.2.5.jar delete mode 100644 lib/log4j-1.2.16.jar delete mode 100644 lib/ostermillerutils_1_07_00.jar delete mode 100644 lib/pircbot.jar delete mode 100644 lib/rome-1.0.jar delete mode 100644 lib/rome-fetcher-1.0.jar delete mode 100644 lib/twitter4j-core-2.1.5-SNAPSHOT.jar delete mode 100644 licenses/Apache LICENSE.txt delete mode 100644 licenses/JDOM License.txt delete mode 100644 licenses/JWeather License.txt delete mode 100644 licenses/License.txt delete mode 100644 licenses/OstermillerUtil License.txt delete mode 100644 licenses/PircBot License.html delete mode 100644 licenses/ROME License.txt delete mode 100644 licenses/Twitter4J LICENSE.txt delete mode 100644 licenses/delicious-java License.txt delete mode 100644 mobibot.fb delete mode 100644 mobibot.iml delete mode 100644 mobibot.ipr delete mode 100644 properties/fetcher.properties delete mode 100644 properties/log4j.properties delete mode 100644 properties/mobibot.properties delete mode 100644 src/net/thauvin/erik/mobibot/CurrencyConverter.java delete mode 100644 src/net/thauvin/erik/mobibot/DeliciousPoster.java delete mode 100644 src/net/thauvin/erik/mobibot/EntryComment.java delete mode 100644 src/net/thauvin/erik/mobibot/EntryLink.java delete mode 100644 src/net/thauvin/erik/mobibot/FeedReader.java delete mode 100644 src/net/thauvin/erik/mobibot/GoogleSearch.java delete mode 100644 src/net/thauvin/erik/mobibot/Identica.java delete mode 100644 src/net/thauvin/erik/mobibot/StockQuote.java delete mode 100644 src/net/thauvin/erik/mobibot/SwingWorker.java delete mode 100644 src/net/thauvin/erik/mobibot/Twitter.java delete mode 100644 src/net/thauvin/erik/mobibot/TwitterOAuth.java delete mode 100644 src/net/thauvin/erik/mobibot/Weather.java delete mode 100644 website/simple.css diff --git a/.cvsignore b/.cvsignore deleted file mode 100644 index 3369402..0000000 --- a/.cvsignore +++ /dev/null @@ -1,8 +0,0 @@ -DevSuite -build -dist -log4j.properties -mobibot.properties -fetcher.properties -*.ser -logs \ No newline at end of file diff --git a/ChangeLog.txt b/ChangeLog.txt deleted file mode 100644 index 744bba7..0000000 --- a/ChangeLog.txt +++ /dev/null @@ -1,294 +0,0 @@ -2005-11-08 14:58 erik - - * buildnum.properties, mobibot.iml, mobibot.ipr, mobibot.iws, - lib/delicious-1.6.jar, lib/delicious-1.7.jar, - lib/delicious-1.9.jar, src/net/thauvin/erik/mobibot/Mobibot.java, - src/net/thauvin/erik/mobibot/ReleaseInfo.java: Added ability to - set the port. Added NickServ registartion. Updated to delicious - 1.9 API. Update URL to mobitopia.org. - -2005-08-08 21:53 erik - - * lib/delicious-1.7.jar: Updated to delicious 1.7 - -2005-05-11 02:05 erik - - * buildnum.properties, mobibot.iml, mobibot.ipr, mobibot.iws, - lib/commons-httpclient-3.0-rc1.jar, - lib/commons-httpclient-3.0-rc2.jar, lib/delicious-1.5.jar, - lib/delicious-1.6.jar, - src/net/thauvin/erik/mobibot/ReleaseInfo.java: Updated to - commons-httpclient 3.0rc2 Updated to delicious 1.6 - -2005-05-10 22:47 erik - - * mobibot.iml, mobibot.iws, lib/commons-net-1.2.2.jar, - lib/commons-net-1.4.0.jar: Updated to commons-net 1.4.0 - -2005-05-05 12:47 erik - - * properties/mobibot.properties, - src/net/thauvin/erik/mobibot/CurrencyConverter.java, - src/net/thauvin/erik/mobibot/DeliciousPoster.java, - src/net/thauvin/erik/mobibot/EntryLink.java, - src/net/thauvin/erik/mobibot/Mobibot.java, buildnum.properties, - mobibot.fb, mobibot.ipr, mobibot.iws, - src/net/thauvin/erik/mobibot/ReleaseInfo.java, - src/net/thauvin/erik/mobibot/StockQuote.java: Updated locations. - -2005-03-06 13:04 erik - - * mobibot.iws, lib/delicious-1.4.jar: Update to delcious-java 1.5. - -2005-03-06 13:04 erik - - * lib/delicious-1.5.jar, buildnum.properties, mobibot.iml, - mobibot.iws, src/net/thauvin/erik/mobibot/ReleaseInfo.java: - Update to delicious-java 1.5. - -2005-03-06 08:30 erik - - * ChangeLog.txt: Updated ChangeLog. - -2005-03-06 08:28 erik - - * buildnum.properties, mobibot.iws, - src/net/thauvin/erik/mobibot/DeliciousPoster.java, - src/net/thauvin/erik/mobibot/Mobibot.java, - src/net/thauvin/erik/mobibot/ReleaseInfo.java, - src/net/thauvin/erik/mobibot/SwingWorker.java: Added threading - while posting to del.icio.us. - -2005-03-05 13:52 erik - - * ChangeLog.txt, mobibot.iws, licenses/delicious-java License.txt, - website/index.html: Added delicious-java license. Updated - ChangeLog. - -2005-03-05 13:40 erik - - * lib/commons-codec-1.3.jar, lib/commons-httpclient-2.0.1.jar, - lib/commons-httpclient-3.0-rc1.jar, lib/delicious-1.4.jar, - properties/mobibot.properties, build.properties, - buildnum.properties, mobibot.iml, mobibot.ipr, mobibot.iws, - src/net/thauvin/erik/mobibot/DeliciousPoster.java, - src/net/thauvin/erik/mobibot/EntryLink.java, - src/net/thauvin/erik/mobibot/Mobibot.java, - src/net/thauvin/erik/mobibot/ReleaseInfo.java, - website/index.html: Added support for del.icio.us - -2004-11-16 07:46 erik - - * buildnum.properties, mobibot.iws, - src/net/thauvin/erik/mobibot/Mobibot.java, - src/net/thauvin/erik/mobibot/ReleaseInfo.java, - website/index.html: Added the ability to ignore nicknames. - -2004-10-30 13:37 erik - - * buildnum.properties, mobibot.iws, - src/net/thauvin/erik/mobibot/Mobibot.java, - src/net/thauvin/erik/mobibot/ReleaseInfo.java, - website/index.html: Added the ability to ignore links from - specified nicknames. - -2004-10-04 07:22 erik - - * build.properties, buildnum.properties, mobibot.iws, - src/net/thauvin/erik/mobibot/Mobibot.java, - src/net/thauvin/erik/mobibot/ReleaseInfo.java: Added - action(channel, action) method. Added input validation to - action/send methods. - -2004-09-28 02:15 erik - - * lib/MathEvaluator.jar: Fixed a problem with the MathEvaluator - library where "atan(), asin(), acos()" never worked right. - -2004-09-27 18:36 erik - - * .cvsignore, build.properties, build.xml, buildnum.properties, - mobibot.iml, mobibot.ipr, mobibot.iws, - ant/jreleaseinfo-1.2.0.jar, lib/EXML.jar, lib/fetchrss.jar, - lib/jdom-1.0.jar, lib/jdom.jar, lib/pircbot.jar, - lib/rome-0.4.jar, lib/rome-fetcher-0.4.jar, lib/rsslibj.jar, - licenses/EXML-license.txt, licenses/ROME License.txt, - licenses/RSSJLib License.txt, licenses/fetchrss License.txt, - properties/fetcher.properties, - src/net/thauvin/erik/mobibot/CurrencyConverter.java, - src/net/thauvin/erik/mobibot/EntryLink.java, - src/net/thauvin/erik/mobibot/FeedReader.java, - src/net/thauvin/erik/mobibot/GoogleSearch.java, - src/net/thauvin/erik/mobibot/Mobibot.java, - src/net/thauvin/erik/mobibot/ReleaseInfo.java, - src/net/thauvin/erik/mobibot/StockQuote.java, - src/net/thauvin/erik/mobibot/Weather.java, website/index.html: - Rome is now used to create and read the various feed. - -2004-08-03 01:07 erik - - * lib/commons-httpclient-2.0-final.jar, build.xml, mobibot.iml, - mobibot.ipr, mobibot.iws, lib/commons-httpclient-2.0.1.jar, - src/net/thauvin/erik/mobibot/Mobibot.java: Commons HTTPClinet - 2.0.1 update. Added automated backup for the data file. - -2004-07-07 07:10 erik - - * lib/commons-logging.jar: Commons Logging 1.0.4 update. - -2004-07-07 07:10 erik - - * lib/pircbot.jar: PircBot 1.4.0 update. - -2004-07-07 07:10 erik - - * lib/: commons-net-1.2.0.jar, commons-net-1.2.2.jar: Commons Net - 1.2.2 update. - -2004-07-05 19:03 erik - - * lib/: jweather-0.2.4.jar, jweather-0.2.5.jar: jweather 0.2.5 - upgrade - -2004-05-03 10:53 erik - - * lib/: commons-net-1.1.0.jar, commons-net-1.2.0.jar, - jweather-0.2.3.jar, jweather-0.2.4.jar: commons-net 1.1.0 and - jweather 0.2.4 - -2004-03-10 09:05 erik - - * .cvsignore: Ignore all serial files. - -2004-03-10 09:04 erik - - * src/net/thauvin/erik/mobibot/Mobibot.java: Removed angled - brackets around URLs as it was breaking Trillian. Added pong - command. - -2004-03-10 09:03 erik - - * src/net/thauvin/erik/mobibot/Weather.java: Added invalid station - ID message. - -2004-03-10 09:03 erik - - * src/net/thauvin/erik/mobibot/: FeedReader.java, - GoogleSearch.java: Removed angled brackets around URLs as it was - breaking Trillian. - -2004-03-02 05:53 erik - - * mobibot.iws, src/net/thauvin/erik/mobibot/Mobibot.java: Now uses - setAutoNickChange() - -2004-03-02 05:52 erik - - * lib/pircbot.jar: PircBot 1.3.0 - -2004-02-25 17:21 erik - - * ChangeLog.txt: Initial import. - -2004-02-25 16:27 erik - - * mobibot.iws, src/net/thauvin/erik/mobibot/Mobibot.java: Added - random ping response. - -2004-02-25 04:12 erik - - * src/net/thauvin/erik/mobibot/: CurrencyConverter.java, - GoogleSearch.java, Mobibot.java, Weather.java: Added -serial - command line argument. Added ability to search the current URL - posts. Added ping command. Added more efficient arguments - parsing in the public and private commands. Added ability for - the originator to modify a post's URL. Removed the various - URL-based attributes from the constructor. Fixed the nick - command. - -2004-02-24 05:09 erik - - * README.txt: The properties file can now be specified from the - command line. - -2004-02-24 04:58 erik - - * website/index.html: Added reference to Commons CLI. - -2004-02-24 04:56 erik - - * mobibot.iml, mobibot.iws, lib/commons-cli-1.0.jar, - src/net/thauvin/erik/mobibot/Mobibot.java: The properties file - can now be specified from the command line. - -2004-02-24 04:55 erik - - * src/net/thauvin/erik/mobibot/CurrencyConverter.java: Added the - ability to list the current rates. - -2004-02-18 03:40 erik - - * src/net/thauvin/erik/mobibot/: Mobibot.java, Weather.java: The - weather command help is now returned when a station id is not - specified. - -2004-02-17 06:10 erik - - * README.txt: Added (very) minimal instructions. - -2004-02-17 03:22 erik - - * website/index.html: Added wiki reference. - -2004-02-16 20:04 erik - - * .cvsignore, build.properties, build.xml, mobibot.fb, mobibot.iml, - mobibot.ipr, mobibot.iws, lib/EXML.jar, - lib/commons-httpclient-2.0-final.jar, lib/commons-logging.jar, - lib/commons-net-1.1.0.jar, lib/fetchrss.jar, lib/google.jar, - lib/MathEvaluator.jar, lib/googleapi.jar, - lib/jakarta-oro-2.0.8.jar, lib/jdom.jar, lib/jweather-0.2.3.jar, - lib/log4j-1.2.8.jar, lib/pircbot.jar, lib/rsslibj.jar, - licenses/Commons License.txt, licenses/EXML-license.txt, - licenses/Google License.txt, licenses/GoogleTagLib License.txt, - licenses/JDOM License.txt, licenses/JWeather License.txt, - licenses/License.txt, licenses/Log4j License.txt, - licenses/PircBot License.html, licenses/RSSJLib License.txt, - licenses/fetchrss License.txt, properties/log4j.properties, - properties/mobibot.properties, - src/net/thauvin/erik/mobibot/CurrencyConverter.java, - src/net/thauvin/erik/mobibot/EntryComment.java, - src/net/thauvin/erik/mobibot/EntryLink.java, - src/net/thauvin/erik/mobibot/FeedReader.java, - src/net/thauvin/erik/mobibot/GoogleSearch.java, - src/net/thauvin/erik/mobibot/Mobibot.java, - src/net/thauvin/erik/mobibot/StockQuote.java, - src/net/thauvin/erik/mobibot/Weather.java, website/index.html, - website/simple.css: Initial import. - -2004-02-16 20:04 erik - - * .cvsignore, build.properties, build.xml, mobibot.fb, mobibot.iml, - mobibot.ipr, mobibot.iws, lib/EXML.jar, - lib/commons-httpclient-2.0-final.jar, lib/commons-logging.jar, - lib/commons-net-1.1.0.jar, lib/fetchrss.jar, lib/google.jar, - lib/MathEvaluator.jar, lib/googleapi.jar, - lib/jakarta-oro-2.0.8.jar, lib/jdom.jar, lib/jweather-0.2.3.jar, - lib/log4j-1.2.8.jar, lib/pircbot.jar, lib/rsslibj.jar, - licenses/Commons License.txt, licenses/EXML-license.txt, - licenses/Google License.txt, licenses/GoogleTagLib License.txt, - licenses/JDOM License.txt, licenses/JWeather License.txt, - licenses/License.txt, licenses/Log4j License.txt, - licenses/PircBot License.html, licenses/RSSJLib License.txt, - licenses/fetchrss License.txt, properties/log4j.properties, - properties/mobibot.properties, - src/net/thauvin/erik/mobibot/CurrencyConverter.java, - src/net/thauvin/erik/mobibot/EntryComment.java, - src/net/thauvin/erik/mobibot/EntryLink.java, - src/net/thauvin/erik/mobibot/FeedReader.java, - src/net/thauvin/erik/mobibot/GoogleSearch.java, - src/net/thauvin/erik/mobibot/Mobibot.java, - src/net/thauvin/erik/mobibot/StockQuote.java, - src/net/thauvin/erik/mobibot/Weather.java, website/index.html, - website/simple.css: Initial revision - diff --git a/README.txt b/README.txt deleted file mode 100644 index 804b473..0000000 --- a/README.txt +++ /dev/null @@ -1,23 +0,0 @@ -Some very basic instructions: - - ant jar - - mkdir run - - cp dist/mobibot.jar run - cp -R lib run - cp properties/*.properties run - - cd run - - mkdir logs - - { configure the properties } - vi *.properties - - { help } - java -jar mobibot.jar -h - - { launch } - /usr/bin/nohup java -jar mobibot.jar & - \ No newline at end of file diff --git a/ant/jreleaseinfo-1.3.0.jar b/ant/jreleaseinfo-1.3.0.jar deleted file mode 100644 index 0c00c5f78cf6bdde3832614f6ea4584017fe5fe6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23925 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 diff --git a/build.properties b/build.properties deleted file mode 100644 index 023fd99..0000000 --- a/build.properties +++ /dev/null @@ -1,12 +0,0 @@ -# Project -proj.name=mobibot -proj.version=0.5 -proj.package=net.thauvin.erik.mobibot -proj.run=${proj.package}.Mobibot - -# Locations -path.classes=build -path.src=src -path.dist=dist -path.lib=lib -path.ant=ant \ No newline at end of file diff --git a/build.xml b/build.xml deleted file mode 100644 index d3386f6..0000000 --- a/build.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/MathEvaluator.jar b/lib/MathEvaluator.jar deleted file mode 100644 index 9011d7609bfb4d1f714823ed3bffa04d6c6137a8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5762 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 diff --git a/lib/commons-cli-1.2.jar b/lib/commons-cli-1.2.jar deleted file mode 100644 index ce4b9fffe40c41669797cd806ac989471b2acd84..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 41123 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%0D2u^7bcx|ezvBT@`6 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 CNzF?D diff --git a/lib/commons-codec-1.4.jar b/lib/commons-codec-1.4.jar deleted file mode 100644 index 458d432da88b0efeab640c229903fb5aad274044..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58160 zcmbTdV~}o5vn|^0UTtHwZQHhO+qP}2wr%5S+qSvdw%zyLIOpEI?};yVocW`wevAzlz#6ocY`{F-`U;oUqqAG&4l5%473jYa%0%HCLw$V(HZU_Pd z#0~)jg!=!5$qLFziis+#(8-F`DF3zJU_kVXPyX3kDwDMWF{P!I@umPQS`<`5R6Vm{ zeE?O(;jY8;e}CvEBInPgN=`-}ZM|%}yMNpD0kZQS=25iBW96h*r*JBayweiy zv1L5?iXqvFNc@QTJZOeAtW8zALYOfzingZ~NXrLaTdz(j+Ojae=Ru{P^Dao;F1b~2 zuOKIe->2RJksiY&;<&7{Tj}Vs)N7)}sx%uQ=qJ@0uvN?HIjzKxrn}@fn>UOaG+tzh z%PW{Jt-kbLo((;)S*U#)0L8UAQ(ti94{hM3;D~hi z)VjDbF`=JX%+#`KTPVkosdrcmkhsV7o_ceByNO7uWHQ47*6=b=lAia-eb~3mE*d1- z5`k9W8NvXv%nCrP+ZY6Liw%qD*$lLV6MDzlxcKOOv~%sGm@o=u;k% zb#*T9fAj){bGa85+FgHKZQ=JQXW2~cDXHaQ)yLNooTdKumb5n{?DhIRQ$yAYYSYo& zHZwp4_x>-F1Oj6EZ5zHimZQu7>9S>Wpyz72nSE z|J@qu-``Zmu)d@>0uT@d?SFF~GLpiga>}A~E*>u1TDJDsqe$O+1V4t-`Q>2QrsT34 zBX7kTP6I0iu#&adU~lzZo5ZbrJ4~JKg=_kM&CT@Vi%l`U)CetV7O$=^yLcX^rhMpYpPeJy5^hDbKdtWz<(50EEl8e==4{>e$ zeC9$Ms!nqFr+9z%-Mb#Y-=E949oyTG>+I0gA3olu_vN~J+R<*VYpET*zn-6u&$p?) zbndj(A38ra-(GG`CD-;RVH``ewl9E@JECt<`I{V?G90YeU5$!N=pnW|6xER+ZOLC^$Wpt-MZ=k6^+X9?u3JSHnpED`55dREvD)t0*C7f zsp?DhPo=qG5s2o*oVMfb_(M$Z4pM!=Uz!hmiioEmHzU5VJ5WMaN1tbN7Y4HGzbsWh zON{%eJCJyBKOiQpn%2|#?9g^lxp}L<#JmxlO6l=LfV%!mhu1sTna9r8V+)qBmcA8_=uQ#`J1YHUG%D8F#}Msv5PbRRgyH zeSyw){xX%}rku|0BVO(1B&iPA$bB$z3ikQH?te zvd+H2>E`doiH~fPgQDji4r)C_vTy5r>Y`nxWlGDo+uKt8ir_Lf!t(ni3CDDNp`)(z z4_Z(;YB!ch8G9yJfMAYgIId^r0g7QZgjhuX827O6C$?%xh+3W4Bz+%GPNu=c^u7LV zl<}Qu@5`(~TEl^ZWzG6-{FBym0?#lEPqF)BWz5X5e8;Udb@46N{#WH0=>Zv}yC|kD zD|ou$-GHvT1N0VXJb7zw!0+0R-Tv))F}`&6%6TQ&kE_S)o7gW0FjQ_HlM1Zdu^T6e zQ$9UX$PjgdwoNfMfi%bp?)FO}GE@guq?tta6{fb7DGek=gpR(=U(a1Vw=HHz6NdSh zgH}=ZBfK*XkWUos+S#!weZC&u`jT~ecCFCn{6rmGP2BXVjwRK80c`lm1T}5z1@v=_ zWoSq&h^_Zg5d-uk#MI9?*>Jc*{XpXPh+^gq>l7?**1C1lApy$}CQx8istB33Qhab< zA#F&|UTkdNVZ1@zlc!Ogig+sUa)V+C95XIB#2RJl9ixn+E&O8VVER{J$W)Hy1NnmY zmj*&R{3fVXY)U5qs@j(8rV{KvNwJNUo5U3F2-RJrTVXh*Y1poKv2}rREh((z36(O1 zl1<`9f5MV2r7wDkvJqrG6w3iu$F}@6e`2pz`dZwm- zY9Z15k92!iHY{sRtbhF(lrYyQ zYXJqvp-Le{ri?iCA$6r|`R)is61;8L)Z(Ks3zj6Q9hTihCKPc~z*SiPp%)lg>)#|N z6wY4`t75<1sq?B_gOxXCwvvnoW?(sINuk5PwF_Tmyfc|f&SHZ&Gbc&S zxxNKG02PL?L|KpK&+b%CQ5;)0^g41n)I#C}ke+)R!S=ZN7$L?1L@un{FpT--7#<^n zUWBK#U4k?PqxtKHEV~Yt(cMKw>w7wYR*=> zB7)1NT#b)gz)ImOxH(6_M43Q*QYglDs8;t{`3%{{XqIS|P5Pn{{_JWgU514!jj8a` z&;rS*wnX?J&$nv9J1I69K4RTsSGZg;dKsz_Hx(l`q~AR~h^>`2EV{R6*zL0x?ocv) zVz_U!sD-%(!8Ta?X&km-w++Hb7yUn3*$ri`t+RLdf~{1m^3^E=<7`r%&aI`wq({F5 zLYmSz5%R{J{kM_yT8T0wMf8jM`hLHV5KwzM(b1fpoVFw~j~d?H<;XXkt(iJj-+-E) z%RXVS0{g^|C2|)W&hfs*)bZ$20t4&cJ8UFR{GeTkyv4#J)I|^0{6=(ACD{GA4#x@D3+hR66e=XHF3Fp^=cyi%)#w^w z02YHT%t}=9h21ESu>NKmUH?>Yo#rgiybo1iOI$XO&iZ((y1)XtcQoi$CJ8f+C`l7f zxl;ogjGW_KpwFt=qE4+vZb^nqD_;j)mOMgMlRPI$`v3zNcip=0X{+QFZ9C;HM)6hX zx^deqP@a_|X2pOFWa9K0C~!QRqN<2dHVrhTmVO`QChvD5pORm*MLt@JOP{h8Asj8K z&LoUNVru6oG{> zVGj&uC0pHBis>McEqXWG5=rE~%Z^~_@rV)Q4dPsJx(pRSBL|K4)~9IUQLjJvL+o|r z<0Iyzq}Yybm^vv8Jc|s^WmzI>k>-%0WOIIRNz{&_<`eXYaW#NqOw}vTn9Fqa%d?Uw zOskgl1;4^zB1}JudM9Cqjyps%qzGx9M3y{PuEy$k=TKo0UY^PUzA_xN(`QgsDV_6G zi``kwop9%AtTE2E49`)mrXt{&H`-C=I{6Yo(tIA5dcz3cHWcj$ILC7h?S9BX)2;QV zs*;X@2_0~Y(;HsaA)D#@4u@`*uWG3?lwoe^!z*sswZD*X4+C=|R{X2%_mQ|fDoTmz zfMRaI>k73>hE)aHxgdOyZv;Bs@lsKx^r<^aP|3=mVyt$LTk&H$d)@HSzWLqD z+dg!*#0Stb%pQ!b)UO; zx1QI%_p*y&UsAu09^WV8!>&)iZ!^Ci=8uJox3B&88UJYqEOt+CPnf}OZ)Z>Hot{o# zZ)f+briMIaHi??yNyeXG|b=ZzyPPWNpch6gg5^yH33`w}j~-AQsLxP%gaJ%t|z z&v{!sG^1ionr#*bcQ84e=|zEhm0WPi@_Cn(@Qc*~<&1B!{QGyt2{H@k>0@FBespVL zj~HIUkTB#s&cI#rw@bB$OwJ*i)h)@SYi2xrEI3=k*4VO(lECD_>aRC$@K#lp1A55a z2)cR${zih#1MU$PFxXD9-BLC@lCrS2rzG!*d(O1QwfA}jvy`}Bu3|qTFa5>fYjW@K z=JN2zMLI4IGajqDSc{h~>}L{w0yAuzHN`u`4Pk#w>`Si2E>Kb~HyUQaB2W%1?3FFn z1pIW)hwy7~a3XLLp}q|5>FpAKKR0^L@#NYLzK}$O zMs%FTD`(^Ny;gc$>vHO(=wXKIKrZDAA7JK>gwS z)a18akuTC(;_&4^o|@n3k^wUC?7#uvgioI7p(dPef?5ffbUPU#f>qP;hp z#Nqh~tiyw2j=+bQ`!Sd6-#uf5f_tG{{^*EH7$-dyi%D6e3oF){nc{V0&Qto&uWzcK z1C7Ef!HhR`hJv?gr4+5Dxhg68O;OBVguaws-?%qOFjzs5d4GlS_>}y&!?{u!nK{*u zg@|6@rxLLpoE9Ks^k~B`zw+Kqp5ZWm_OIWuhTx<5!dLxcibLuSJn{;a-9O>brzs{d z_@p*}#AoovJ63mclu!r@7nwnWK=<6ftU^8lxd^Nu!}WT%1BT~ zE$GOSNXaj4!50o zRgH5{aW1USNb#TiT=QK9O2<>r!_KrgWsT)zrR2aDHvpeVuN!xB@C2X85^8%(WAg7Rw!opqxgd~M*d$9ozOJ{{}>Gj zXowmJh~{63EB`4B2^l(@va!$^+ZZ}KUuk;!Brmu7&A#|HnI&e2$Pi#>)RQp>)?=Y2 z8n6){wvf;Oqmd;MVx^nxPl=${Jhv#=TGu>o?0|Ha12Wa>F`5yzx*DolTHNgI?QN@? zH@rJ7U%H+0UVQ$_gr(1YU;py~PR4uAeCN9JpZIt_Kgq`+%@Z{Y$x@&4>jd05T=8S| zT$I8+^1S%Q?|s<419$f|V_^A>DeE~c#-Ex(cJJrocT$Gux-a-UzWtSZ|CPq?s?7Ek zQ}&a+hXGs1)HQM|9j4Eiqu+VP{-|yD9hcR6vVo8JJ$6eT#{bZ#kNG`u%O19hyEJ`d z8cvWb#1V3g+K~nF$m~D{dktV*!@_};`-+=Pqj#Pj-gS$jaiHRn`!j7CCw%DCYtk{x zEt0Ez*jbT#R)e^R32kHY&5ScJi5qHXRdB;K6owp5;Tpjdo=#Z~ zC~xrzA33g-#SIe4%D+5bGa$mkk+Fjj3m@cqo(Gf7 zs*h7Q91~CI^t@V$y-?;|qN7+nx7^-Zn=e1L>dXZ5#8Vmbyqi5 z_NIPsbpza7+vsd_73lxnS_4VVOtsP2|-$J{L3}eKLg$>&r4E7!OlNgVkxm94mlNs5^yo7sLni(_9wX9{ve$L(N_8v?x zL>NX6!nt#(cV}L85*obo@L*Vnm#Q3OM7+R_gD)x#H}>v-m-~bd64EtcNVE}fH(h2E z6l1m!mhQ4UxD}A+uwzXBiw6T9{<)mkG*yp9h%Jn^j2RY%5w3i}jpEz}SQj9C$u z0lWMt0ug*C%qrV2(&n}4h!9A=tWZbzQ>U3!2vAGs%eGHtH48D zL7a^lN2W=i(wVuj;ZcbPhY*y9S3>74UnD6;_D}v|L4h1o8lfSbKD_3D>>OzI2L;VK zV;g|%7SlIKL|_vQn;8}XTY8*sCQ4e{1{^3cu!MS15_!}(EHus_c25*J;=$ulex|^b zooNJ$&ohd9_(%45=u^Rl0V@VpE5w5jVBnObWpNUE`DC}qQ@Vf8OrBARt}>=f&fE`} zT8Bbj#1u_>ES1o0C~WulaPV(apX-`{J2(a;sPNu0lAMobX$=MwFN8Uiqy8|H~ueCv}cXgeD$imK;nb>vgSdy}Uld2IdVmo&bn^C+lJE>0(6) zV2O)>PJv^>H0hEVr2+?$HI{G_w=cd5loI@1fl;fn} zW#LPr48?T!TO3SP)-wn|;U8swYPf7R#)ue3&@*&9r+|vIFFoQ@D(O@D^G5WmBq%=~ z)Mz!9@09eksRecUF(SODf2ud>+6*4ZzKA#??x28hBN#JooJR?5yC~dnV$M0>N zXaf%ChY9MSO^p4a#S3mk$>$G{b}LZ`6fI?Vf&{DQKLIFxx|S#<%@F3v$4dl z8+pLinUp+FvP2kU!cMZRa06j6*AK~w(k6-SIUeGxH#!Thy)_fEsM9zeEWU*6WjDGe z6$c9{p2&4|?&X@7a2nQ=g!_yMR~?3moR@?*IWd%<^N2S)80Xyu=y{Zq2c`-U z%NuotjyoEiltW;a*HS2KHkWQ=B4eplPM;WQBbVwfVM8FxhD26*LX;)5ZGUrjF#YpV zq?@{!H}!PBE!NeQ1@T3p-jt+tN@w*wL{)`^%eY1#fSX>qNOKyawq)F;%!qC$jgR0T9`oR+wMl!u6`SBv0uvX`o%Q z2tNsSx5!|*=ai-k46eX9D!dkI=D31$(`VzC)suzUKj(Ok@kzCxm=6~&`mQ1T$0;YM97S-yh)qsU3f9gW z$a7A{6>C2D#o)WWE{Ql9$wzO>@iv`vb%=MT0vF;9)8@T%x0W#|FF4*5J=8GMC^|oo zk6hxF?0UKcJVhZ0`0*VAOJkM#mA@Mg4!yFwh)w*np=TE#9f7kXg61#A5n~lJQQAeB z@#bn&=+qW{8p2YengKch#Uu@R>mi5@BDMwihDbZ)tTXs|!Ivnxl5|tVN3xLdtW!4% z6rwU!7n+(v&ws2^Os%Xr*$o}Y{ioT+~$cfo71gEbOmEM&M61lOv3@WWM zHkb=g%!=FGVEJM8Mih92P#(`2#7B(z3zSiV*>)$t0o<9-_4> zWN<)P;}&W;rmID5F2wQYL7!5%%w#W@3=g3V>|a`^246D`>zwookeXst09JP6`h)=y z(&#)2=d9^zc1zt5*^TMmnzRT5Mj$wiNls_1GlkfACv&wbsrd6E`#A=mb`vN!g+z`B zs!{HP!`CGcjxlP{FY{h^ej5~W#ky4S=Vx?n2%Sr{0HDqVp{v4HV-@9Q_xzFh$j(Gk zJsje$MvhySVk~O!fcq4tuaatafx9*>7)_*oSdd+sqbTtT0UuPHT;=RnS*o+I=ri4w z?_rntW`D-+&5fU(rSEs#e9KV?_e^L;JnD~twIlW!<&26O5K|*HBYN>?OD6)wDUs&S zn2nRh{kSDLQnfESQ>63)3-YYMZYM53zD>jS^XC#>1bjj_hF2}}Ub(hOdn9j={uUxc+Aod{KRn{z@xFJz_D~?wM`Y}a>ICbf z!|kKZQ~J?(4a*M&yjE~f`H}6=`4P%Rs1IA-Wnv=rqQ*z*M@#Rs?=$bW?vvhe%SQaQ z=DUNek^5BCru{CyLiAsO7}5u559>FxN9S4CFNQ#OK{Q4$K7xjPplg&OK%O%)V_CSD z1|c=Sr1wW`@Mrxq_^L7Vu%pFju?NiqSKMGCh@D0S&)?&`-<#wfwD6d3DVltNwvFEo zAaR{F=M;N)w~Sh@tXX!Tgs!##R<4`#L@rHUGlPAnU1&Z8>vC|Tzs|vAjlA-b!yiuX zuSUsmo#lAV;OlGX=@~a9LafP zm=$UJITfYkY{@(UP7{k%a<0=hzPO9H$l zt4mo+#PvM-BJl>YmzK5^y}=i?7Vnpsb^dCzYN3iX>O(Wxd^KzIvR2h;VCQyijq*%0 z`ZZ$E?;S|>hQVdLkgRPea>~92i}s8*;v=(iO}ntnf2It(<9&o*D;Z5Y9h@qtlkXpv zVt10CGB*hnQE65$@_wZAEoNIpRHqyodz0tCxGa&bM{Qb`ak^`V5S&cE6H72GpMU9~ zv@@N6tv@!2gT?$18)vt0tpM;SIKYOVl_<}f06mXzf`ci~>8|`)!uSfa;Ozd74Q|`E zS6W6_S_ao%**0PA>$6XhS;GyQAgMA7EKAVIjd3!Y@+v7rIm)_>}!n?E)(M)f< zpr9S6Vd?{5>!)A|v*YuU6{|FS_LTNEEO`4&$g;_khfXgLIHQbCkk2*tDrl+P=`+z*cU91Nps7VXO|ITE5UaV zK!Dik;Myl~IW`4o)E{vg#&g;{$2U+6OG0~o!9;tRJ0|Yn(O`vQrQe>v4;_OG-HLaA zZ|!FXGQN85>KIJz+(h8nK5jo1JBRMkGd&U+UxL(D0rLhpF-pb491_UXzx|V{|A7OQ zZoya|Y1fPxCAH)y5cUpiY{sBe_l_*J<}YNrGR>^(7Gm9q{}ZYwitZJ=0njhCFWDuZ zcI9q6?qbNP?U#L`p-5ANpssUUc-lm-pJ7PpPeGRPwNP7%F#dCDl|;cq-QwS1jS znSY3On6)cfB;$79psJena9ZCj&OIqI6nSPi=*TGQ35gGRT=1?Xqei}z7t>EKy*ANU z=qP4#SfGEKt@+_XpPUTCeKU4_J$iK)#Gu$F_1c_aF|SC(c1GY6Wphk1ZBqH_#3hL9 zD%6)>M8pAj)ZUAojRo}c)Aq&M46@0epcY&AtJlJ+4%{Y|-4$~Dh-((y7qtNF=e$b= z;TB~(S#Ita&6R*@I~P!0734JwZeJbFp5T@R@}$#|2~MN)kY!msGea+CnBL6-2&Hh3T>-s5&NT@7F|+ z$kX;4ToK^B;tr6$=RTQ5CZ7!?s|Hl9cQE;7)*CHsQ0Hm2uW z70)v~auY$sA^pcTRM8~H`L96x?ziBUhMaQCx1h(Auu3JrOw%LM+WsIw<_D@~X;uNo zrdg6dT*Ei!9qD-R9mNGIK0X=a>45P^G6nYSIwSFiP5N6&q#}dQd|r;)x8qG7C)KML zJeEVzPVw*b`KNK5pZBAMvM4a?cGs4gh4Xg!L9BLYi$i_IA*!lsGEVop>)&4&Evgsg z0;2*?Yx5HI;};x)wa`n!vS{&op1)7?h&#Vwk52Q*>%PIE-f5)#M)wG3s6&Tt_;Dd;)WuBLJFd31{Et>2sOapUp)}`!o%eF4 zUY}J8)7A;k>R2Xaix_9pRFb@DWFPDoDp395E2}9Iqj(>NAA&RPSJ-XRT;XvCgmqSm z#`3>zfg4rx7O^Wwt>COjemVVy6OWnXIcN2_ago@ALu1oX|7kJQf_4a%)z(rKBtRm_hSq7!GaVR8bN$4Yp^Wb|+Q8%g2)^FAAy z##uIG^cBf8Wu#B5sG4*^AF}W>+4{2e4_?Ubwcs0_*;(rD^!I2~!D_PgYkS;c{Rfm0 zY{Q(w8t>fWxYlCM+8AdES`|gw#Td~rNmWde7i5ZPgddL7G&s((Dz0p1t5_sk6gQJ* z>~ziCU9lIopTI2dy_V<4aAkG3+19s~ZPRFVx8c_}mamelIy*{qYk|2Awepo)fOVa4 z=V(_!n@qUph}nUfj>HV&w!o%RvI3RtfRD%F4SFuYI9nATykDF^$U+A&U(eEXo+5wb~%`_`TC9pbhSvZ;&uJe`0z z^x;9MO<^@i!vp+0nHdNU`m8d5=n^D%g*aiW|Fi;OjDz+K-xD}Q@_^}3A%Lchi}qO` z8X45+fauVrfz+i;2CR--2T+^PI+WDH|^{J4jcSM)yxA4DT9_nT;8anI^z`!oI=&qqbpo!G^*v zVwo|ZGNLjkGbA%5GftUMnBOw0FiaVxPcwuY(hc&2y}_oys>1roS~dqZS5lTZxfYbV zbV!}KWGtMqN|iNBl})C|)v0oI%bmG|E}Th~EOM1BdaY0T{7dlV9VuEQC^a{Y{lpmL6f^5?~25FV} zb(!GVCzpY6nYb9BZ3^s=^$5~BDYOgEi3>#w>OMiVOJ{Zk5r&OrXS7zc)DT`Js0n-d zhqNz&2K;$~$v|TU>^kMBkM9ihc@o+{WCr9qsVVT|2**HW1{{9Ovrmu{A2TVXk5Ci5 zOY=R@5$*k#CY%fvJx(f2U@HNZ%OvPT83I)vU$M_SgU|b~%%}8@w0p*cI^;L9M1U|( zQGKqw{lHl3664*~5Ac80iz@=O#(4iJdd!CWrzH1(tQSk#Ik>tgyEvH|+Wv=hoT8$u zjBSeQw_}qSI!&YxE-h&Vh$5_jLz8M&=mX?iDwmfO_Q7S<2R3JIx2?Nuz}R;=jo6Fh zMr+_YhGE-fBc(UsdY#4mjPU2@K9GfR?8|hItv@{Rop{bRW&QnrJp$@OOl5i84GPnX zX-;IHIWCO)1xG03#4x-=y_KTqC>b0kiI&ECntnLJ@-k)NfmY|3Zt5I5t;)uUwyH7( z4XEx|l6H&N>UyrfQcXo%RiN*>QrsvEw4<9t8tL z9aXQJ9oNbe1RlW_#AwGI$wT4DAMUW(VOvhhn&&tz=e_VQQpCd1L4nba7hG{pGMZPF zbe(Op+_RZ>IN9~rW5CYtx8=gVU#N*1yfSLCA`r`^63;o4pak|5QPMGvp878}PGZqn zvpLRY%w+b;ZB9Z19F2Bpuygl1@fu2>Re?zvB}4^(*}lv5(|n-Mt1*)2lch4R)2OHT zG)wS;zaLo!+BIk}`buq*IoeZW?bN(kwO@MmXo8Z|06bgI(WbDXF_u2+qVo*Txr{Ik zoR!4+3%PQK90LPKH;M8(Yl{%b*SvMbp@l)nkECn{HKk|OY(F}zIeX4n>Bt<;>j^Ka zGu@9XzjYW7)N+=kilj&3vRChDa+Mip``BH(0>N?Z8$F|^i4eFydY{Nde^z4Hgr~k0 zFYHb^SBKJ{C7r@hTy>XSi=5VPV~?NB5)dm!GF=lyG`;3&2WM2GMHj81CM?XpnxIj% z&qQ8r+YHqzTlD)EA6=gp!fW%RSqbZ+F=+EhPJs`?}&gK(;h4e$58?-{n6qwUwY={$J`K&d!k2Z|HK#%p$u0r;TW5%HIdpT6ox5cLt zo7F9uW3zC}OMr8F7l$pU_aXfTu^~4`fDVYy}*$s~nJ%QI2|OSLh>o0>u_b@WNQgbXcPup=H+P!6ul36ncG+ov<=}t@K|#qlxTnE>o6U)C?|Kp->wK=d$BlR zuCTC)Um=)vaV(@Se++q^YmR*`t?!)ozH|U*CPBUhR{TjI`G6X|Wu*N^(fTR#K*}>j z%{w6V354w#0_h=Ayy+i-uro%v+1KWJ!tEJBaMDF_`2s)Zp)O%|$VG%GxzvVRZ)K2C zCG1A3geZ2Go7m}EQRLF~hLfMX34EmruO4J-A}%{`w(<=kXu;|J#Q3isiN|O8KH?vb zWCR5S#PL7&Nb;^O|J^02YAfTYB7U2>uLT-Hh5QrVg+%N(Vy{6(SP;y|=4VwSf{KA! zF?GT+bWACD&mS(|*P2$?Q_^+~F_qZs1yG?xmZ)hS1@n*JUo>UuDkWCFE|kf;=Y4nd z@|hpk`TOkvJD_67Yz2?Xx)84mTop%yC5_#Ntay^qf7-&Xra)={u@-`ka5qoEkByKATD8^>*nvXgDyOc<}UQQ=_RJ zbybq5Q_?ciRTUWW-qd|iw~*8sN7}{hln*VLI{O8xInU4^HO&C1QQf}MG6~P7gyiM3{AwV;TJHXhK!7z+3DjcClhsUtI#=-fx#y9<-**lG&u&=c-c zv!!XQ+&ItDx=MstCk8xYG&B(J7)EGi4CV)5Jmv>LBYt~GP7U$JNx}{O{OCDcw?aq< zY5cvKY0;ipx~v@#o}X9~mOEMxfht5*nmuE`e_YTkQgsFX+Ghs=7adHp(16(UcQ)@5$k!uCyn_S8yPY@!xC0^5n6ZSEWKoOhG z7)gR%PU0Op9;8Fu@X7|l_$Bs57SwP{_PFM{l=D~20!0k2FbN-(K$LU9eunb$AH^k8 z&7u29M72!j@wzuZ8dq(#<^3ECTwT@|&hJ$zkb z5RE>Hq-snL;i**S5B2N4I9KzUw37B2C8$3){=`^nzI9H4+Axo+XC%-AC$2a8sD;V} zyZ1mm{ax@Jgt6K{jEcd3vD8^N;wN(Cf??d@VEVR;FVp=~j`iL=6u)8F~n9nRP_ zn{^L7`bv0whm^NLURk8kK42vdQ~Z)ZFBXf|}7x2YN3+t?MVA1#6;XwK?!T zehcwFzHP{q` zGd${$^7=R7!g}bd#p{>Wsc*&yx6iU zxDewPo7|-RB_z>TIYW(;3hB?a&S+ITkLkfrHxF;SVOWO_Fl%4x_Q&xWI@ctP%d!Fj zBJgV{y$7W3Ysy&fo!8IIplx8YV+CWY>ET>bJCv@>qKupT|NoZM;#x z>%jQEqwr6?3!mI1n)y)-p?I(pU8RwPsLU`Y+8~J6M*~X1n1Hsq^sIoiyu7qXpJOSl zwS8>JM%q;kNbO4PT%R5AJZZves*Fr&tO%D)jO=jsl!gY36{&-UK|EL#_&JG#cD^3S zHi$QAdA&d|SU63+e9$Bav|!y-aD#K^exyf-W}l`i?y-ut69t*V9IpIOoO~?8h!UZ( zLriMnwaF4D40c7^P^zM2{17>~n=85UAh7X3MBEU_{NXFdSv`J~C}{9q$e&DjKxWP( zuC2+G29Z_Rcm>y@7VWY_X$%ZVit2XJh$k_F8A%vufB(D&%eKZBK$5H}YJSs?@pqQQ zC{}hZ);R1Q6Isz+n}8kHI#*6ybFtD0K%jzG$({>M9+o{b5|!5$<2GBGbX1$kFWo7t zT?s3u3~P)qHf~-~>^C-pX8GOt^IarMQ5#7&UxqMQWvX1Jo(a)bWgMKwIIS!o7PDfU zR8xb;GnF?fQYH(f%JkGODo*p{^h#E)q_82bjfY^H%qMoM?2c*4iX-X^WZ61btJ9OO zqB66p~ z_R=D%Y}zu{%m@AUbJ)6~(-)kx#j&l!uJ8(hy!&^KvVz+T>1vF#jDNQl<<_KX26S5_ z&|^It_BOu(d532|%nmyG4j(5SA1_RSSU2I|=KmgWd0;vz&RTTHteW`JAM}LtY|R&m z(s3SZzxsie`#vt9^PUa&d4kB_r-5d)h*rvtRhprQjhQFG*Lc4FF<{#fSL>4dX;rWv z@YNmZj{3A=i3fNvqtp98jHRH{8qfC#|QfNT3r+uTMNX zFg$)Q>Nx+J_Sj5yHfKALn^|+7VRzP(wVIWx_^T^?ZYF)M?l9)GXxl#Dv_#89edwD< z=_3G*zrk~%Im^Y{I+rBQ2a|g85p!aM|GXW#+3G=iu+y6EY}vnk#dE5y5|%mn6`hyg zzn-5=!Cv6pwcOe+f>pU{&2J`l^yLajrC?3_3!|$zGtqE}UNp3+rp4z&|Sccb28|;FG&R}sKHhbR?k>ut`v>60U zRB6fZ)n#T%nn^GGZAuUId7$X(fY)=qIB^X({er`f@1z)T_aV7{Ao7=A_RpVrnHSYY z@SD2dNIg=`K2kM1Kx3i?dTbt=q|VdRmK;B)9Lr5-0v&#Pi`su*euhHbjX0Yl=I2Pw z%EOYHSo|sG!I1U*Eal;oTChnf+fcWYyq{s!qpV2j;bsZmnyP0bUX+(++HM$E5q1pt zOR;!^^Cf77K(Q!1@kq}69?isSWQXwf&Le>T-6DxLCbj%0rIM6dwfBuqvLfy_(L^dB zuaA`z-ISwaW%O=|X;gW3mtspH6tZ1N_z%Spx*}NbTHmY>WA9K2hm=p^Ghf4d&SejYH?n}k$#eMKWjA6Nsu?X-FEkG zEJuogh$A>L9V_Pe{C0mt2oYEJNlMtx8?qF zb$31TGIw{qbThm5{;U##k&!Ux%;$c+T>8(v&Aj9}tNDN4*y90N49}_-^Q1or32sEA zn}np(m%L^pYTl(Q8%BNvVU&3EM^9>~I1WcUb)EK~41ZN3>fi2Ww)K(>xzY>mKTQry zVuU`y8FrHlQSaYLQ|UbwqSr;v)m2%j-qWMzw?1>WVVbIli z-^wEFDBRJa{Z+dwjk=*IKgY+sjD?riiOIg^W#?mXbOgAY2n5={Cf)@h$zh#k+_t62 zmYT~^QN)`pa862SpTsT&RR~<*dwE$HeeU0`F@v6H%i{wP^Vbx z33nxS(am!iYJ`D^Psk{nq0ve-hJ38-3Au}Fip6$2!PJ>iT41>2*H8BllOq#J7 z9g2j&K=b&J@7|S+{$tSQiRjxDlmj$v6N`lg@eXacx|OySeaom=R%EA%uQc6r71SAW zPz<#qe!-ppth9Ki@+;nWk{ZpDVqS(E$hcA1j$>b|vEs~+kJDu|MB>BC5-o|nNo6o$ z5AD5px*QJTPVT!pAG+$u<-Jh(SdMEFGaOiQwA1ruO=y`J2^NZiL3|%?m>M+?py8qp zVq|rh4pzpGM^z8Cv%TzhEd1xgBqqj=#u`;Gw{!lOWm(tmPUM_q@s-tTlwLWn##o9* z!BkaRZldh2*W@LZQRg;tKF67(H##~qP@azqL&rlYgHPj+x%C#)YYWsE{M8^rl9;rD zGbsfn(kHgdSl>c|L-9}>q!?j&G*%c?1X!OU7UEX}`%=pl;3KO2RlVbdJHRxSwcTE7 zW#F|n8?G%6>L^f|$YxXu)O4OF=sCn$1ql*BoV)eiLfwayVKvYI*0fgo5{7Fcz^XkR z+TA<&ohwuoW;q4b%fE1I{3#+#9!JUXs7NI|DF0AuPg%ZwmcR;YEHXUHvNf>zd#AsX z`w#7b4N<30qeYZUlSiKN+%1xpG0M8JTMDaRzF{5xY=#g@fO43jgu?;tLY4bE7;pKc%u`ntb6G~%Zb)omETT> zR>0L;g&beo&De0Lkc$6B`Irml9CS~?GQr2e0VKs3u+1SmX6_JiwGf6BgmbjX*uyF9 z386R>7Qa{+e!EeRPd*QhVO4%{JRvyE*mFVT6EsS05(VFKLV3>7@LHSpErnRHBME0- ziOJiApY~%e)dsR9802o7?;?F=ZfZi?8{G5Zfw2 zURCCKW-0I2dL>z%Yxey4K@e7a^*~2EB$y4&cUtR8x8ok0=q6q^c~jjTI%n8xJzfG( z+5cOl(#42wia&k@$Ti?$6y7Xuz*Baba>~TG$KBpE?(!j(G*K?%CW|i@C9# zI1Zhv5Pz7#0c|0_mt>NrZ+*=**h>277IWF6tV|V_lOsr;Cpxpin>-R^eOp^-Lyd2b z&RDgMba*mIH(DjKhq$a%b74K#VJ*EgkW@%?Q^3;_rP~vQcDhVm{`l5buGxQ$rV^=D z^Ce1{D8DkaIrWYE?w4lXO;ZGMpR1{#m*|N*%&AFDwP~Sq+^k3)_4>T#>AKmhgsv0H zf4cc#ec7!G)gsOHMLKOa7|ktuma@kKgR-#Pqzyevt=nvKaE8abOITA+R4OKI@A>0Om3_?I5jmk;Q} z(5T+|zm?r(!|Lfn>BZ09b|uTw==O6#FYDi zD&kVJ)}LK|&wPJDHvbF(e@YiZPXM17nYTEf07uRyyb6K)5Xuntfa?db998g}D%Ukv z@8ugDWJQda4)XP5Pn9oM$WI7 z{y((61#F|ik~JEp2{UKH%*@OT4l^?|O_-UPnVFe6nJ_ajn#*3sj{>a=gr^GTq4*m-Nh3=sVF>ZdVN*e+qB&`Xc&axPiS z+`dZ~Tj?#ycKS0vYRt8LSGw|IoQnU|X-efUM5zWR)${|kjC{Om+Hcq?y)J33LPg0R zkk6l31sYJll0ivWg!@5JUR<=}Prl`bNd^DR`&IB-+rRyU*xCJ-G zJmMsZcvIo2F^9pu9VI;66@(z&Lpkd}>uC_kfZS=%+xA1%kgvCa99i4RgD!9~>PqwX zTW#0M2HS=FA{lL+6s!*80_$G*|?&jlr9V5aLy9I!Ld0au~eqOV1XRyj!jS=8Kd zDgc$=3GkT4ztjeK=oj0s)4^g%+%LOYQ6_?GC!~r$QGcN%epME)hzmWOXK}tdP!E6o?wbe%36C9lVmQC2;U}PDggZL zHT5aeuBTPmHr$y3xG<$FeVW9~bfZOK@;O)?w+7w?2dH;oF7Z|nc5A;BQlC6LYU9Fa ze!0i#Wv4Gf;|h$l(H)c0IHn}LW=S|eU->`%(48UHzM=t-7i#lZ`&ug4l!Kz&k|d@@@{XxcEl) zr|CYx!ozXiIid}YZ()M*=srloY2iO`qRY8;&2H;8bFM9s+9$npPMb3gkTIb%FNuqw z+nb`FnScp$BpKhiR$aJ7XTkdJryT5&}+f;n2< zF++Ho`4iV4??P&yDvB1L(D-&w>zy4DiS>nuPXFI5{G2@0;MV1ijfROfIC4xKEXUC` zth90a>+r9xL0y{(Q1i8efd8t-`EQFtME((N5;OZZ$r0y&_X?r${D@yTDs=CA)5o|c z7%ge+Z=8rtZB3QhX(-|W)b~jJ*&%RGsv|>TV59QRDO!vPCA2CdYJk@Rt3qI0}HbuAlYIPDa|Dis%PuR<#%04(v04VttnwO7NE zHm|vonrChQR@kF1MpnRxbGKrw07{wQM%djaAS;+3Y|yCnMbR0SVKawMfkAQbqQPUq z5By)Pc3euE{(oV$xc&d#>L@|xyn!jHBX1~FTY9?6RkvVdL)fC9)mok)NM`tSa&$4H z(>>{41}yiUyVoG<*xz2jzypZ~Sxeh|hRspJh4E3}e-+8El(g}|#c(-XRj!)no^EG_ zSyf)xJcM1CmCZ#lwY!l3N*@NL?4pCDH?CXXt6m6O4a;_0?oe* z%7|JTIse1vuT|jRhdMTKQej95J?wK@6UEdqZfE23wdZll09yQVj+0 z8J_GPV?O?1vwo5odH_QKP#0<6jVk*&ftf9rQ ziJ_21rXn*Umy7gB#eX+o|MIuweRNn8fP#Vohaz-`QgDZ2kbr7S zSw4PGQImjTN64=kX%hRJGt%Sg_xU9Yag1ssFGnl^#jqB2yd0D?^WJ0Z4rTvckgLCi zihG5g71|Om{@Z#734elw1XSpIk?Y@)ppoMkwZF&j+qwmWehI!!0%`=L!6022G4NR- zu7i35V-o`t10x_{F?2ETGw^gm0<;OxMH>Mb1QX`Q`yl_tM2_5Xx%{s=$?*kG82=Y0 zihG)vIl5Xo*#F18oc@}Z$YGy}vZ(=B=r_+8m?rWu_H6cIq+uPxPJT6%O5pTX(XZNd zQo1i70x3>qY}UxATgUk>6raAVXF2in?H(X+>vP{@0g3F1ZeMJ{Y^XMvrNAeGl`0!S zN51Da6^aE6Vvo~K;fn2sI&HmNkxx>Q*Ab`O+mr;V>t)zU)*E58vZ}c1`tB>AtG$Xh zOp80fym^f=*UgbBi!Bdmq1xknSSinxz4i3drrq@@PTWMf;;`q>mpGGNd}P9OiXi5K^`U(-zRPC zCwV3_!Q)1l&7Oqn6V0O7hf$a|bcfjLoBYts6XFZ_?BTi0$~~9NE5jRwhltnk#Y6t| z(NauUBZgLR=ku5Y684FhW)|&{B8Atd6N=6g>Fti~BNm<<#5gA53G%-mA7_YoeX z66l!X9#rhK2LC#pTUvszy1x<}tSJ8j4E?9Jl-NHcrv9HW6rkgXW`_RJ1}hEojXpF8 zeM(P?5t#}-kYsZ)4KoQdi$Y!py?v5H%Qh*?Ho;pG7>1?RbNB1li}rZtqB69F?-FOe z@AFR_B42k2ehW@{BOj56lXr{$&+Wd?oX@@d&yOd>0Pv0z$!`p=KnONLibTW22hnkK z8*0WyeQbYEr%5EDya%Jrcym+ViPwaCqp|RE?1^T#K=$NO^yng@bRe6JhUQF@XV_>n zU7iV$FB(g;XX20?Q$wp~<`4sOO|xg}kR7wW*)w=FTVMD2kRI|kDd}*p-a+)v&%VCh zgXqHD!6nkaa4DdW)ru!gkgC&J%ywNB-5{Lko(kAn!+ezk7?yF=j`>sMZji0Sq}526 ztjXT~V%a$qB?2k3mP^d^4!0h#uGv<_1%?Jx>57o8IP{6D!I8QYqF$Er7mn8NdOBoEVDhhZ2M>6ED61~+RNPguRyi;4I8Z0<%nf6)UD|u2Z{E0dA*@(=wRym7% zvG$;{w^wB&>Dgs;wg{ApfXTzWVQcQqnHg-dRPbA}8mawXkms@$(~7E>qA zJa#CpzY!^UF`FH}sZ9f95ffWhcb!asmWSZ;c&`V#;@cXCso`n8yP72txHbev+W%JK zfTZD^7cKkyiXouVl%`PM8PsmtU4D1IYx9ey#EOg$GMbtovsN>dNy^kNA%#WC_un2Z zsXwIZG8BLLLG1;1b)WhOmaC(TfHLkX1DSRo55uCKZ~LN1Uk0MHX$ZyBqmX`zu6(v* z(pu^ov+2%cNk}j{RK36uxr`}Bn0Azlj#49D#Xfw=7F1|wjm|I9sW2?6J(vVk;~E1K zqJ-hSfR$16Ofy7hnhAi6+9F%GuvTmv=G|D}wbs~S%qUJYE2gn+PNUP<7*2E(rg(bL z>L*Zl;edgeD66N0(sF$@wcO-a9jP|u47_p~F&?&M*|WpFUmd7h8<%K&n7;e|IFsS5 z&51K*Y)x7|eXM5XHo%n;s>Xvuc<|j9=Su8>1A1i8Hi05z@un(m4R=JFfBO4*8?F1o zO+l!?1skiSI9~1BuWG2b#&p*#*(7LK*u|=auA&o;lzRGP_awq^+mWJVfGv>lpTgDo z;UP8ae|Y}#ZMR$-{2qJmbF|5hPVrjKv90<8hNrWsD}V1uUuf|6-e;O`+vS8VHU+xG zi%O9|+@WAyhsv8ZPA606@>d8UB;6JEl~Ovg5T$}r3Xg5+^a>P~!q7)5zX-&s?JjtP2O*s8bl(@bbzutSX-A+5vkXYk1p1)~G?A#M|-1Z<@0 z12gR%)aJd?yZ(dL(<7JN$?bhC?a8|Jm6G^lHD%n(!LHkf0M92{OVelPqUX+0 ze}J39rvv`SxRo9*c-%6eZiEn=C{(LI0Lr3-H%@9to&1cM?uC=iFnH;cGI7#NY)UTe zofGb(U){)=kW_>m2`14WEmN#C&o;^XE_{NF=Fv2HIk~@zDN_AHx|lTS5G8Yjj3OJ7 zLMC{EjDmTCj!F4R%?P!6#59^!C49nEEvJrt+NbIvLQZ1z+#2=07?2SYwbTlTNI}mW z`TEvmZx!T!cARVBl0CoP@{s7FX2C)8Y0~40oEN7sF;;Yk`B>SlV{WA64V4m%k{c_{ zyZrh!(G#Y+7n2N?lyg|)lcqf?itfCmf2mnAk$swc{zxy>Ya6o=KOGAX{;c+ zf=O(PmSc#J!-f1*Pn?8IoYWuu)Wo2`5~BbmPP)G`qJSf8t|9#VFGQY{anthu6|ngi z>9<$e0DcsNf~!2mEvlyyhYQ?S-mD=V-Mf+S?|w&RF#u#NBPvB-i>H|$1D*1WGx zTXi-!+ABIanRQ*5CK$tBMC3=pOHZ()RlnKgR+QCMv(vV|)GOnjH(BQKBX>8NOL;+& zT%{&XtC230GwDy*W~v98bH@r>I5sz*0i>6Y(?V46)NhHM_TJaYau`jhX&0|@Q;2TJ zn0G(Y%Idc3EY4kY5HkpJen?I&N}1@IN|-8`CN@0Y$bO&k_4u4J28Z>R_Q#+b9H1Ki z@}l2Ex#~N~e?wS2aiNZj6+(N%(kItY#|cHwZcW_M>~I>vEfJ@T$AXMsqB}GxT^gAt zG|aO@6C2gtM8Py=iF4S_mB(qCjl4j|h%_#X+9InT6h$Ma{od*`lz>QH;lo^~UmrCh z9fPiH=R4dXB87_{;!VjqQT$hIL)`l->-kH!cJ7P3!SdhX*#A_%6g6@;b9S_Jus8dU z7#pmoE&yZv^Gu$_g(bJ_suY5rCU`Z;bhAXhMGb5eb&-QfK0PI+gz4er#EfOq*6+T| zDrz4LCh8jvLyEY#IC@GDyEu)kUezij29}zxl9TW#B!;-yd@e7emGz52&Q15($93mf zuFJLi=|uDMHnbr(eaz6fPVvNnT}=Dh0d9{d((a@u){%DXjd@QvP=D+VdyV<&i(9rm z(2?kbcJwy}iAi9hBNIqG7LG$?v_14fb)-Hvj!k5-J=T#6gdL;A@nCvlzBb(+eL*)7 zJX(s89s?cQiJ51*Ho`acO><&A5*Yg%1C1Syop0is2ZS8M!U@MQF!s#^VvM1TY2X-` z_~rr;#)4xUSo%g^IF5+NJh1o7eB*(BW5Y2-O#TxuC`Tw`@i>A;?ckQp^wW#Bo;Tlv{_|9~?oSVlXHqA}jOX0d`v)F|3Xkc>OlSaud8c5ZN;y2J)a{u6H6&F%tvZA^rhD3nsUi=SY$t%Yb=G@s*inW z<<=;Oy}y~wJFS^ND9mNMZx!{&8exr@m?}%bYsmd2Q9~=%h8w36p_|^#Yf8WBObEbU zQBE=Jj26#!hC6wHDO7)LGpfC@!d@+HIo4uOKzQ*WE7PYVlv51{~GU7=p+2v^2eQOqds!6y-LYO9eXC-!`95znyIs+^};MWjGuV66dAUTBm&kP+tMrhvP8G5fPY z_< ze4mXu8YHA{{g_iFIfeOce67T5W481Q6SnwMv{Rxtg2HodB4>@0Krhw#pa%Qos}1fo zk6zD8T{?5tYo%?*k#a`oZN4ebGW2<@cTXd(Yen>(j=0UD;V^TCiB1_=(z-=|9-Ql+nM&~;P(6kFQV9*6v2i5P~Boo@ds1$=f| zH{&=1Da8gA##5fpD(jKIBCx6lNtF zLXTAM`he`RG}PgRDL5m5k+p#xBR` zIRr>m@WF$wz+uEPPenXG3!KHX6W)FLITSK zptNSNL{2QmuOTbVXoVV4)Zb2oU5P{7QYPS0zY=da4-wWwsvB|EjKA57G1?ERZxg3^ z6eEQo0hF@giYC#osrO?%mH`HYJrZI_O5KpTUi>njPs}oJMA5-W;Am2pFzZTC#l+E=+K6+rH_@#VVIPS#E zA1V6_N7sDi(7BpWLz8l!#-`J>c26_dOLB#??7Y=e@5HN5f7Kk2XOr(`rkT*Vi@L!FlcjPDO0R85;E)c4dFHm@llHFAO+ly{d6oRh3_2TI5n$|6-+2V~o0cHU6??0L0=ixvjk2nY@gu$N+4Cq_(PpWsj?@eLNrX&1+pb(W@G zu|8R6{DVb_*8wIW3?-9+HsHT>8wC_tuo=fePW!Y6(9tLTb7^J&% zC@X54wAwr%I7mK0Y4P|`l~|6+n9^vo?}VGZNoqxddmt#BTYHqbS!!5r^oobJAw~3* z6ith@8X+HQtYm0anQ;-M?KhApTaP2<))28DyV$;o5hoe#f-}a*Bx6UypC`tc;933Q z<8fHfwE1yXgjFb|IM2cDT(m~laCmS@AYh3OmziYrGq<&z|>L4cs7#hFyK zdX+Yb^F!)EhlOA{OI?4L(dB2b9=kM4N!*v}Gjq6KAoUHm8c=9ll+U<+oJS;Mk$ILR zW}4?v^Jk(VFhnoSX`l_zR$IkoI=#jd=U8)uR|9+bSFslzyT9P=_PBFqYp%93W=)U_ z@-fG{)1l{>x=ix)yP20%&H&)U*P^3nImt$i#TN9H zw(L0j>jcEPOXhhtb`0A}zuQ(VeNtVF{mphUdq zYXm9+GW{_a=_7W*hko6TB*&)Kj5U3et}uBP~*RUQ6xWIVJFvg$uZ%zKaR4ajqT<&Hry zd3J|wLU_!d+0{-E&_5ORCf*1pzA-c*<#RcM%eGj%a!7ynVG@5p{3}|=VOT>n!v_J; z<@p~<+x`=+{};FN?+&F`8}>^TtyS>Mzj-?(FeIJ~xd|D@FbS3y0tOj-C;^@ff(2Gf zDV!LGI77}DbGudBZimyFeNYCS8PG^$9n@N+UR|qGUAxk!(OTX5dby-txmw=ma{W9z zOBS+r^1OThd~d(UfA%r&J)e8KjkU)Q2Xa4}CFY4Xjk=FOr&vNUFbieR;jDTvCUeb6 z9)wrjv5^DA-4U8?{egVkic7fS+?<-tV}H?UwO^K)ZMU5>GfTalGbJC9eYG9ZxiKh@ zc5ib^aX7ZL-JyC|CzcUM|L(-eS$@A!%V(X8ebT3A4E<~&b(yk0IznJd@@#ID|xHOnJeG#FFmOJk%hcOYn>wk@Z?zBkQ3A{zhd?_Us&?CDW${ z(wO_Uj@WpPw{GiF0=*+SrM78-c&H93FY@|*k=fbgPcoM#S$?Pvi7)h#?K0c*S=VO> z?b1DZhoF%jQhZcEg-CGJetIB7q=#&ew)oLpd{1WDRg^YD8! zZjxt6I^jWZA1zQhaxeKMW2Cs}wqt~nOn@5rhMJ%B(lSCMn=j=X+5fJ2s7TgF2gHaJOnqUEte1J`{^2Em_#5>HF>sIUqkF_a##i((8+9+~ zg*LK3?FBEgKlOz-vOoQ$ZA4JYSMrdEypJ}K?Ue|1Fa3ow@{<|}9!Vtg-aOJT^)7Wd zjv6ohUM&U&tQ_h85{x+fA^omgK%yE&N8MDKK_MQeBj*u~ zW1kqE&{fxKA!$>>vPf{fzCswQCfVh!-HpN*XvwyywTXLu5#>tU(Wbughc*bteDwM@ z@3v>v(e<^ZQ`J50{C4j^lcmKX@X6t%XA3R1MVVx8d)B3H`Xl zm0vrNO>DSLcw7|Jts#rlHcm+z5@iT@LO$mJA0ElhW* zAd^g`XGznM&Cdwx1K%4{4!2FLZcCV9aK}reVA|a!d5RD0i$oTOU+PwG^PZZdEOfXw z7sc>(ie?j=r3iA{%)mc;G?h<7k6)C`+;F^bDywN&iQPvR15V;#@Y-f)vLM|p-Lx(uR& zLH#{p-8-y3eV&M04|%@E*#EsI$y}OVZ!i%wjYr*fN$WbTuJ+18LVH72#!Hy(iUf(| zHEmU@g?F9cy2Nq>)A_w@Rf-EY!u`Ru+7r-QZKct%wB|=*w7v^b!@E87Gf8kYZ(zM6 zM{jkKL8P(S2kZXawh(<0RYDVpbcd7eA`26n!|OA536nGj z_``d1kNXGgkj7{J{3mZj6f)eH7~5EAJqwE$;R(RGGgZF!=_&`?_U7C+s>b2KhSN;V zJ#*TY@0RGc4|+HBneP^h>vXX5HW6BJhz|+Vm{4TnQw8?LxpVTUJV$LL z*ui6j$bq;NVJ&^sFEqFl4GsJ9K01^riO6J=ohfdDgE>c?5W3W*#Z)xAn>i~%`trBS zIH@={m}s7GfXpWPue*p&<2>kcBSf64M=2^PUz%?VbZ3eVg{wniHibP z%M>Wz9^H#U*wwJu?G&fx(8*{o^!>4U`CyVt6?(?w6zAqpydq%|3GucRs0V`c59E{9 zloo4Q*}wkX<+LKU@GL>xx@)O#?}RgErSqnjMM++DCho3T6-Gk8tvj^N2BmBM`qCL9 zW?PO^oQj;wym&c4g6~K@qp5rD6L@AP)||w<@^`NO;Yh6%cC%HoLW;RyNvn?139qk- z>ENoWv9ESeMf3n{;|TX0Xy&cmMxvv~ApnGvR#C{Dk={{u%N&G} z=17P~MG_TRyLdtu4NI+k2^%BUVucd+@esCof?Lf54rzj1tBSXYDvs->`jy=$ZQ?!C?6`@;e2sVSX{%^5DLLKXTjEx8KDzeD0(Q_WEK>RFn@*4Y*nKls8?b8XEfW2X zzlY`P6lT%b1z_Wy0BqOp!es0*%sTVO z=2TvV;5+~TG-5l~KbFW9jT&IKvYRok9IM{@NVZ&(1w}Y;}ogPh&2hL$(4gT0`t)0gCIsR z4U}5U%ZBv(R3PoTo+r8zX&Ert9`k*v(nYMPNyeko9cl%QG7LWODUr!E`TY6B};i3DU*O;HH$Ish! z*-b;wh>UH5CKt}RFE8ZzO_vG7AH2U5cmpCdfMlicA%9efPgeC~{Q9%P8+z|~d7c=z z>!b27+N?S%y-L0&6NKizKlTWC)ZPyjUQl>zKe0|QR6}}SA=da-Jb@5F)p*~vjU4p_ zd*R;h0UP)rr+)Jz6*4>wudLQlinE{NGBD<@GsedqP&s1YW7}Xi$Xql%^Fe4gXN}Dv zIvR`}1mOEjQTXve-Gv2)$j8WJ=)6n0!3pb>yV7o+&_+4Me*!#*voEkA=J_wEfT--5 zGT*;Lg1|!Da=!Mb98;C}6FiPCzg^w@w$fMd!+Eq@Uc#O)7BKv=Cv;DnVj9r9tf4e7 zn5?ey3HF#>@gx70#^=*~h$;4!etEvIFU$LtC}=snvc9k{_*L8IQ$5Q-$dBL=x}qL> znhW9SSt3hN;cv4m;=Nzysd*shPUZ!65KufWkWoO&gTjF@1QxOcdi+UPN=APRDY6pr z>owT>S`G%XYrJ?52#?3SN?yax2_-54# zmRNj@@OgcoK%}nA&pn65PBz@oMIX^C5YU?_gJH{+?qCM_V3yVhIEfslFepj(0hAHZEcGDXptBT7npcKfUT7S?LEq&I(Y zBH()$lC-UMlbo;weMA&`j&K@7JmJ?f@CI=V zKQwdDV^KPPMm5flgmy66@y-c2>#w{e2Nf1eEl9K-DIZm_X1+T8TL*RnGp8=$M;})# z>*6}fLenb*pFQt=IIC$I*q-2gUn5$~^;h3%s`1HE0hJ&v&+@n=QHf8FHo$?Z&da@a>p<0hzODK#g8vdpeHbYe{idW->pnMcjDV&l{$2JBz zLk@sFK3MAd6?^W0%W-7w1`V$=L-xS4k#AG zzM}Z4ic98e%FV2E=Jc$wKzJFNF*1~9B{TPTLuNxU1((pyMcq<&N-Dn4o=Ya#nUz!A zR=&~A_GLOAus(rZaXQ^}>yl-D&q?r(inIN*6Ftsk`^DAim9K>&qP&FgERKuCb zL&=7er^*sD;VuiZT6GC5TlgIaXTy3OAaVO5Tv5^cR#OFnqa-f~4580X-0zSY1LYl2 zMV%1I=e=nX@o6MuO1nA=8%-W+ZB#QXb&Rsgv-iM&_1v;XTfW;P$I>~Gr1ua%8*oEIX zO^ul9Cj2Q!9P1(FLI`06DDA`4>*!~D#8>~(=#`Q%e<`|OM40c$M6ylW*++2iNSwfv ztq`BQ;`tc$Kq@f;Vl+vhSbM^jYSiFujiA1Vk{uuD($hJt-lYnmPOizsEkGroPfZWF zXGpK9&I$>%m+fz{LMO-*^b2;og`dol5D+HruR{s&Z{x| zG00)gKR!wU+3mPq2WWiRKxSPC5=o}%2)H}fl4~BVQ9mt_XK(Zbj*I~r`V&}4_fwhT z7;fcypv?DM6T&$YLVS#vccm8nl65~QDoPI7Bm5dL93qoz^kvoS$*b3rR%|9IimWVZ zqor6VbGb$YD&TVOJ~VOR(%=pI^~<9!O`leCz-Uw9h2NMtZi>>gUe&_1UYPYf$CP0I3DwLz^Ocn@Ram0Ek(6Qmo+O>Rb(kfE~z8!VSt3iYx z9FscAFrJOX*7(v=_Bk-~0*s^x%PzuK^n+O(C${awCQbdA;!S3SF?Fk*l@Jy6P7#}> zh=Oz~X?)?s_n|!@^2Q|{Q3c{~ULX|4DXGx}V#^O$*W>07yjuY z829rJFy3MGM@^iZKC|N9)?Byy%Z@(S37)BWiuI(+jHkr4dJV^DyVh3Up4L+y^a+=K zRlIS>UddC=AcNigf@DtDNB$NP1KuVDu2T|7zc_$tWmwr55|XY33mXT-a0!DegvHm+ zrBRb@F(yN1*&9by@aBp54?>R64~Ke9nh>y|q6x$(5Y=;yn!{RQh*3o;} z)#@m4O)Ci_3vMMwKQoC)J>!D5n9+Flim+yeQ~aeTYRF zBfL@5gl-i(ntjYT)=6e&_&{K2;%U98cl?e^K~3SFuG;)e?wDMs3{^=5#}hTdP;BUMXvu%cIZ4;nr-9;xGMjVIBkz(Im@I zwVzO|;=Jflh?-P$0e~Vjj%Y$lWD60g90U|6#2m)C;ONmmj-?&QPbxdBv21{3Di^a)?XRbm;B93s6O+%mK8^-p2nrS zV*A*n+Z%Vfw!P@rS%x@J-#uJg3CA~4%kj-QgXkp@VdkYy(Fr$%-b$gTq` zI6kzkFsZX z*S`txyEqLY z)PzT~^h6(v95*WR1fz(il-An|2LqzdU?~oJ1L0dD&kW-|K^c%42gwg99YZ~F5F_%( zDt{NKuL;-I1#9a;w|23#cCD%)8ch|`ebh3$0mh3ywvO>if$R~BaZB6v?x*oJ3KLqs zIXktI#q-{Z2tv(qYA&W2+&kX-&)Myn?b*<3))7mUZmK!ensOEjY2dS zd}z|u_6fI#_9J@fOu2TxSUX>`RUqEl&-`5W24(9nZqsYn4^0wS4omWis1-BBj6HRI zw$Uklk4z7p{$9;~<`MtGPT&v6Oj{NLY$z^xXfj*{DUR)i8Ek0sG0zItq{9)*1!Fc# zX51ER1nn4GKgK?L4gYS*ogF;mIAuHj(rad<%;zd?n%tW}D>Vm;U*6qe_t0j$!B3>B zR-&x7mx6)1RSe7&!=9uB6gaBHI};)75}3AZWrLU|JeMraM+^%)+HL=AuV6d1Xy#Zg6&azt1H2cZ6cu zR=B}=Ya1#NbH9y1m2Y(lU>2uE=SpuT%`sz-m54Pyt5gQWgQ6U5*A1IcW7HoN7Ux^% zPje+fe>{NGIxpK3Vr;LdNq%YLGaCI({haA8!(r~2;r16vA^G%q#ZHRw_#_^GMKM#6 zcBE4OTNGF=-*C%BACU`>$+GO+Iuy}+Rx^0Do_+kS?$vLXEBCz(BPqrbKL-PM4i3R0G|UC{ zbi>ho{fB(UZ}~dB5Q_@zjO&v#u6PQc*&$)iG>N0$Qv$xOBM5U|%46H!*q_jtjN$|?bjzr^GI!2H8D=#sGEIoX@o~Ef^)eUD zn219zz26C{p=w^=ruWR^;tFYnu{8q6J8;Xe*9O#%w41I0=&zi=lspF5a!k&uwQwhD zGAt8hy{^zompfk>b!XcWGFJ`$Os33hH1NMIUo!PD!7w6z?#T8Q$LOnw5Q*Q@r$qFL zOaD@r5&7#RGqG%8ameS^7W|o5=x0oNWfVf4`DU0C6}(kL#tM`7^V%6}(uY&-dn!`5 zY}9F9(GK~jd%D=in%@(*o4Zw#T0-KvC%iLm47V`c)z4KQs_PWV$sUV57z4 zQS9+izp4unwXBJpvmV2O(0N9zh!*#yJYw7yO`O&gq6DbL^HYixWeU6gwx>08I)N<-)mZk zbw!Z3FEb$q{qRGeG`ei)@EK|GPcTcz5^J4IZSXg6CELal?T+?;(%^QY7op<))IXGY z7C1&F;pQlU^62uR({!NHT*2%NORY9KvDWOwRj>O;ceBB>B}>8{(lHj{7GxH!VxBT! zay;7(+bCEr-DL2+ILNDMRBU)=jp?3!#utIr;6J)}6!E@nNd+Hn6$mdlMMn-cF(i^> z0-AY=oxK4;k03L&69vHUJ!+S1QM#3N+$p0hi@7c;dMTsks-5Rl&W^Y)PPnqM)sW__ z?nk6FJc417W6WKJ0)=WX)O1WA5@ypDYDm5!rPJw~vQ1aMr$O*E#xi#AHZ7O`Y*bQv z6dMRMz5=Qk*&}YRL^^&|uAsM7CnTrwlVIlbS_AK}S_3_)bcTKSzR3P5IhJ++>N<3SRCWdKtvS7Ll4eN4 zx`5`uMen<7ib&^wYNZZ5-rDT<50Fy7AiQAg|M)MJYgU7y!+CHZAc*MyLk-1$W-kAe z8u3q>p@xs6+6vBRuFw2V?}qJAQwOo)SJpDS=IbcT3aW($GU9}ETPY9&+oWt$t0p{m zPGsLe5#`^_D&j%nVy+miMXRx-wezd)wzX|bJgx4&ElY7rKhFhoty@jra(x`G?L~~s zCv#l-Z+Q2PJo@f)$NPXQ-x$HTkmh-i2il#Lf{CGhvDHy#h2cqqHmJKg2w+=(~)dH)3I};|uCAm)V25)JNThUc51UAo~?vIU}wmFx~+8N)-H|)M`F^&SIqv7KrDjPAl z(?r@stILZXhqxS;1e9{!HxBDDq|1^DE1s;oU8s=QjLqKM;^_|2`dg;tgBNVV#fKU5 zXhpA`63D(ZL7r$y)|n;z1V|*o3Wj&lCQ+`nbM26f_6YL{V?$wF#Us3c8z&9o4CUj- zmS$RR894-RJxFxCDNx_S!y}|Xf4ExmcJnPh0Ih8U$c9NmnJC8^p291#z^C>#Q>w5p zZF?HeJ0ck&qAnk6CP4%rcoM<3q2NSbQ>b*sK&29crWD@NQQAnpy|s2Yu2d@~-CWD+ z$|F*tJxLYOw&{>IFE#@++-CvklW7a$=oF||OJmq~q>*tQZM3L(@({4dq8pcpK||ob zOC5&~$WEeE&LYS*TN+D@vhdcRNE$7xu}xuSt}Vk-63=o*Ea%Di@|IDhcl>0zjJh;@ zXUFhcDiQ;zI~{H|3Lh!Tk9W~gc2R0v-o#v?Ia z!qBja<|3UQSO?;Y6}IDVc%9&pxSa5jSkPy3JdOB%jllAebtNnC#YpBXEZm5}#q<0O zlpP%~QLu%S7q++Dy%?e9Q!s7l+>M<5BOQmXC>xffsKPa9}xYz5B&JHI66kS=?B{xq2gijq|gI#8LKw>aaj)Okv8oSk{pG~^$`n1b;yCtAL+ z?3*28ywVbH8L!b1-66*eH!4L+7&(-BN$v;^CEhn)E}@j-u1EJ?@;4^ z=ZMuUs>A$3DAW(ya5|wwWzFcTaKP6isyR$7r;U}|FxF7G>AngH_fQU%5%np55#;=QBF zC_jg1#yPCJD+o%SAm~T+gVXa!U)f);r*0RgPuFa_-c9aOZEl@GTN8-WsUMxQHoH%s z(c=Ad``V;{6;?A>3X{BUmUZd`o7>j$vnKfgZ!oshowUWRKNsN6wWBFo$C&r{72$8M z*f!YaxM^ml-1OQlz#t_P3`#oMumvu0n(xldMd(YarHRbLX_zw}(J~xfHZ7@gC)1!U zWi+tu-j8AF;|p=4-y(CNkfvBtoU&$YsuTz?%=YbPcJh zU+tF^s^rz)C z`?cc6`s#!o{9wBk2+bTa&J=TY{=6-_9;uNyfG2fG5Ob(^_XlO{milSmMK}0!pNGPT zvDt)ZdK|%);i*{!-}Iy-l75K(Qe=Bd{m8uy)}w*GBf2-Xd*jA2!Y^X@(&ZK5i9Ak* zbbb)(S^K#^$zRIYhDq!Bg#GoSHgnyfoKSr3*t*I^0pa3u|5q=|Jn;tE6=8 zw&#I1CvkT$zSIMlGy|-<98)|t?qNv(KfJwTm}Fs-=iOyjb=kIU+sd-LY@^GzZQHhO z+h&)|uG*U2nR%aQc4uby%bVXauX8d_TqjRN+;RUSetRc((4B-egY-uX+wt!=mTvss z)cAwkcZ46h-3UIp*k>_!FfRh1lzj0!gE>bnx9G3DA1dDX_zQh+?61t8{hWM9jyLjr z_&K)*9}y`BFy3_ChtxNyCC?ao6C~Ty96Q5Sogrn~hVXoo4zG|C2O((@IlpYY!?Ol* zjKDrjD`R_x!e4CFp}u^RZuuGMzqqwVdw!vY4<=JUYn8XEC+!=09|5aYfUdbo5o;AU z)*X!(Rm!#bS1G)$iAn`lE!ONz#0{uA;&)3@mxWI(cZPyBsrFov8e<4n7Es+#pP$~@ z6iRo>wS`tsKRU&&Py?|b7u7m!`@tzAvo(jd%m-f;pIV|kyZMk1(OEG7{dCC&~o08p50TU4qdAbJ);h+DJ-6htSOdl zjO&hsZJZ<QKe~RM~IY7{+eS?^P?ZM6pI&?=b*zOhLo0CmP4SoZi3wV-na*9N%C#m9i zsMWJ|{bWkm{`6tc6=0<}jp!88_M^Y+`Pt&QnJP3b$<8Q$NiTh->`5PJpI%}ai?e;55U;tCSMU-E^PHtOT5znw3u|_NL?D#??P|Jw zu3e{l0^&3%pQAgL$lk5*HAAz|p`eEs99rFT(DTnSy=V2c0*UX2VXE(hm+k*b4Gb_g zF}E=`QnGcnG5WWecS)*RzmZi?K8xFAu!}SDY%Z!w}@1i3#=hIn)6p&RfVA z0b$KZo!sR}?n$V$@X&G{pZ27L1BSLQkmII4@0co}mk4Pd;yT0?n`&vwnRtl}gb zLVIpd)1Z%}I8ut1_3?W1QPh6`aCGDXmITWDG~)YGJO<~bed{*Tb(tDqqc+0~=Poy+Sel%aRwf454go4gl1%O9DFx|VrWA-KWh7Auzt`w6NvjMP9Nv=aJu#9Ctgu)p z^h#-@IhschYSO6P9gi28rg#Q4r|FVYz*t!R8mKDgRdttc0gLx-xQh3kLsGed2x6xD zvp9iGjE<@++F_B*y_HKt?Rj~aO-eN@Qu_u@ER^RRJ1epKA4!!ZPW(B`)qq`IfKrV> znM@7{%EzRkgP2;1$3w~P2s*hcHx+D^?qdKq-c-Kfbb!9&sL1sd1QSgp0mUMh=tJKH z1eg7iP*=8-7836)v1Qoaz>j%;&cehBe}>IOJ$VuE6cGCOf)Dp+zg5-gZhkLy)GMVD z=eB%o)1}RD*A;58!1ze2j%3`)>6i`u!Q2=7XSeK7g(68;Jt?r4_{>4qfozBUe zaquD&^z`*>G0v7DDe9!r`b70ciB(DDYAji)-8{^Iqgw0ZM2d7vqSW}QMtb6mYGW*G z0S41?=nVyNvMTJStbQU2^3iePSx{r(0qB~KI**BcM@mc}7A*b99)%AUBnbJsJuo?C z&+twp8K~>=pu$sF-rhFdpXshNE*y&LES@L@wQr$lwqQ7q*n$!Vo(5z|D_-Ehy!}28 z{H|AEpot2;K8)-yQL9R@Rx@#VG*zc_bo9Rb=+PKEj(ja_yQ?4XkWkvk=|qd5(faei z2+BZKc7&pmy7ik*Yc}zVh?=x2?B{l@yPi?AFoE6OFwI5a8$zoIXcy*A_gTKU1zEL; z#BJ z(sTOWd62w-+;Ab5b)k0Q5qtXeJ-euVqtkcbzuUC&{&c~uW4f zUe|BqU^=~Jkze=y{lV9BujShDA(wakJ9^Vz65;c;!V>p0i$>c>)$cm31^?75D(Y|O z-xmz=n?&M9ITQZ4N3#2OYO%T?d!7^gYV_28>E&DY<|Q(;+Yr46{=Unr@wF(1*mg)tBlbw>Cqg)+&cYHgMTQz>Hc8P)9VrR~Kj~sFor-UM=4PG2 zAmp*QgexiOuBY9NW6RH;dAx%_|9#>lkKZ4~y|~@ByzaU>*E)Z}*Yj$GA_!s+aD_+r z58Z!-e>lk3_9j7R4iz=>ha{*Nn6E<-pbLekfp|?#c}^jDG;Bk0LUB&?KkdHCazJ6t{gES9Yy zi_=f%a8Ah*@cbU@v?7Bsp-jnasdxq0^az|dwJA4D#d|H&d=L5EsuAe@?X5|$>WLUS zlT^`GsKLlQp~|F0hgKHku{_T4c5X5)HJx%^RM{j%j4SGBJWX|UVGP75trAitwKSgE zoP@fn;rJSzkp%6vZ^_ovXrxjF2>#^Za_w1p-hovtW0JiGMwmR3UJi4&pDWL1M2BH2 zY;zc<$z-i?b99UEVL54q~epAMJa*2)>a7vL7Ygf3Ilj)$7kXikw~C*87k znuM<_#I5YFb6l7(Npg-mDe`PG=@44KLw)YkYiKKX(;zOEEbbj|mk%~9Q`97ja6a8X z`bdta3J^vT@`j!mXk@vXP#7%TDiFlXbiTU~^w(`YrqHZr7M1F&v|qTNbm$V1dVK2j zlj)<@h#juLJeSZ-Uc2GJOop1hbp(moLkAze4fG=%g!M!R0Y}1^wO{Imc`5Qkx7Q|U zWYq^2-XQWGE^})FBJdk1nJm|6w5q_WTB1%8+8!6XbXasG`{PfNULz`P%&n;#zFvV! zO(hF2oiI=>d3GG==f-2bOWJ9*3o3_|nsCLt>15liQ0ri#U!GopUKPK!FY>&M0l#Fd z2lbGn(VUN|Iy)(Wz{|cVBQFA{JwWZ?w$$s~X|n5l){E^r+=~J)S(1%%DtU?Rmg!Tr zI68W|icx0oCKpvG_NiCgJPi&KV{nsgwPPLZXYJft=gNtW@i{y^@6z47&BxjL_o7|= zcLwKz_g$mEag&Lbs7t&?ReD95gRu(1vI)v$bDKkM&j8)Tc6$7NU{B?I;w2lnhgbqD zRUIzUju}lW*oob#@r3mkR_(-Z!ETS*OFKnounCgFM*oFU*U+6z3eexE9ybhlgnx0p zQM^tM(s)JPV=Aj0N5l?1aPG)yGNL@lZSe*e^b&ZcdS~A{fl6v) zEEkRYLJL#@G2FqVtWx74jPua8TrVSNCsaxJM-hjA!m9?*7i|0R--#2o6!^_jp_E|N z_uoLEPY%^q7|mP#vn9(OB<0VDh@b6uHk7e;Itu`noA~d@%08a=Y>mZ1Hg_P+rg?H% zDQN@L(MdLHO2oBYuHl?W(Opn8+vax?)pikGtf$ubu5%5yNY%IDg;m zdn;tQsbwA{}lDUG@RdF#_n2J>o83|NSI` zhB)Q3gAuGG_TQkH&4D_I!Po>J=nOEuMUOs{$7zX~%VTtqIbe|Xj@6%xop)spCN4Az zn~%z!7b%I@V<9zcL?2{MCC$lc*&)A7CO=DrQ3#{`T7G(I1gj`7S-)h<`OtQ4vrx&i zk$p9_R(?5z7(woq>M@=Z_YhWE3-GcXI3@mxzv_wZ!TwWoRbZu`tA9_&a&@aCcoeIB z<+dt@RC>p3K?gloZ?-?B@M{d{rY3nB&)Ud15!WX*S!La&fhhH0L6?pUd-u#3n`IB* z$>vM8?8^!ycUh3+Fk~r84t9*6@$4cEC3U#bWlrLELq zt`$dZSjAXd`sKjeKkUatO@S#>zEs=ujfjY}Rd)RdhF z;bEkRNJnv4XnZt9g3rsFEjA<#$@1I=%`~AL(Qc2^HMLpg6nvi#au7mCkbmGWGog{d z)80hLeT_O0^gut+xv=`xFjT~TmAVR`ahS|yQ=T8Xwj@XG5WS$&$o?R5zj60iVt>du zL}wa~lMu`o8p`PZfQjl$cS3@_fNpqwK*+Po&0$!5C&c^c9kXkoB1Z8HXXkek;{M|Q z=fw@3y(@gocdKLYcMxUyzgpb^<5qNIdeH}@W zLzc5B)91FjD!MvMXR5Dkeg3`x_tGrO;P_hi_f~2i%S;|@GE5)%uj{hdNsc`)v_>Mx zs8gh=_o9MCfLB8oqVep&po2APe@6T2+N>1yN=)4!N&R*d25-rV`W}$q)O_A}#o<@- z#9M&J))n1rRfWr9WjbM>G4HaGkzw5G6C$ zA@D}0SaYl!!w#={yF^FPm2Uh))1S%6Q(!kr82Oi}9PPb`+M3Ie>gn7{ZwPRKS7V)r z&hF%oeDHv|Lg>k)IE2`EvDMBkT^FI2vEZ^%nNb_i>dw6~vgj+@sYqz^JpwTr?E!JL z@m8B$gFWzM*v&?Tp%FAbLD}7^l!gk!32;@K%Kh3P=26U6<2@x$GKTvvvP1qkHFi9S z6xqohHnEsRUM$XK`@K2!goH$_aLdTNlXAD|p*-&grXCKP(scGiXA7oCWnQ&upIiEH zI>NQNj|94c`g-Mx>a9)eelNYXC8t&0o%MLZwX@Mr*Xw6Yj%~3kn>I}qpWVd_xSy8c zA#%IF`0+L>Ew&#PV`2?^spugio&(&Sx~*u`(O5G83S=-d1l=X^y%a0TMm*t+)v6c1 z!mb$(kOv%_+#lRklH(phdcV+IVqb#ov#E>;?;Ra9v=-_99Jn7d%ApKD;+l2L_6(0Y zJ>`)Z47>^Jc)ma5uT2sc!tfKc1uQP){PN_hGS1O2HC+W^m8THEGe=RMVCl;u{Vwv= zh9g(r&>XvVthJ77U31ap21_dfoj@@KD7l7Ym%n+qq9-I8X70jT`zt2ffodG52?QC- z3mE2&*kz)roYG#gI_E2RM(=?_FT|||y&jT|FBe3P7~1B$)9-u2lBX$(tW#P*Wkz%L z@i8O##Np-b+-4FriU>vR*GO2%qhyG7cSz`+A-W$jGBNrLnRx}GU`CaGFmFJx1nF1v zAvfypOQT`d*1`)0kyJ!DF47x%;EResQ&7bnk3qVJ8Oe*GWQoP;p^B1AcIQjPIwV;i ziG)BRp5QoL4VM~QP3Axr`*GF0O1pVz}b;u z9UnXzvgz@>dBStTd9vwo|J>8F1#&|(?oEOc7^i%La_nK&v^$dTf8N?RP|^9E9+|c63#l!Pkwy*|ocB7tV^>6`9++b11nbjdX1F z_lIkWR|3;^Lf)9fn1poff`?`qjSN&?k=JE3+JvP$TeD5FgS(5IKYjLs`3uP^8WxRXnbyjrD#(}^$4}! z%nY~eOdpO6_nLGjs^i)eAR=7Vlp`aG?o;*1ukWCiI{cMVfy3r9a4e`8sL~nJ8R-v= z8yuM*j_@^8k1@Xg-iF=9GCG&`JwHtpTA#U=Hj%` zj_Q+(4$#j$G1;G_hC@D@)vx^x8rE6(s?<^3#rj{$suQ=)+lm+TTXg($P)P4J)2>d| zibsZ-;^loJ!gLiKH0Gca{dQO`ARk6U&Q^j-?17wcU;oU03HUBMC79t9)tIlRm?aYv zp8eF}pR0#4WT9dKq3;jj6frAWXAohOV^)&kK#2%6szl-x`AzZ$!-JsyHfv4D^YAqv zfQ`108|9MfI@Et!H*7qJBX@l4x(DMkqJ=wN>LYj-FTq;`4=+8$dS1e* z6Wqu72y*;M1kNu^xOC)jx4_7w%-y9{(A9i0?tt$S#Y~(WC>WJRXqm5`Cq_ehz82dX zgI=BW7*(w!f@{LKfZ0ki-I0Vg4j%?#nN-x`^czFQx)w9`j2!-@AzUxWt~ndFj6r-g zOc5W&8T^OQ;VGXFQ=QgAh+K9v|8fHis}PH-6NMqLo}h< zh(bhkZqm7QbhP}~@Js8$0{_o9a0?Q5{5-5_)iyYBj8(qDw%K2BF|m{4madVid4yON z7<_{VBQ`o#K|4q%zYA|X=I=q)ysb**H=;&S%PyOO?GHl=FbB|5G0bYBtv+4l+R+4?+w14knmK=S(`? zj@NOW1f?Sd_c`x5KChogA0zzlGcmS5TG3ZJG4Au=5BL@h^AkHp4)Z+_lUR<0ae}qU ziWUtrRq~`+?5l}f!1U0?+uLOrfq-0#$om zafHkX5^}gmtF8t&>R)!^rnWO8D+9Oz!eDioX{ljOWRrvgg{c({Ed^hQKy#D|%Slou zvb^Tmi>4020hCbCFJf;U9^fJE(Fjix(}BJwB!*?JbCNzM^@}{DyEf7!$R-`W1$noH zz6}v4fwLJBSby8rO5-q>3z&lgW5dsw$sc8eys3*9GUaCFbZn`ZQRf!it=2;a0SyhH z$Z^pIafSL~;Du8dh!9vdaB5sz492OvNSK(wT3A>S#zW}xv=gn^a=+QKO?HX;b{NTs z-TPP|i$s{R?6($aqil$42=ig*GG$>B<RQatFqd$-x0*GYjrg-cEEe$&flXshF+Mh5Tq_LhCs6iqU}}KdtgT#5U^?9 zjDgon2r$o=P2-T0r0ig9gcKjWCCtpb39+NiDECb`C#^nF2%iwSi8QXCS5+cAk`o(D zwa2&|cV#Yfx+t}qL5FRpUB0Kb<4i;(#~VZ}dV_N)I!L~e-$T0R4qlUlT_W7D`yeP}|^+Pv5A$9jko7EHaRVoV>&WBfn zdR8fZgM*O_1^m{>=9-0i?QB5-wiHBf4=cxMI^C-dj291U5ZOn;D%wg6U+2ILfug0! z3xcxtpUn)}5iWzfyyC=x-FaEvxL&=6}5*+I2?CExa6#<2s}9zZ!6#>eU2 zFPyi{;1@dcRHqASE+obl@3rJEf1lZBWrQb^HduafG}4 z&UNrY=YC5EKIVb4Gk~$(V&IdSwMRX;Jv`4hcvM0-6z{&fP0K9+Cyj0?o>@@)dQo#O&pp0dg=JPdT;S-H>q+Y(`S9Ls8w^p zwm{dC;+J2#&*4~(>z(QFYuXX7grzanA0$hYLwn__KK&9Og+13~9?Bh)14y56TE|(T zJ^5N=AU`*aU{d91y8Y_#DwtKVR27)gR)&((X6e5WE`Skn+D9|gJ{a(20Jg)u~$5{XD#3Gw6yg-ab(dt)+Jb7%JnJ78o7EOE`m;!)<29$xk(*BRZiY zQ!pMm?V*3HDb}WK;`m}{^iNL7{6sI_e&9_j@;9hapTUd%rfQd-(-b{NsZw)l$%hMP zqrw8PRGKB^PlaD8vIza@c~(gJ+I4;z`^9QmMSwGCc1&jOVq?&>Q$cl zWKQZVHpeJBg6bt>alYvN{fQ{)V`F{_N|#K#cF=E5#oo-6IyoRd6;@BsKO6)ZoJ3lj z&Jb_~bwJ7itc?>Bt5gAf;^q)&(P zrLT_73%08YJ;Z-`Jr0;vA8k3N-d)5XBf|iZ4I|`(Z1Wzu5nG|*kOuqSgF^uisX3@M zh7GLUetL($J*)3{1S6R0nZN#n#L>?#zjyMR@GFA!-wbE@pSgpxt&_2l!Z)wPN&kBe z)IVerNos$!luj_a^&~h5@hk(uQG>+HttA8+l}%L4p!N&%6%eVpv=H`w)Dh;5g$Zq} zxj5r*Emz|=XH;o%cTBa(m$NdMH(gDfuRCA1{H^c#)pLcgy1X?rMkoSWxFWh;bMLwN ze9w1%-~Dmvvr-MR8mWcHb3Qa6;Z}!w28gDimx{aHCy|q6CbRs;NhKULqHEoBj`k2N z)OgrqeTNjufeAd%0T_JUxERyI*J75P_~Q+%?t(oPdeyxS-O6EVtnQPc=i78o&#j22 z7r)5uSv%!7_98dwfeqb7g3CUQvmHdwYxi5>kI?|f`n&8@sj!Q8yiD{RO2$XSx({SH ze8@$FqSvxu7%aZ|8)i8El^Ym1bkxSv+Bm6s1n&atMW|TZ31xZUhKr%_8E|ulqmX|a@EHo=pcX7#i4qzo{cPszMPzwI zpf>S46Pg5WGN9(N3W^kvFGeW`kW9O)mo|!h=95b_(XG#c9?=Y+fvpk;Ymo@P9SoN^`{g(~5qfS1(=Fe(0 zE|+(hG?sVK!OBZi^v?coE|+o1a!r;Trw=@2uBUGZ`$%i$UU;;;oeE*=;+ATu&JD+9 z{WG@;K}R>S{e0*MIPlE+$DjK$Ool8SR4EO?hr;NZz0_!qP^NJGp!bw`*oeKlAefue z)WJ}H+pA%-)cIQo?FB{xNEbs*u>s(NRF=)$@HQ^QlOOL6=CSZ35FpDhrI@p~lza>J zxa=&R)d$6{l~5v4B1Gn3Z&P4I`tYYO1q}EyNdk5PocF!ZN2JJFSfQ}&(y z<^G&o88))whMkyH#}xxYMyR&FuQeS=0rrxx6pOTF!6$M-C|q2&5!mMY6g^ca>k)U} zsSSeyipD*RLfLrKoJ!lg%p|D^Q1^+#cF8|&t6%?EF-9;f-yb!g(y{DOuLg_nilrsW zb<2AiSqH*r{2}ysBnCy%sAlfmOBD|C&eA75B44&CqB`3WUov;0EU( zt^=Cc6Xc2E>ii`Pc@$ZIEx-EnkNpo`r^^$=djfZJW02&%pW;L6#LioOkMiF34cAaR z{#vquHi8|n-&-$3Yt2lB)`3S8mDFMz6;W);Ld{ne6mL z%63%P!T!qBwZ9DQoY$-K#X@)c zKDTb2KwZ)3d;d!CNd0Mf<10HYDkRG>8FwL!@OF_HH;0HrS_VBGH7NMsNx6z0STu9)SRWSVCds7<^Pn*1$Q+|LXB{NUG^Q6(41^wdsy$HU^v=|r|xvXbHr_=p(4gddUs zvCCSC^(QXOxtX+xt{DF9LOHw(C&2c=7J_`9r_25Kbga7=f05@y}G~#(}rckv0g5wwUy0daNO$Aoa(AU zSv;B>=tS~(t5p7_*+rHqP)8xsDzmSDI+eu?>V$`FwIp1e_yJ1WQ7$eVbyM%^<1gxzsX2a&>U@zWnNBJp+-4f3Rdz;R zN!Y8Xfp;5$@WegF#66~_Zfu^v3+jwFk4Zngw3UlgrZCn4GGEUK&L`ETVn7jIB} zODSWtDAQi7S6e+8HTfBxqd~Rtw1>^O;k69QMI}Xb=(5kgmPpp+D&Ye?OYyAD1 zD^laQG(^nyPl(t0?_`^)_>?5p83kVu|6E+TiYKL${FcShe;1bjOJ>TyBuD@;VMbOa zrhiC`qExhOk;PFy$uvCB8)A3kePK{i0DlHSg`rV^2}#MICR z8w=@2kMe`19eTcl*d`ntC0sF&CRS^3BTI6eiK+5xypPHdE2>8D+g!Fjc(T!ItW%ah z0}i9UQAB6OG9hem`Jw%5GPN6k3fg2iaP+|j4ZdcV}!mf?N(8L)zf|1 zq>xeM8~>jXTvj;o@QE#CV>4~sRa2&>k~#7I6l$V^?jBW5J-k9xwqSr-8|8BQ75jX6 z`NdPshK<1{CCa_q3i76=MT@b8AaTw~^yJJJR?weZ>j=`7Sc}E4Eg1iWgE{SqYO9AA z>Hx{PTsIihBYS<*F`0sa6RODmF@N)od8R0ts=oO^Exv^xa|35#{e`q980i**oYylo zP07$*8GSUrnE-y-is{}IUtdh}RK>8Lj2OOJ6Z z$*6D4(dV~?im~#K0ICXm+q_oGJmvfc+%?gh5O=E)tyQ?-may^xy!;)(N~s$1c4N#c z0ts$j(!n+963|N)BgjTN|GyU%jdNHJX;2pdI0AZprGFc#IecB_<5RxKo`KfI4}1uE z@%V+e7K#2qZ1hV(`HeMqeXg&n2-($FHGw)~Zefv^srI+S7t!YP2#%%%t-NbNy&X^` zx&Z%(j61ORXAO(u2qBZv$DURKFQ$x#DRe~4Y7OMm9ww-MsYOW6Q~5Qq(BX}Dct()* zXB2<{zsCSJ7xq2yo%rye6yFn<%Pz9?faF%#I3{#n;;9qILOZy159pyau=AFXjYoJu zxz!#q!#g77C%k%=AM)*RH7;qVi@G_W`Ad0j^}_PPEdN{<*H40AQ@cMI0(DQ7(h87B z%~~UttOqylDdtbw`T4V>s5SoMhHX6e5Tbv>JWr;&S)=Y2l$&dD8B*ma3jPt(MNV{4 z;uqo^dYQaFbrl%2jsn0WEWIF+UO{*(w{fSCWjkMFt2kx~H?!!(9qG6JF5dh@Vf%v! zntcw5-t4vXhi}adO!u&oXTZ)a?Pve*7l@trA}q?1X3g@GBtTQ_6Os#hpVhSH#&v`BeQXFD zkdPwDu)`c2pdeK_eSHWPR-uF_%k%4KaioM*uB@@MLh->Y2zOMn-wADEY;l;Mh|2+5 zd~w#~L(3<`$Q%P%=fJ8Y{#od{LlL}>mM069_;&g zJfVRQT6UG80018V8WusD<5-Y)9>7IcBJXO4RC0LGnE4(JA-^B#-vFKMaA1zm$w8jw zrN-BNBFH)|edZ4_v#UYLOOC&zcGKw}fmhiJgI77o3C16bML!-xFIkaN^bqb3#HkCo zDTg?>n~YjHd}$YX3x=@W53$isX6BFAMFKq2vTr9-AVGW6#C?hId6(~o`{z)8t9U!0 zx0UQvde>GqmtRwTPf^r2v0{o~X-zH`^3A(qJ6*vNXG@c1&VmKZR}?Q>RneCWh@Cy6 zj7Zq#Noq^IY%TAzp9ZQr(%(;uLZzsy6E9CQHVSvwRq(bXJWYMDZ0YiRg*sK4sBL(cnNPHW2L=JUt1gq&5Jlj0?~?p zjd%?$n+B&)LS7IGx64p~?lms@`INt9XV-h7VvUGvpZ{^#E=`i5!A&cY0#CvJjHXG9jdgOn=F`ncAj@ zQ$ihtf-VN@NlPYR2t^t;+eGNN>QYkzx?gH%IFe>D*KO^zhHyQrcVSR_lBkp3g*0i< z*gb{cSPVZx%`U%9o>)mw6hS%?>{3~G8x%%w?+N#)lH zy}I(d&h9BS6KQ)3ic;^@If%{&_pU2Bdzm=mA~D(@$CKNQxJWb5V56QYhtLZB~BC@^t}R&^kr4){?UTV3n0a4MKoN7*RQBCZ7dCJEM zavl*g?p+D$EKp5zl3Sf>YSw89noY)Zd^70bmS0|7Yym?DZMko?i8IWwe`wC!(t$D! zb5Af=!M5>o`ZRf9__GflpWLn{Men|V&)nnsx+1+hfpJrQ?W$xBTQ+tJM6k;mxG)-J z{T{=6=$C{;^`K}wz5dxf)Rp9cbMQx&tPH(wWmBH=(a?7=i8#t@RX%azNU&cK(3b8( zXHf)9mc$mM6U0pgQh4(#w_e{giQN^GQ``WpGk zd3%W8H)g~hj<0Y?9QM}mPxQhQT9qwBX$Iu&FPtLpNK=F4YBJ?rUrAYrGcJiSNgdRf z1SW{Cr_@2zJGoEm1dcQ}$^^Q!jCRSCU3P_x%K-lD4i{b9mizUoNf;s^Y>dA1L<3Z!rWMJ_cJOpO^q#vn^8)#atF=nEC zzQKBziic1BYfjsu-lVZ-vW86>DF&0Jyi`3ji~~$H13K&)3|3}B^3oa@2qw+MuUFS+ z6jgYK$MJP2<*mG^2#?F6rl7n`zaKsYk2|kN_#b!jCcQll>Qc3-9;j>qHPd-zkfo!n}XA{f@G?1KL#tN&UyiO%Xt!8oA5+U7{OFX8Uh&@j2R>Y~S zsV@_kQCri_bDKWqpf|y62jo>x7`d9|#(s}C9oMxCRijxuyo)xUM>fZ&UY&*vj`y1j zjc!-=8`X9rf&6wJXC%X&N z4EM|}&dF|^BBR)2^0dLVL3+cPI9^Q19<0?%KF9N>vLvo9IVvT;UB+k|;4 zjDKUO=TwT4jZrM?Ww#q(N#-lr{hSn5>x`F@h%sdm`v}Bt4L--R0%5gcT=hxvCPWE7 zVa8lW-NAJ9*~Jmbdw{5Vy{&`9%y#}j=1b0Ydug_W&T&=VWc^FP)Rv~aza>k3n9akQ z!TnTio*PX*&I-%1s_MatS^mWj9o#=eWcx$A?C8ab z$}=X<#@Xj9mG>P$^~%TfR=@Nr&WaBv8LYq5zA27t=@Wn6H>lF?@JBLk&Id>b*WD2k zQ@^x)IYqhGo9)+ivMNj6NZxnN3%ycZL zCXv=8ZEh0UD7~FA)L*UFgEpbK*1&-kkDHLPK1*0R^ z@vWSHu8Z9I2H)3x|9xowJC^nT;@kfx&|JQ6V(vEr*99E!KjG&7-Hp$m>~#7+aC3G4 zk((R-QzQ*$b@rQ_>ykV7Dth)71{OAkS@t&e+SVqJ^+xb&n2@4E){*h1*NRY z{{O-B{{*Y|Pp1E$$a?<|rc?j_WjdD&IIhUI^BDb>TK<BlQvtm8H^^a^0azs4v{IZq_>BzZ*hF zj_MORXy6}rHR*^KlLD}>rCqxpPo|~m_4IsGoCPTTBzZFZ{lq1ChKv2GNSusdjo=Pp z58tvpk z1^9ny|7yN!y=&bum--sCXvWki^=Mw=Yw{F-Ra8Kj&dL@rpFD!^lv}y0>Q#av&z`8J zx2BFY1%9o=q>c~91&-@gE%w&$YM5+3YMxY^f-#3kI*+rG6*xx)OAc{B#JnoVuP23% z4}HxD6G4IB*{H|n$gX(n%#S}_52q3yG!k(lC?|*#890A$=5a{$q-HN|sJH=0=yL^u z#)G>6R)Z*OIl{feR|0A34e!w?KCa!MCjWMf^jN+5EwF`9vyXtBEG6U(MI)A^;*$PR zE<6b%uVpDO3wGv9lB`Yq@(0AsP>5w12o1n?c}@E}5)f+;dx! zaikb7ZJL_BN)NJp@7R@4|9&5jDtUDJK(dEhLST4$PNclZy#^UtUL^Sgh$2FM>jzb`oYYt%jcyQKX29fJP_Vfg>> zMRvB6=#z8@jH1%0G~BJ0ugt;Jl~JLo!A)C`x>3;7(Cqo_@6Z4*~? zq|~Bc9;Wz(l;Md6;*t>{7E^{Nyxa{kUn?CnqDn+0M;9qoxV9eWE4yb2p9o#s3*?Y_ z%vgwIl94Fl7DBUv(Znx3u`x@qF#d9GeFl}jn7sUu@_Ga>lA!yM1au0+V2mRonUsR! zLBPK(VnjF)1C0VH&j?YF45oW9bm5}qW>bqnhm~NH5 zaY{m&ei*5u3L?=Mj3fQboB@+1gTBQCp(bZ}p5#rq3j0Ey$wR z&Ev1^n5}NHo_4PeYsPUuAKID4S!L!CkEB+X0B~n)ijt`1(wHS5Q4Y}%IUi6_?k31z zq3{7PFlrgWZ|$>S^&cO?_LjafD3W>}|E^gb>lZYPi0-G5y_xQ=N8A*eKCsEG(2xTB zdp>m(fNb!l5T^yJAY%m9P-dJ^WOHS}ebJbK;7!Mq3mTmnZGS#_%Gub? zifjR}Ig`EgY)K)0;jU2I zu<$(56Xn`N){}FaT3G!FY$&^<=ZjemhyhrDqRi#HTaR3WSjHG#a6`-}d_+q`^_U@-NRF(N4i;*K>}5F-SY>t1pz&!Aud4l9&%Iwh4k z2%1&~b$YWcTiC>981ldC7s#arRzsBinSAZ8)i6{)@H z6h*6RwTFgwcoK|*URt^OB6>-@Fi3%%<;8TkYr0UG8RhK69n>Z&^!OZ3MMSLv3m9qW zL#E@0=rzU+8WEf}R>$cQ^4jU%vzM$&u+X@FrXhH^ag$ZDW0?fnrh?yl_xqj#D`K#l zpufqDxc>~vZA|b8xp)yn)pb1$NQ$B}TVT8fKIjiG>XM5pWH6uQBglBiGeb_gsfWA; zfeZ&SD#hB3Zawa5sZvTw);+}zl2>&_YY2MoO8bYz_%#+yx2vw_%8YcE(RwIGn~j991~DT)lCs0_M)x0eqCKsVhsC8zIqPh)AjI>&#>s38fm0rT&aN zjV0M#M%1-DSrQ@>DHkCknsmu^vqZKQm0eAiYd2l){YLaP-<^j0KhHDI49|0Z?|a_w zeBXE8_nh;dcek=-x+%Uh#e~R{t(OBL^?3d9w4j-O1tl(-0zsbpHzGdm(@UC1$oyFI zsE_C1(==(X%v%`0*NhsLa}8sX6hb%lh)w?S8v>QgKeZX&Cs9r~?_RF2;l z_u?jGj+MoDJ||K1v$q@;gl9VT{Pd_-VVh9g=gRT^c+Q?6{piKWx*vC39N8~2SCQg- zHffivZnD2@9Zm1fjOJl-P3m6Xs?L6#_}zPtu|K?P$sw^z)tJWTbZqFD+x}d^ws5;F z@}k9oh!Y>sv}VM_)KKN)y%}vHjv;cI)aJLfy;^GB+YS|#osF9e8tJlWiqOjDz~Aq8 zlRjhITk&>Jq;`Q@W5GGggt$Q4!+wH76>ksP3%vH?+H%5XqpegJcLnwHP$42(amk%; zlW^fzl`#@|^(wO5{;?RNEDUN; z$>A2K$c<0iH_VD#288lbPFv}`-Zdg3Kk`RF(V~|&$5~~Kb_GOkgmWf${6{gLye4W; zT!L0q$m3#@n8a68uhV)`1MKrHH``__jaaPfrg_4)l$%`#7iUxSi@e6bNrG z%zJ;rV@S4Dz~Ph5yG#dyiK4vAgUU|zTjKhaL7I0?P)~_Y|3X@F*BE$vow7s~Pq8GI z#+jH)k)1TXjYOVwKOdD7E7kBsmV5M+vOVJ!g6mG(z6d(d)j*1{M^hSjNtcVP1=WaA z+PP#WRiEu!M6XB)+no#djO#4stRu4R-pEHNl+m8{pXKIj;8wO;EWIk=aw;a5W^bP5 zV-?nT{;sH*dQwr8jp{gd$}HyNo{5|@*6OF_Tc4<9%Gmj*8qAr86jtA;?x{1@2~Xy4 z%nThx&5nO&^VZE3dkpssnbkGuK;6Ta(8Sr$mpIcg2DL|Y${g)01ckXRJx*@Hpc`k| z&`wyXkZ0!Fms0B+HLSytaaVOD{CEq=4!?601{qGhH<=6TWG}ZIhLN;zt{2CfPKC=* zTw5E6Pj;bxqh)i?cLb@5Ju+^Qk&ofm4Ra3Qsn)FHv0p%y>rEvZ{aqgyNHCI&99I70 zatXFA_OG|MGu=O(4DQQN3a8%1RNMSYc2CPb{bpJ*-R}*NR8Vs8!~cvrigOir%Tx=x zCTiwvXbv+}kCUF9aS|q<-PkWelpragG$^l&j!6x;$6J&=-=yf4m0cQWP$c?sKAHEv zUHYG(>>J3X)UQ9lIrrNdoc-ZmtZjs67 zG~tcK^G7PEHjTZP9XVx0%4#N4!({#KPExaS_LtMR2>GJ5okfT`P8W@YD{Tvv^ZA#L z&Uicjlzmz+^+zRHn!k0V!_*SBrVUpSCK{BFEyzx_pUI+R{FIcYS9q9YB(`hw(}CR+ z@de6k9mjf;>&AkP_w@a3li14sTZm#8M|G8uPj&jBmUp1NPRNln>fB3{k|Mq)sJh_A zhbhKwzLOs8$U8&XSC@>=8@(JAY9Iu1v$qr|w`44|aA5rcCmRE6?RL%=haBVQx@2#5 znWrQzTDZezNERW#cs6)8kn$LkhGk>{!DCJkD0o8m(P@aUsVvQ&(?XN zt|~)&?qK(TyM>0FTh8CtYH@5%cw1-D{Ja{G+ytFqho}4eT zA{IV+n`6O8eO6ucF6Y4quO;5M-;n5U6CBejw}M;h$lPUnWs*ED!H1w=t|<={t6aXC&^;uRq^*T~)xV?N>*#Yy+IJhIgS~4o*NM0v=enuM{>C%Vhn_W4|oq-W90r(vF z?;~9=0^SQpAiCquV|>h;kV(%1K{Mq)l$9n>_t4EPO-(Hdo#`bnv8*V-P;nCwBBYC2skq|Lump%Q05q5bRz0ilH()0N#)B2c(cKeExWG~= zM%rCgG-r2L+<78PnlyuMA6U`8rek4svFI-7mqNc-dw{FW#O7a2Mi0q?D6Zw6a;@&P z=|#Zjl~;oHHD>_zwTq%m^$m|=3=u>>B9zdTb*az*2;-#y{RHd)Fc>+MALzVa2}jMX z0R}UGl=n5sAt4y77I29bR~rL-lS3nc|9-bMD_2erdmg8;?@Pj5sA_p3_P-wnnvn)< zZ`;p6E(2t(k8JAcm$Xb>%S|I-wjJx=DK^jGVh011~If70Bs)l z>|Uh;-{eqDBnvQ0GiapOqiz7o(x1fi<%_F@94d}ln`!9hg!3Z0<2{)xTv{4F`Vi>S zYW&d7!FiMgeB~Kyu>7cH(K)WxJLfXD2fsB7Jj;tmyC;dg$tL>752@;r)H&dl z-wfR1^q}5qA&2(cuu%BxTS6ZQRuYy^R%dQ+=z;AZAAV{*e8{=Vtd4Joc6#U`&Y51v`ROQ;NJrZ!MUd+d5-Fyw86!l7Ag zK)6uye}J>N<)CRaKnb&{EF{p!CEq61fGQ5%p$=jvfgAk0FDE+o+x_ZLEOhf4h(+99 z3;W%zY)~Q41>m3%b6^sXrSAV;4i1Gw*D-?d!Ll{rjH?=30)6|wNT#!GoP+nZ6Y}|=f8nhCa*vPaxMGW m&>#WGk84}Q28@c+`C!Pv0=Wrz9n(iX%CHvT!XRJJ|M~~EU7ouD diff --git a/lib/commons-httpclient-3.1.jar b/lib/commons-httpclient-3.1.jar deleted file mode 100644 index 7c59774aed4f5dd08778489aaad565690ff7c132..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 305001 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
    {@^= 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�K6;V=*aS?57vP%s-9y`tWD7Yhw-3N^9ART3Y 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 diff --git a/lib/jweather-0.2.5.jar b/lib/jweather-0.2.5.jar deleted file mode 100644 index 67baaafdab267be4066658fe993ebe9779ff14f0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 44542 zcmb4p1CS;`wr<D&U_1QO8$0_ z{w-+#6DBXLAT1%Ts>UEMAs^R+5X6Kg@l4?x&MQI!kLB_cR1Z%|?n8UJCD{QUZBdu$ zo3Z7!>8w(yy?p63gj# z?I@UW3DfW?Y^?)y&huCOw;IRuM!htVsQ+FT(0?uK?@Ipr0Q+0BGj;h72*`gSoX!3N z2+JBO-msGtfX@ry!bRnw-01VD|EfJpzY-u-b4LKP7bEfScjD9QpYYwIT3 z*uRhX0W-;&8(Jx3iQfCVE2;ftLsA}jU%$n=#lKbNJ#+a?n5PItR$p3(&y4OE1BN_O z9(5r#mV!J49|O)*yH8;!J!yN^RkY7=P2FB6B1#tksiFwRMEy7jL_qCPy$cjM4_wd8YkOzXX zvP_h9CY$Y|@6c}a$O<-&d3N(p3+c>OEt(?^al=@99T5>nl}()!aMkOo5efH6Iu@6u zB`s9(v_#J1c4=D|v7Hr;ef5J-x*Wt+M^-QjRSop4&hum#YG&(+Lg5TPVnmBmiTEID z_{H>jB;oL&GMrpP4N*)6+VsU+ygzUf+bG>s4@UaMQ&YJ!k3Z}(EPHq?_{HTfloQ4% z9zrupj?#lLaWH-@%|*(x>=g!)!%vFNrXwrUXKh~1A`-pOZaA8@O?X>Wt59^efablh^K_Tma{CHK zXIrRtz@+WQieBkRbZ)=*KIfo!y7<6x_ipB}1NnTI**F{B6%}Gh z&;TAMP(;P%M@$MKUz6nxW+T0dCk*s06bG&SWpf|%&C!Me1Xas@W)Pm z0^I>fsOll6g?*d@^OBwftau_^OCnWKEK4?UtSI?fI7SdAalj{-eFRXPA(Co@5dw4J z8`S;71+TRkEY-WC5DdvL$yf;;$An?Ec z>Woq{;(vhx0m1(@cl`gwY&8FA)c>*^bz4nTNi;u*#7na-40wp*6^)uuA!1Ur7KkAl zMh)CwFeB^F<7OzS6kXmNsOw*ael4w(PV3HZ4TK-cx!Y?$s)xaooUf;5Hs3c-1f0#E zU!w)TA(SMxM39>>6pUvEM$_9Iz%}9ZCJ#{cIF%ZH{#+RfBEW3vD40$R&3ai9!Dzcj z^V%3{3`MWb)LJ~i2hGE7pJW0&>B1SS3)(m$LzzoD>16C2srM}>?tujN6sgrSq(Bi0 zl(V2!b{Q$&w%+Ra$cEOglH{RI_O7ZAsIt#rOQSwxIYrl=RFY39WmYqrq<)5(U{!YJ zZl1cHvut8Kwk~<}lCHBOcfN6JPnF}hRattf+}S1Fe36B&ClLFi#V0S=NTW9xrPKG! zSl+kH#kn0TLxtjsX?FCEGNqyTKFjaLNMRU6>VB>z1dc4uO|i zP*V6@!=D}(E-EZFwSMTIj}SU!GTH4qZ`LzEbqlfTR_Q?s6l8Em$+jm9@IQt)ut>l``2 z2%cXH3AUW=qb5XPpSo+b5?}PJ z5Jy2~E;$5lM~HiMApBnFk!xaoAOs!coj=z$u~1lzzVvP$ury&aE6WZ1#OUZ&?hAeG28$+pbCenqc#ych=g18$90?35;ry9jDk^C+i{>Vi0MBv{84Tl~bI>jr}FC?ESg@eg3IlcaHzIExGf70aQKk&c_r> zz=?q=3}T7_tCd_&Wx8joJTfp^m@N(tD;O<<0jo`Cq&!@hDGnd4gAuJwXXuy-3re6B zLGYzDVT2uhM5j?-?tE}YP(2FqW#M9s>d)3yKMXqQXu3DT`Be8k&o0{Z(NgJfaMLWg zk>`8oi`cr4Ju?jqWGA>NDyoTT_wi@3jn$4>R{-;E$e1FYGFYA#Sbno)@Bx38w9?6Y0gyP|Gxd%_st=o6{ut z=EBhk>=s~phu^L{VlsLQa4{lKYiHPyBHo9~xaX9G3%S|86`OXynvd(=?ntTW-r>lZ zmgjU}YWKmW$!LCu&3V12V#s_rV#p9or^XrQfNjKlE)hG)jB!9m0cagJf-?>oPKI3B z*T0VN%7=gMWI7(;3Nj`^5h*{96%(zQNM_-yY*m@eY*^WrqAHfyK;jc7uSFOt(n$~K z-DWn`vCL5#D9|X1MN*I;@`&vf)625BD#kdcj;vHou;^w)S(0F5k5WR5rgfx8xjqxq zs#k=C9YqyfSnHGAq+^eQIf(Z%5mgjE}Ca)Ha#A(IOV4~_KZd}Q z+x=4~L+aN$c!8XcxM&fT%#TtXm}Us?;zk}#sx?-LNho2= z%rjFmUQAaMHy&16@25C6#Hh*S4~b*>$G3)18+{xi5KG;l*8N#~r7KL`?>62Nb>YH& z!{X-fctniwGddS})hPtF^yOZ@9w;yx{Zf>6+%9TcnUd${P_LCJjdV!NLgXYA(^zoS z2a75tvhdxoyIWzOhRBJPyTt!2-~nBLO|mfiCTQ{LDsSNtRk1utnOharLY4H4v}44XSFagf!yNPoze8)$k}b0S%4NPlnc4Y8Ok^-J)rsO{}Tcf(7&1n4^j~i^lQq zAS`o&SneQnTIezgd74;DqgI{fR2VqMFJ-X172Sd_9(uw#ooNJ^TTExKp zU?yan9)ygv&CP~bAMvs^ex(s@ZdHN}UCjb)MU7<#uwK#naB@PJF?T6Mys_wCO}**CQWX*5e)9$7$CH zyU@~`-G|^J8;o_(3d_>koXV4IcS{~-#%OccaID>$*yq4#Yib8YPz8Ze5e=Ii$YI$W z-nYYeu5ZUgNFW^3t}-I6N}O>r6dAGHq#P93t%|T4Sr5P{9TnlKo&ThzIzX2)*Q>bN zOuGZpmu}rxXXw@$3HE^Z|0T^hfcoK?6SH~%&q6SOYsweHId3#=FPYEJ;%}x5Gs9|f z_HzQ4h@o41gw!M1F63#$+S|w^{i`FY2@HGAJ#tQj>F@( zj}~~44ja->EFX9RZNIerk+#-4S5ll(YmP?(*{-oOpoF z`~8Xws1Y@GsVPOJ8imc#uWPO$yPy@fFX1M51{ZdvGW0jbRz2S+G!I#{ne(uiH|>qC z`^?!?O&obn057J&kq!x#_!if5Ib#%~In{EV8_71t@FL_gUI!Kx6dlJ4dtx&SX60k8 z7nGot10{*{IDf1X*Ln9;B;QasO@u(BQB|e+V};x)k!{5`gC9>un0y2>{h+_}d>vUY z@4QgW&1QYamR5pX;*?RnF7Fggkf31UWuMcvzw6g;olfAtdo0CkraW>us7C% zflh}AuzD-%!FUNrfa)n`6=AI7=tImT$H(yU%+c1jPj#_6CCA6}@=Vg+wrM3~?u*Yn zVs7dlz7(|c+p$V*%Q(6+^9BE zu!mh{_ZFEolJ-~OAnjtSN|yO@@Otkk;HW|EGb!N$nMb_Bw;Sao)*$A2;x6t=SacbNFYPR zzBJ^D=M)YhaGa?S6Y5|h(bgmJP*FU=2+)xo*CIEijjt!94|RNvI%}aK+AqZf7|EPO z<`;Y$9G72}iVg#Rx4dp#etS3EX!eH?r^p4!wIcQqk{o+%n zkLDk^YA$_X*97fy%yK_`np2}RjVr~9r>sik+>kOAHh5 z3iMYT`diHg-`jT(f8w37>3$sT%lyVT$VHyLNVcr7yX!aAIhW=v=@oOPDl$_b!o=V& zF!5W#hfn0C1w705i>Yy%vj9(=-kPo_!l6mB4WCH6edT2HjNFV>7SoC+5%AO_?NW1R zhNNuo42J}Vj9yYbiZuZ)BE8ZZm^5hxh9tf|(*XzvLsB$DST!SB`o#>-)UysX9s3eS zi4)g;(Y^@A88)()+4w4oEpZ5O3ZoZ?jhPi#ebRPUz z1G@2qQvZ4*sqwb~Jz`aeeC^;ej#Z(VoZ{12Fcp}?>$0luEp%7G#lDc1JJRd!NAq9& z4Q}>t6c(!rY4B=N??{$}xvISPgMcMJK+Kwgll8c>3wTLTQON_hmPMFj1u|C^mt^~7 z*7ZHk5A)L>>2by6$tD5DXwnBn2VltuWJ|_a8iru&j&-IjJgR%|Dp8BXNvd7_!Q3gC zsPFWs?;7FM?Fv{!Nii~VjRztU?~(JsMlR&coiOLORu=ui_0V-KOje4_Z<55Mb^T-3 zUgP$6iT01_<5U~I<`LLiaxrm8MMXoWSj?TFSoo9@ZO~ZUd!~2DI%Yd<*Ckr*jI+pZ zQA{lpmlcoVhE|_R9`;XvzbrYiUY3*Xm=8frVB|dCMQ=H&LxUl)i7PR)$gv7OF+Uw(^;aGz=8vfb>#-eU(!$Z;nG99<4U zMaMgks{zJ-7@xHP?-K4k7#^v-F#pBpD8eXTCBx@_#K_4iPoLY$IY@Lj!VkIA;MEX; za;dlcebl#I%)?-VM8s`k!VfP6LZWZd>FmzI!yhB8I2}5UB+mG;tfz>@U!XEQi1e+= zB{r{)GJC6Xx^6fy7bnKhv*tp77`lCB^DFcc!6wPPoMgf4b)1Cr)WCvO8fI99Y*I_$ zZe*8VYBJ@b{4pUzb}*1sz|o|>_<-+F4TWB8fr*!4K=;cA0&Xcm2foKaM0A96D}qTX zkTs;HJrnoMjR@7&eH}1ff65aOb~8K(mux}WiV$`aKM0#HK&Ir)LE;|*4d#;dPp?5>Xh2) z8i6-Mw0VJ3XUs#zgzsVDUD5acJIEm8je-49y`dMItL|9V1;4~<8ZP_WR?GUavSEF+ zK&ulSL#9o)v|L7B8T{sV-6QpO=rh=p#v1CbUqR2!p#9%E?3M4YOJAz+p1#nXv!ri= zFQWQ39$WhsLwnuUp7>uq@rgb0M-9)Q1wG4d-g!vt?~-0;W*fSs&Cl44&ue&3U(jFG zieEbqMl-E#6t?!UhBuuy-hGNsy<$(j*`wRv=QabuQuM+p-;WiPrWIF z+wrePz*2&Vzqi+$ds@PJE}E`B(bwJ)*50o-p9)1S>}$5R5yhVhSzmX2N1Za0%eLO( z0k>o}e;FvtC(Haag$Wd2ZA$0_PVeX01Jd{HMaC)Wg|66c4MhG9 zNG}f^!SF1Jz(Dm<<`!ZK()@%*QS)7pt| zNw(Q&6(NqSx^!>;{~n^?Pp7%6`5S3`K>-4y`OhH=QF}XQ7ehN2=YNGBS6zJ$j+ccX&{n>n>?DZQW(&RARdMM*5OjR_L_WR9H|q#5=hWA!x8~ zEUOQftGi0ho`zk|NM9OD`xDL$bE2FUdvvMm5zq4h;Y*_uEn4*;W>AI#nvMQY+F}&?SxX_H69&+-tO_SEhaR zgp++aG8BYWE7KoN5(5fOU{4?a0AjvEV4@7Q(ho2bm9+ai(M636$cQ!REl%HL$6e;i zQ(GRhqYKENj*6`yz{^dcIJcHgKd<}qTgDq6 zpTNr-?d;k(<29n=<33Ff#Zj-^($BcT=}kuKoPKVM7rUxgRXk-M&_L|(NLNOCXtTmi zi@$V9*MWqPJd-c0F^df961a(qyRA8f9h%9@wfg&D25i zl6al+i${J^M2_T)&hJoct?NiPM4vvn2d|1(==|*vSd(3>Qk+{q>RK> z1^+a;%X2Ysgf_1zNp@&S2qK?JGR|r~FT)W?q|uS(_HhX=7>P(G# z8G>+*R7J^?Q_yHE60L}otzf61j`JYCIX+z0radpA6G(}AR>90u@N={9p%1;I zuNX!wVd-UG&Msx^rDwNdjJ&(bzB1rECmO!P&&DTUz*lfZ*~vI>OS^cfeZURQ9(6B^ z)5?B-$z8e+b0XTATua!yf9&{mBWqth7U}a1AuDNj2)W>Vb|mHZtEuRM;QUQ*9I*sZ zP0;*)u%ZO+NWqV+=O`F&BED2cn&Akum{pB2(1|+*lS85S1MppgMXBaT>?f10!CCp< zLG&=(?l&5}B9OmMIdp<-NxBlrF=m4Uu8qoQ7#mx=dr2Q%C~>0a7GYPg2;~ZWcvRtASoZY6a0&t0R2gf%VNGTwZ*jg3)6l z7He}e^Lvx!E-I$%kV2GKA+4m#uVK?A26S%R8-9WhcKS=^!qQ-!u1dcp=yQE4&0seN8mQnI zPaj+^*%MRthaRcs=e zvQEHdj-B;z{Ndhi$U%`n?tw@D^NeA;BdL~+iSo**iadCXkEgY!9?M^5ck5P{%(Mx7sCtfWZh%!f}O#F`R-;?|HNH>qn#D1QVxBmH%^`JJ%vBC#) zP+0+#k>nnzcV-?@9yr?~-RRpA-T2$W-Kg8*-MHJL-I&{w-Gl-{K1e)bK3D=GK4`rG zT4C|X22g~Qy->Z-ck+8#$UAtw;CJ+U(UJDx1|mKnxx~HfKDhfE18tffYT!60VE8Al##Xo zVz)gQNAz6sUPL}gKE$207r)!j$YIY~WI?2-2*rNaeQ*G!06ZfK=Wf6YT(=nBz~qp8 zySNWVZwyz^#t?qHtPg@du^*C8t_Qjw)1ByUIEo-#Z}!XHEolTHv|!W=%!|yvYk;ISr17$yLfRWUX`vYcQbD)mIkNpE@e|4aa)Q|rIVxM!sp2Uy!17p8!z@F5P z_XAiHoED#XYeFM

    3A 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 j|8LPhwIhFt>|Ix$*LVtgOz1Ox&{+RneW-AT; diff --git a/lib/log4j-1.2.16.jar b/lib/log4j-1.2.16.jar deleted file mode 100644 index 3f9d847618bcec9c81f36ad6ee76a0f53816987f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 481534 zcmb5VV{~Z2vNampwrv|bwr$(CZQHhO+fH_DJK1sa_QiYW+%vv=zjxOf{jaM=_oy|i zdd^iXF9i&O0s!&%h3@p_0r;l}1pov!4gqZy_TBYAu0+#<(lvHCHj!W22ZwWap!l&#Ob}e zE;G$ppgFTQsiYDm*#Ktbd(X$0CKa>y;61l)q6EPT(mreKE`*`un@I==;~KWi(-B$q z1z1S_F0`XpPiYY9&H*n{x>5tqa=2Y^%|O_+<%kQh*_?*y03+{rL^*?SfY!NL*CPgL zB6_{>nLR;(60gh1%Z}HPJs{zpaJm2u=OT81f0N`Zci_*KUqU93Awp_#zk@8v?H>m8yHkWx!j8DxwA}NbK75Yz@xtW+csQn~Y#l;^w zPuR57Nz)=17>=3*8}V&m66@%uyVQjrcY1prBfG#;gLU9AW~&YV@xk>8sXb-pmXVLq z`C`Gn_PQ=~k(*Fj1+G)`rsMJT_r$AZE1cloL+kHm6&IQHUtyyzu-R82X_N#(uT(is zkF_a$kzNU-JfLvJmM@xjoHie#Vg1$(h3i=W{y?%}%*?lgzPGMI8JIi1(t++pFv)Mw zJWC|)s1po=h+IFO7B<3z<9CQo82r0RvJ5V94rLH*BocrbrlD=ZAU9ci5jLsHDB)^E zNEJ{^W*rRN)#7(bfq2+dA&(T8-;z7mpIyHecAKJ#ZlfkRL@RJUvkh%bnF^pKk>;c6 zizqtZU0r-#9bWBIXI6n2=#=@xV^MXol)b&Vy~GVzOBfNcZhlOsJ(;ksUAuUS5w;PX zEO|5ewzm2CcHzemc$(P5l#D-5Uz%TWasdw-X$Y?}iVm6c_+PbwHbD8Le!z8g!6j8p zrLHs)X*bAv=3=C8Lo^uan+z;AVQ!7jnVn3G#_Dp;!hAPPZPJ2Fdybc1!dz8*p>ebT z%Ph}Qv)Ph&R$#8$t2XmHlpz(!HNvf#`>Z#uT3Fm?$1Mo#VK&;pNDe6%Lz}Lfeqa37 z3dtH#>F}ZV!*7*R4oY6rDt{)|Lz$AY397bGvBwUW!Jiwp*%sw$ky~@d9t(F&mjZ`K-2n4p2L=Fe zgaH7M|8Kzu`4@=)ANYX(P6UVeH)sO=CqDmSxX|%mQH$`;hSCy3BC<*%+nQQQo2{t6 zFLl3Im(Fis)La*fYjVg(x@?!ZH0LaJ*q6?Mg#(c+6ZHWcTQ2HuJN85+x?Icbp52k8 zh~VI6kGXd__n_}f_@i`Fxk+~}6LN~fY5h#x4yd3qE=emy}CMecj)cZtnP3A$a-ti?AzkwZT zG26Nwv@o!G&);QJj;Xo~HRz7!QmAHr>p#1)Lp0qcqvj*gEDs5cJFH_?{m6WHaGt8d zaC1VeJ6n;`T(v&Mw+WT{|DF`xia$dp9fgAz|4mIOm59^~z}(-Y8yx`N9jM8>N-wU^iA9Xi{RKwd5i3Ezqzw6nlIZ>U2M=zF35BV@F_^s8Tc(6lbbC z86A5t9MXGKVp?Ync+<2;sx0XCc`FDbnv9ekJLf_9iLB8dsp{%jHSf`0hdq^}R*mqH zQ+OEkVxcF|=rnc3DvB)LF`p0FF?Q`7muRUI#Oh@th2nGnRkf?T=n6JH6bc_WIsmKh z@&wpEL4{5dI39D+4^aZ9CR=RgNtX6wIGWM!-||Y&-8J0<=eIxx--)G=it6F*4tRms zyaI;`*rRog1IjakNe?46Rp);x@gZLp@E81 z-PMRWff65F$Q)$uT;>7Y@Ybq&f z1W{GOLOHo)flG2l(%LRj@&}gR>fsnCf)d*%J=Q$Ac6o^cJPO-Ar|Jf2?D)H}<3W+`B4VlrGux1})w>uP4sGz^$JF@CEPk)3;7 z_q2E=Ij05m2@*GEvEa{fgx@}00W4e211jPkJcfkvbMuwE00)9wd++bScj<@H$v4_R zXOZ%kCx#kDKSuON02K_SMM_{jCa6cM2Xi2fy$*fipwy05R@q%dLHmr7%tU?%b9)|? zSRHOfcz5M7za0?)qCk(4$vFf^P61*qfv9i1t8$K#Cpg3GtM}qk)2YG@sMunLe`N?V zUoexhU{Q{FPe4~kRsok%c+w9?ItSFN+?hc1n(M@e`WTML-)(DeRd_S8l+|c?h>yEQ z3;G9f*=IrG@eVzVlZs;-G$H2<8tk7O@N&C!lQBELopwvB)Ps zc*m>1lqqjQe@K+$5-he+&{K~4fVHm*B_=XIUS@XU3g91ivLYMu`7}P~jmG%A_)Oibl9>N}_D5?oGr-VLB1H^*qWl+n9^NZCo#U8OVu0l@n4(%MorvAO8bar5tYcu z%pB}TsFLK(jwlm(w7am)NI_+9smfH^8*g(+kx|7suwYIN%N~~_r*j;6S-O780K8O2 zfOdAgt_z^L9I-q@V5eYh>LsS@#1FrX?x%~G4pm!6KOdb@G5T!XyT=bH+a<~6{ba39 zFVQG6Lt~%~EVn?l#dZ6dfN7)H*_HQN!?2sAw`y75)0TgEwJACFDmmO4+6Dat%x6GA2&+%OKbu5w zgp=-Q!X{+t?vpoqN2+Bsj&f=mH@CkixdNVj`VyO;7-Qha31l(}|^PR~bsbAwj(aXh2BwR61o&~`g)_#E|m>F5IM zEcOU{M=UF*!xcfMUD3#BF-ee_H0iGdZtggtyo|7+6b@>%Lw~!wi=zL$vf}uBW83lm zI5Wpy^&$A_?ey}8eBSZ?@Zsy>8y%{^ZR%rXCQ}bz-5nDj&26tf?iStcU}&rhzU>mb zw$)o}eQyTnYc5L1pyy%?7TYrJHy+)CR5kDfq+N7#&8MC)Gt}diFJ$SqB{$I!SU4lGUlI51G>qC~#K1_C z+kpTzkE;=fe%q+B*Y;7<(42g-%&t^65)nCu!oB8&X|r~Wu~M845xX+TTsLH38vsUk z2d}%)F@Ze;TtYrR{6Tj#hjiLXP^r}7@4j9@%)J-{UE8|@PGH@+k;36je^rR_C~kVi zg4x7_CAf+Y7M(bH=)4|VXqx6N%poQDOlMiTO^Xw#?i$r#asZd&f-A|9urm*si-p@? z4rRaL^k^l38QH9mozYE~UMW%TQ_~>0$GzVwL1%;B4nC-H5m?wT_%nE21-B$cgA#a| z2hP2pM5We@+Xxe!KCBS24&Lh!#gU^EdxxDDX(a`pSSTk4`{#li%obS>naOxgxi?B< zTPu`duc7JyOto_`bEGzrkU$-AYtk1zn%TBf-zFIKnVgT;s~-?rIC8M<;Bu{tfpO=7 zCQ1{gZ=1}g&5f2rfL~2rVqBiLtn8mY4u-(pjo)6_&jd5k01ELwFQMP6yk4;@8spp~ z?oPj{(NVrxBhOg~=PiLXj0#}!2bGJ&bG&O*lsExFff92B{DRt&p@^LR#QDt<-7Odo zs&xrLkO`{nKAYq`X=`g|-MHQR1ki{D-R){aU948fxcs6gK=MBj6ro^!t_Iixp|Qr%mA_x|mBo_J&OL4qpb#3Jv_W5(=0iEOZ|PJxPeJV@gw5p8 z<^Vo6w~xW#8Pa6zd3&Po%g;n`=h_+bnhNn+0y38pxP(Gp$jfD0l==Jh=1CE67fdm3dW8@cwch+_5 z#U%}oPC%`Q72odLm|vEb6?G%bKSmh*ma5C`1&8a?+|>@4Y(BC|e^6|7J03ETiIcG*e{f+r750l$5Z?dxlq=-$Q6yY@Na z_wStj&HnMy6&?VaGpLInT)E;+`r&NC!|c^gR2 zfIpzZ};K`-~8VhHBk^5gKs6a!?&4&C>%0Nps8}{eP04{n5{%x73g-P z3JR7H6@Y3F+mOWvjxX!^U*%({%#5D(h2MR92qLeR(-=aVITn=zIL~1JCNjK>fX_Jp zT~7Yr@eh&VU!}qSvS1qnR})+M|4F0xS98>V-tT{yTicnjSpKh^VE=bc{`amZ|7TbB zb~beOj&}AYj?NY)PQ2qiP=gEz0DHW04)b5*an2OZiU{Csz5Oj6qvGO&8R8#*Y<&;e zw>X>Rjo>dKMSv7bu1DIPBEf5UKZaSK5t^`4XYWV=%LY0pqLW@;n-M$eW;Z&6y02LV!|ULufGe8Tdi*UJqs9!QU5 zD%CdA-4Pj5{j*-32CWPFSI-d=P}=%ZOl@u8?192_qbB%_P_)8&=*YkxCkt%bqo( zU8(LO!u2OI!6S`e>T)0>=*o3GjKf$l(EB^*5yhA*8#xnznGY8ziZEy2yFx?333hu< z5y75khjdZewTy`pniDm9z}*HY9wkQN#r+o@n9jqEyFKIjb$lNEjc@mxy_hdwZx3&8 zZx;u4e3q7@qmz%PgPVgB?C$Ku{WJYh9r{{XS8zabKKh^J;&I;kafLt{{|cJs(lfjk zpuVZ#H}7E|3}v3#^Yny<^hOrZ5^;4bhlnPMfR21%PlS8vidgH|@oQ(CvfcB2$yWkI zNV2qvA=y*ec!Sv?f9>5I8G$JJkyj2044`%aj6fiLJ2jr~{ZpO9U=%W*z{CyyPy%%X zX~Cul!&fsraKlnDw5e!8Es^yANS|T60CfsX0Lf6#Sm=|S3$M|DOkPI(VVTk1IO4!T z4gd{rK@}l!}6BDyYcHShXgX~ev{9UWeB5_N+V6d1{O9PR0qN9ckR>N;D-m`~* zH%yPnL3KQrnaT)?JG;897k0IswVT|owUy*Bxx}>P_EA$ilNtzx_Yi|+h)Rgd($FxU zm;UXa(o-4QTp+TqWO9lWNhhFT-nm+l3m(`HQHFjpSKS8t_4%Ms-8msiYrrTjGc}e_ z(x5I$y^QhP?5SvxFSoZ>{(4pOIcCt#)e8~UG*@z=rO}HatMlU1N0XlKc(I8Gys`z1 zi)+05uCybe`iYTpTvlbXpL`8~s$|}dBpN7Mu*>Nu_h>En@Mm<q#PJub@?YS(H0hQKg4FQyr zR>x6vO1mOd;5VAP~Z(|cMk*28dza521Ntw%+{o3!vY z=Lm{pGh2^&D#t;!G<0o=jxAx|?&EJC!(9$sdbKnKac>~M#+_LEvkbPi-efthG;6Bl zM{3={jEVT1j~nymSH2Q(t=K%A^2eAy&$6n@6P@>%7R#SxIzXeN9_XU0#Tv>EQXb0v zIx8a;)vuBTwgkRpo9!-7B==pKt5aorhUr@0Q_MTNER{tXHp(YJ!TM)tyW`Pjj=GN? z%d4hlz+6Ri8Am@zBcse3gmK?e7uxKm-$(2IDi;?@^s4`j@@dbEDCdPRaPn7ljAIuf zl}%<&Redi!BVeNnWm5#9u6s8Sc{}_?)E;jgO~b?yvD~{xW{_MJ-*1;af?%wmW!*UYSs~S7+d45oa^0?M zY<+2U2xfAf{=gr$y^vXvT$|Z3%5hhv>aMP&BpF5m7#G6%EtHe7t{KLiB^o1(ZpvtB zj#(yKbSj^E%*AaIRAy;C9U3J6tcOxyH;^r3mqXFa89B);3O03IHJ%d%Ji>m+l&h7g zWtxRGBNpeqXL)|d)Iw^WFiK-bqCtIT9(Br{^O=(wnC3|onang5axK;$bdV14K{tst6`bQ6rpPMAe1%HO;lM1qF77!>ApvdoUzPFJ!a$x(BpFqm;jL9251Rl00ULe=g(W2~GNQLnxuIkH%Mt@TGnH z(X(r@->&*-9u^q&{dRqT5yQT%)h?G{%E8nh-~3R4_~u(o?oLdY@}IktsbUCz;SXfP zJC_!qxw1lDJd3RMLoE(n7z`tIGxJ2$hIxdZ5J?KAaH>d!D*n28D3)jg)orne9Q6`qgAQDsFjtNV{18@mivn2S;rSpElGh1@Nyd*^)4eh7GIGvBN(yjAae!g z{h}V3Mo+#d%jHSk;!KYG^hRNFS@u*LRRLG{aBsJ}#GG=@!9W;n`$bJZ;Hg zT6RoMc_3hrc!(lR%U4M8%U9x8*|yy?Dlv-YUXgM0^2X%Jgw zRPX+-u1>AOXTqXKHOKN{3IL-q#?+E3tXZB?d$_d%a*p)K_9nJIoYS$b$~dYHtXk`^=ArPa)KC+I+>$SVCdJPlC4$OLL^J4e4MgsUlB#8W>kfrJl+ zr>=)cjqBv*-igI@xwNcg_|ei+n`>VI!ih-LOZH1;`{kkuuRJ zcmr8%zVo|$Xok9eLScwwG`w01JQo@1o-OQ90B|(#(9IWVhOiBoi~#kY_>-=-K!31f zrwMve8$X}cL<^iWd?4`DGC~~#R+FCBX)&{}Qar(KraHtQP~CWC%Dm_ORQABx8}g&A zIjW32B)DOKwUpnDil!>yIR}pqYyLX)Gx42(rVBdcx$lPZj`nRHliQ?ZuRg}vGtK0;MQ^* z?DIIM1lFe>lRpu%hbigUSEjESe{3O#*2*DL53^}%Dpxi95dMyJFm48a1m{g66Pr?f zO{5NMV(imWT&_8|Mo(MpH#KkG}UC(E%8yt4niUv8oke)tvr2q zJoo&;jC4fl%VLcqco)~^C`fIH(VS$J}OZE;c}o z7L4Y4?>qTGE@6NQXOU`vgB3rRP$M&sMz3}u@4O8>`e)>40)1PRby*dQ|H#4cP&RJ{I;BY$f!ZzOiWcuYskXM61je8x=;c1Af z%y9I+3C29u3gT;)`)MeMAzD}<*lV=n38XIJN}W)V@bK$*vv9ghJ3k>`3}ks}dIDW2 zsU?8Uk;qB!-13mnqZ`o!0|CO91RPh1tHpz45jM}^vDd1PPFdTvz2MY-H zZTHnLE!wWuu0hw7-h-=v%(491omsfrtX66yU1TfjKxT_pMCi9AP4v}gqrR55XcJSY z)nZRAt89cSecpuwqe&LKKID8_Xhg(ndq2T||FM*$? zcOO7@oE{f9*Q{d^aQTh$ppEK%HtybVDv)}4ZCq@TxYs?hcRW3a;K_JAJk*N0Z7|ud zy5=D4ma#U@o7qr=5$2&7eZxrlI6cS)+5#dtd{JAz7-vJzB0`C$AYIyRTo*f|7TcaB zt7qj`d|Uc853*p-jrpU4+v@!RjyJvV|>3H2P61Wsbf#IkKbv>(GgB45CHBJ%mEQ_ z-J>3pa@7!MGdJ8s-X-mM>l9n()3FXKjR|Mj_QBr4o*sczL$0>Bv@_VS<$9c>3}N5w z2}gDde@)SAmQC?_6dc7Qnp#$oF13v-rFw}EHI=`kiqAWfP-XO#VlPlzmt;&lRAHLu zF#4QChE)&;=yJdRfzCVta)*iS`W8v-%l=Ne>at5YWY{l`5vkb=tqEKF}zZ3EMbPS*hDY$?3Ms%BGvZZkwK>g0-A+u1h(rHEzptn09?_ z;^7M?5Sb?4Kafjc+4cR+gI)~RZuWvOzH5|Z)@)$MtYdCkGBY&6l%Xa}GKxTl^JrPo zFf`W_V-pN}!W0%%w}`v_%q*vStu1DSQ>g$(Q+1PV;xOaIn8VhH+ljL)iViQ9matCb z9lLruH(0R?;n0Y(#hxB=T0X<0|N_(l--Enk(h#SSQHvF#V@AMNwPHyPRKRs5bGR;$eZSCjv!A?1R2>`T zTggvpASM20WiIlOGwTQVZ`#QVdC^HTENi zNMLAQ=nojwn@+V{eCQebWqe9n8$8ETh4tRVQ)F%^UT&X0jI9LiNRA}@Kj1$Xn3l2h z?XvvDq2Bxr6kNTLAVM1|X$BNPY5T?^cj6M~ppG2K0@eq#k$wAeEIlIo$b5&bbHEmH zMlxKI)}lmsmNieT@Y?)uQz|?BDx+PLKe2dqns;k7DS`#W--V@&LUt0`?|)YG$gb&{ z@~kXYD70F(^|n~jO#+pf5wQ*IBj%H|?>xL%Yu8frjw5 zIi30c{X^1km@$_I1OO=h+k^EF5$<0DL;gPnM#;*=+Qiw;_CEp?qpD?(tb*|^n`N5h ztVPgVGQS#1v`%Id6iI-d5O_=!KmmE+)D4~G(r zxf_hBmwm6YyMmeHFuEBO`5uoWALs55x!#Z0qm*(XG=A_rl*phw z1gd;sJG=yA@o@hL1CAgTCZr{V00m%l_*<}hAt(bCnkNKU<4X8m@jBZ`JoJDdpFiXM zl`=#bBVOS(bKn&xBM*HlJ;+@l$6aD@6Vj}NyT%|jjIRtP`vcn0Vz5E!p`@yWsk=7w zqLt_Yz4DHA~OPWz$1y-qL%#uV# zR;j^_@>BAtOem@o{Ar_QciS04fFNdVacfm3DFN+H{GgG;x}vhpdp&;zCa0`!gMg;B zqRYzfY59#Ehj5_Zro|NbppYu3UXMjWTRizN7Ovr13{=!uo}=w)W@>gc+!`BujC9+ONRFDtYK|Fh zT9$v8&16F(-USzRkPXe*#W^Is97Wo{ zco;8*xWxMdX_$%ND~ZNAL8@pMcT}gEZG%EOq&wzP&vC}Omw*+oq5+x$epNg@m~X~ARm*h^Ve!&+Ez&X?aXjdj{Fkc zk#_8KFz9QR?F`{&I#8dPXB{&QwbEF$?3P;_{dgjwpAC+7bsk@q?lKWZOj?LY4^}hj z4uyq*Eitg2frpPGVYi_#&ut}&Jd_r8Zc#o8kCt)Q8U0e1;N+9+w$m>QW;f{$0mK}u z*A&H89aj$lC+Vg=#3jM#^rDH1Go>Y}hY3^kreeW`$3A5w*bj_$b5IzyB{9|>G{L+z z$g2Or5W1>Qh%-)R#3P)8Zg%EHBrQB;r8Rt+t(7K(JUaZq&{zNNgN-oQmzI1F6?Io^ zes5$5Ws{>t<4U96DD_(ID&qFdgmLjax1Ckpk1gi|N>x}dC{ieO@QxSQa^!9wD zBdgV4JNq#EkKu+}Ta_ZHX)?{stNSV;xV< zk#*@?h#oC6a`|n}5EC!58((USOw;8yG**`HUl$(kI+Ti(F5 z$RU$|Qkn@=LGht~nG#Z=bWkK2tSMrEmp4R0^M(t-{g{UB(sK-vhD?`Ft|t=F^-UeO zWwq^jVgc)FvzBPr45LyGk@f`B?w@Pc?|(T=F#jKGmXn9A(f@m*AQ853GBR*9R&uei zF>v(wkNTCOY-6{iisEZ~xLUyo+8A5AJu0n5AhFgC^Jj4Cw~Iv=s9>OYFv>Ns)3w%G zijmqH9KGOY)|bBwP~_^sn2aI*ONd^OYi&-5Yb={Q$?1+$u2b%5w%3i%+xr^&xB;RJ zEY)nxAxPwd(qev5wENke&I;ox%oSYmVD+8ricd3*ZUspC&bDE)nkwvM7h2;pwa zP2KLXz%+vze2A51S8C6U48Jq|P5MHu*{aamGY~tVLVr2#ACk-!jL}-p0CalhY}#HC z>vOgsMOfTf`|2Ce?uAQR$AwllpGK660-Lus+WiTi-SXj0-C>4?6OmTZY}LBWmSJG9 z9yAbbWgqHDj<*?_H_Io2dNnsUk3D-vKMq~Afu%&J)I$cG2GBOc9lN0n!}A)fgiF!d za$m{Dwrvs zjx9z!I$owuo=BQBvCySMQ5-BS-d%R2ufM-CtfHWYpso8(5uQyB_us@|#&*RmZEx(e zBDwBIm7xu990^&ytBN97Q7^gJ?r?|Be`>P!feff9OB3~}!Y;L}*nYd&*6dpESngJ^ zS5;kWHWeItEh}p;IpDfTcngUH8QkZ@#&GE-6DPZQXqUbFgk~6srM#XYlrraL4MK;Y zE0r#ARFj_S(JWw4k7P<$D;!{3G+~laKKE^kOOzpLP2Y~0;&&oO){0b&w!TM6ja-R; z#?Po=v2lo**eu)9VX3kg83JTYqUC@vM#Ce?dxb$@uGWFbYK$Owqv@7p9fUeZHP-sQ zdy#5g14?;m1-~49$>Ieo{qO>-7lO-zG6?c_(oaOz!hD_fnq%enx(v)Hr2yoQxB~@Earf0A9KxJz38K$2bL#egqy}O21~_DJmqjEMZ`K z$FU@Di}MaMck;rpb4gbAU-b+ne)c)b8C+Oqx{t<+kJQrl;`o026-~C((8n;Pi;K{( zh|U-l$0#OuP z^IvB2pL`%iRYn@c48ynA&dlwP8HmVgr#dS2MI%i$zxif}rkb#h&aaSnEv>L^156y# zR_3PgRkqUmvkpi+&$AFIF9t--Oy#W1^isS`mWuO=FuZPdi-Qu$T{|=&YT>7cp52%4 zAD-K*@AuCzue$=&ys!oT7r}6YK8_vqF+c}nB98D{1h@jNa-7&bh)!c1)T?TDoTxnx zN5rRmH5?x%+0X{8FF}J}6fh87@PiyN%uKVP4sfR<4g#ZLOmvg4;e_&vHZ#tcSWc-r z(iNnv{M98eRqK3-lN@R@-lfWm(}AXL@i+P&=HgA5s;8pMjI1iIF2pHIxM{}wfj37g zUGqh$7?$W05dsJCT&JT3>n$vc^`^<Ep#oZ(;r2@)L zBv)BjyQbuE#fUYgpj23B*A<`nx~vy5UlbQ~_Un8VG&By%Ye`wYxHRIJ>uE;nqO0`! zL^&CAGRtEY$|*gULQ3{?5_2atMhb1wxmjpHyF+TAuo^^0$Drs0 zQW(n#;+g}2ejCT9(NdRI=|hNs4$YfHQ?$bfjg|u;rv@VNB?$0Z>2#a|4SpRjD6I5O z$}7#t@A)4ji#!++HBdv13V3Ge?hs7XzAxr zWtoCHu&$(&Cv)s9Lo#g~ce3MG|1_GK*NW^x9l=g5KpA_8tV|44R@NBA>rfkQQmJ6a z>5ccKtBO4`@i=moVwnKGJl~&)xL-HI1ffvvRp`aiGq8eNhPtSXM)m8qB}+xXRms+| z-FS{5W05X-EzfaR%-Szag$*D~Y-V0q;*DaoCZwrt;P~y#D>uSrq*lS}%wT{CU9j@= zz${FPF`H?W@G&>t0dDtBv)fA`8Qw+hF*8WJ%)6@{Pqn`8&Gl7%DDFqzw(!9lYffW) zMKW0X2Xi&F04Qi`$1VQ$Omp_&_`WT(-x2<_X7uCzO5o6G_fO4C&6E0QqQ3gnqLv%*J<1_K+aH z6WJ=s<_#_(2%tsnVwaqj6wGmUXM<~83ZwwQQkbKhe!p(tUeMCHw?sFZjk;JC{|&Pe9x=xR45-USAAs%0m{vBJ)WA;MnM)(0W!mK@)(&F*LPsHZN0puw4r zHlnfkXmooiJU2q37+V57Vl?o@?tT5}>Tu$8ZoK!@tD7lKaURrP9LM*Pv{>}1m+mHm)N zPCvO#Kl^srr5C)-oxAtQ>z?+upXGMg#}@$pP2h7jZjX^avdW;7U4!Jru??K-IN?@z7psYR#z!`U}9=fX{6U;k^*E#8qTp&NkmT%EJv}au` zg`)U_Z3i*m!0MD>WCN=^iX|ZA?;RWya!np{Cry83@n4^9Tmp#L-{AiyA(0x(2C#tw z0CfGml=a`IWRm}DO8(DdlRBh6$}#Hqw{cUFH5nihP^dUWWPFkeNM(Mr1VpAQGELb) z5ZnaGM*D__8T+s1R;v6K%c=uVUDUYp6|`zd;mY!R^OiErmR42I-$GVZtu0}Tw=>pk zT@#Mt;~#N<^YHfVSJElJ?~{XZq3H2zJ%|>o_N@?D>q$N!yLtOU7>%1ll7AMcHFCYq z5G~(PXS){YR_VSgtlKLC-tL_N&Q0oA(&^8~6ffd_L!oBXsRnmqJQM=jAv~DL1~Jg9lw&tm9XxNu)TdGV_2x?CqeU@U;F_&>`IAlVp7k3@u@YNorL}_lp`fC1Lo`nUmZbm(m_V zjH#7w(&owfpvG7`Ps1F6NqIKau;1o(?JnwoPzhGeEwJ>cl2c3B7-VRSjzcG*h!2TE z@=CyKSWwJMTUaq5Uw~CbL7i;X>_d#Ft|pPw#DCkG#-ulIB8I11Lt|=8g`-J#4p4DR zx2>JCDoS`1TB@b_kLs3yw-icYkjnZNNITV>-|z++Bl^Bi0zK5QuMoaqWoN^PslJ043D zy)>>$X*j@gHC}4jKCjoDB<3f%QYx@$fvh;N%^Iv=Imp%6VD~5nIMa+^LLrOFmtil+ zuHxb5jWOX)ABso8H=FEVE55F4x7eEy2tTYUKP8Wh^* z{HXx(O|my9c!%CybBL?)je2YOniWg!&=T8s$P0UW`TEQJoAC4}!teZ5-dfl5EVJNn z*YS*hy>7pc>pLtC#gb1!2O-P(;uQm2I9^sKU{+DmJPa$cqM;cPuzSH|RgQi?RCw9(=$=p-|?yxbL# zZu#CsyV@v;hCM2V-6(1>8gYsx3wIjRG+np^#4pij7VY<hA*%He1xfb4hVYFRbk`vFB^Kt%4F5Y1vw;DbGQJ0j_kMRsRvND1?@BSuLKW(|{*z zG^jRQ85(>k(ZH+p0e(e{Vec3VwtJv)(g4)T}_AlEi#6^>dS8FYt^XnCb$Al>?Dg??)*rXq!+ zA!qi9#oq*~Wg@8=h?GyLW+lv;zLg)xCabG#mGr}270%iBMQ-Pd^{CLTFO3WJ>EL2W z$(?O~*4btlwTYF!Qr(L@NL)PR4yvtMek}r%(34V7lHA9RjY4JIz{X=H#JVeDJrH;I zU-Gb&2bN7iE%GnHWuhi${u~n;ZK5r8Fv-N1VGTSdCEOY9UK{<4Su-_Rr^9IXQAec#f1UiqI#oHu4!pF{T>Z9Uo z6ybDtl{Mp;!X&?=b2S`v>hO%hQLk}uIkqjI>=`%Th?(|v=a@NI-h{7l1fshUb0uwa zqT>C!Lrjy(-ihm;oD_>+i}SXPvD%2br)}KduOkcJPOrxX{h~N3oM-lrV7d`OgqNdA z=kYHx=Jhw61!FJ)Aia4%(}``jf;=UTV}O9acx!RtDxHT}ipYpyQ!a>lWk4eobn(s@?K>f z1CVT6D2^leU`sBYWVUfh{H2{%LzYgrhoN|6EyPwfHt8Aaf2bODy?vM~Fs-c4qH?nx zP-IeOiO|GU?|I>Bop=l|`7wW)K|lLoBlL!+Y(2*4MF2~#wQOR`b^&a0v5ETx% zjN;K+5L<0ZKaPZtZU#G;H&AzQi0&TMGgshDA8S|fI|doeUB|h>4Z(@2p%eZvvWLgb z5Wm|8d^JL|7gY0EzCl#V%m9l@K`3kGZc}r#>kh%S5bKnx#N6iCAnApK#~#-dK{u$# zo>opb%+Y!TXUiYC0hfFqEjw~kK57$_){Q~)#yIgxpK416eoIPjYs|bO53w=nHbAEx zD2`e8Pr@MrUjNe32N2`jo&irBuRCJgKB=KDnKx+NzDnBr302; z)H(TR+0HlZln}U*0;yyDo(Im-n&N^eMaYSa)rpzhUl7HKSNmmjkBDk0^^@=k{$>;{t4q(1!vEoUlJs2Ev z)Yw!+5}P$3E#6*vo13F5!|-^JEKcQrBU4^)1&Mn}bYJLX#3(n#B|khjQHf?L4N2sz)KFJDy9!EGu2#BSo1#oKcu~5aHa3IFZ%D;wr$(CZQIU_ zla6iMwr$%^I=0b4M<)yW?z`7rXWdhEYQ7(5)%@^|XUy^ZG?tBUim?*XP|4G5`E-o zO(C)0Bqo#jcZERXi#rmo@5!$3_o-=goK{g^tln#^&&cKt^~S5mHX}Py0{(1kblJDz zC%Xd#jPdW1#<&Nnb<59D8KvIkOlBR$)RUAdV3(m|JATS_L5Q9s;Z)Lz7HL3ueb&Dw@Nz-a%4E{(ORtT`yp^)#%l0nTj#4pp$aUzDNxrJFFNm`X zs%en9}^ zYx|VK#WeFYZEVP{21=$(nZJG5gf5+|lHSp5-00mQsgc@{S1H2LFGb(PG2HK`U(y|? z00ZTWwdX9aeecQD^-1jwf1D6*EDVjobf0aK>(;!XX`P+GV2I#(Cm5R{c3bEh7Zq0p z%-J>p%)U8Hxzz78!Oc|K{<=f3eD`gB>xffcdw@iOTk$COC=V10KbqB@<(%=Fi|HYE z*JQWyo=eeJ(G|~0ci(2}UTNQrI8VwvobU?v!vu2zlNkjWukP8KP@_kkA2EMgB@yTng7V~xest(iK^?WE*b#38L<9$LXt`=F8 zc;mGfKQGJ_)d9KC(4L2qb+nv_-?7I`hu(<2g^=%i(#hwji5lf?%D06aP(pqjKbtX; zv6eYi&=arr>u*h6X6pL1t1VZh8jX7Q2}@rzLOT|$EFb3u`syUMj0>Vpy>0(`N``aR zDA*=|>Nv)-p;;Wq!Q8{T7inzc`@tdNSw^jAa9sxoUm7QEN_>C+>+Hv){g{j(`q|xI zut2U3$eYLpu+(jWUl45!V0;Ah$w7jB*J`$43(EIfgt^;Wd<9qtptD*HpmVs15AnSifnVcWz%-SW|n2W#fx=&8}ISUOpI6)Z@uL9 zZJKAg>)Ge)#%t%!4|vu0>(W_4ft&^Y6PDlMAk^-CED-;I9FOm_96a+@4X)#s*~3Fy z@0a7j4)5(Qt;cJ-_kEQDT`Qa+10Yl5lO~XTEqxNtxWz16Y;7*k z`$8=mCX}lcHTYmJArxY(wLgWZm1~_=LLoAwY%;+my9eYtVHb&Bj3Am?cz}>Dd5HdH2nOi7O zy$0!#3YHUx)7o;sx`vp&3YNTd z^D>b&bJsEuEqbvMXweF=7RW{pN^HpGMKDtCF@z-*MmRu)Efc<7khJmvgQ=U8m)Ows z;R!OGIfT{W!hscKy+pVIDRTxVYNS<)7HQ2(d7g}=3;5Y$y_f%k7K@=zPCmS4IYrHlI>HA7-of{pJ4+O#v9VwIo(KGSInY@Y!%Xp@~c zW+e)arN5L)NLn0Rl*jjiV9gfmej7&2*;r=Q3ohgpJrt+ZNRZgsn5k>2Q{toY82_1g zWR!++@Z4^=ON>UG5J>W*Qf_hqF=p(M9<$}0tA@?EtJo?>Y#{DPeqwZOG6 zmK`5c0c`-UmfZjt6S@5osCI-0+jpeJVuO${5FksL_Wbi15|t@odk{SyFU`}yYNZ(X zC36ES)=Xzh(4a4U=}SrXCOW!;_?M&SQyEmzjnkCW6jP?F*xu5(I1Q`qD7?HJeMI#1u_kMJqGpZb z6)U;f=%3Ji-grZ?U}ugz@X-EUkYo9{HOTv8jyeGYyFZaL5?!=Hq~(%V9CH%Ut$(#)5JB}D9Hq@wqYezmOV+-?$g9n zVJe`tN+afLg*)F%!}?yq{Ys*sAE=#oe61QK5!%B}sNxR2RBB<#R4s;`RBGX7sD8nr z+eXb)TDNgjD`9GEXHl+^-rH1>; zBB)nu=V-W8czxh1^WoJ%&SXWAkFgrHL@|V|YkB*Q^@_uzcaW&sWfCrXhN!tCg%xWg zrglh~s*a&+1xDn6a(5{5t$@asJxsBoA=eylPTm1E_;`~!)a2~=h@t*cB8Ww29;T-H;irqVc{jf$`aU^1Dfb)HqY05=0TkzCAEppaq3D!{;FA}B>e$SpTvOKSHv%f(XbAm=k zaV5y#koB$Y>i|X%#gv2 zX4!|Bn$}wCJM}Ae>WSNV3>ezj%Mc75d>fvtaXjTF%>dWx8zbdJy-~cFaWbZ6O4>ll}#$o z=JWXrZke8M_i;kq2D)CP7kd|7=;*iUXUB-HPjF*z4CM=$ z*?}t8K5NY%vWyoy)}CNCwn5lSrv(A}X;&lAr$qtFbFs;#XpE5`SjPq=I78cA>brP2 zOtQQKomu)PxPp?MH&7LAs>&cSMrh#5pn82xa9^e}{1G@`qEiSQz8}*?wI@g%mY57_kNtwoKx9Jo!aIDlR~i9!#;nmKOwK#1%qF8X6~hC zQB~3PM9KrhvP$KQ$sALn^WG^AURliU{N-hX+p0n@ z(dbKK*~w%rm-vijK>*Z zs?l|iZ^M!N3SvIy#|C0fUoif}?f|69X8SE(1)s=rX!#$#iXQs}I+uxuD9D1`a>_^> zMr)@dK<=u(`Z-VRD{+~W)q{lb5F$!AxC?A#6lzL{k+%x{t5Xvw{-P}XN;B0T2`kt8 zk3jdarHn0(m66g#w(EXHY;%fq;#uG0eKlvt@OjxSbOj$JIB|uY!3v4rY8 zIYbRZNaKNNlns-YzKdO+zX5MGMABI-Udpx|OQjTdAooMel-j)0_aiKgKcGBfSdMPy zsi_sNlZTxm+nnboOzUa%q^V_LiGBJS&vHe z{KYYNV)(T-CzqaBtvbbQ>6JIB53HE)DZoeDC_`qPK6u+lKwsp}-4n3?@LGSC-kz?# zem=h1YkT}jW94Txx?fQK(9H~!4BNfiAUjY{)5BWWA9n0)UYFk!8HuuHamr&fhT{MX9IXZOjM^pCWv893G26j$ z9DyS$ZxUBQC*ZL+IMAQoUMvsJF4W(ekYAh=Ic;Y~qQ@FQ;?q+01g9d>kYbYp;khVE zn0JqgI3bVI;ap0^2p)2T#9eTN5smVSxIp}l8AOYuKA!6B-#JHZnXllD<|tpyp?Mi2 zayxU`a{(Jz(u`kl%vj)-OVn+2_C^AY5mz`RxN*i2u0BvkMkratgjf{mur(YEL_Hzz0+0E9?3XsPIWD zC0LRsSkl?F7M25J;ExryGcXp@xqED^TWzdcZf)S4VN&I%llJHY4jM`3K931=(LNdv zDeYf}G_HEVlRJk=KlZ3ySE3`pKREIk>`_ofrT8Y2fu@ur6bqC3N@a$POgn~^kL!0P z3p1x?NK?+FZ%wydIJwI4FApU~A`65+xsmVLDg9r=QXC0ZvEmw~8f)%v7Z3OEYFH|- zfz(*qVIFIgPAFbfFQF8U5q(Mb)DeAI_g0a5(0@nd-d@ycS^CLdAS zQUtjo$yCj!KmuB=8MIPsRxXrJ%KeQ=kEI{x+o+9XU=xwpkYS(&QIc%10byn<<&Oa$ z6%>~@2%pAC)vI#&s!aGo3sJF3uGs(^FfHN$j%Y&~V4GHZDUm-}u20otwQxigNvE#q z(mt_88v4FsThOuk?%R-NY8@{Ez@&~%XmEZ6QuEa8RKsOIA24OX7mdFw(Daqp%>Kh` zS`vj`3@#@s+_Mm=DTQB=?7LO9m99jHrY(Vh` z-pBo}&ai0ji$ih$`nwjG*karB{g3uY65D|8W_+5`{%>+Vf~-;7(c0cC)RVZx9GbU1 zwGhQT9D!md1n6Y1Iu*{K<_SX^)$2jJBVX$4lEx}sQw{FAfcJh3)I4DN1M7}SH|@)> zjH6$JC6deIHM=~?7EqJZ{an}HEvw>jk`A7YYJ5>TN5l%ru|^g5jDH>lrxfvw-g&bK zKVfp^OrgKLE{jPZN$)VPcR3WSxTpHP&JJv9{ZLSht?`MYh52FyoiDQ+#%9U{6c)(oMHhs0FB}=>bfe8%j*g$a?7Xa zZF%$~2Oh?@lF8S^J!7dHjM?XeR@kKx$#2AH%pxswl}rD*@ALhQOo>+5Vdt6r>-Hty z*beG)uTK(6y_R=zo<-|yvuc`SO6e?{UJz4moSEU^<+6qMTDpRk*=c@G>q-b?|}<_y&B`jEIlJFC?` z5Ac6OeMIq-ipsy;8}9!j&*fj$S$|97_?w&LpU#kf*gO6U^^rFHr+zY6MOz+O5aqL^ z)pj*my4_v4Od}8d42Vdr9~w=;xH=pG$y+JmY=By_254Z zc!652CCgQlzQoqXsp&X%*K8vA0JG@WnuDnga|J5_iZ|^B0W9VS`J|o{N@k~AFQm*q@()3(U>yo;k!9fktoC0ADhx8)@ zmvl7K+3IQHvc&HD=Zz!B5WzftmA7{=n%^O9Vo{AdfL*4)(HSD;o1(A~*BPh^;3GkC$x{|Y@4)nw*w3POl#|G^CMYrZD-i1V zb`AdBoE}9-m>+eyipsUC90Sa9*-_fa4}kNAHc|7iV&7wf^~HG$g(e2ir2qkX~@a{viNp)}i{QaYsgL)f#@;t_5IF|`X*7I5YO z#7)kCD2Ri+pNj84xnRI=YUzE|$x~-dS`p!{O#FzRA@Av%MrLt^H2=W7@)DU4PMoxs zhv-VI<6Gog;#YI`A9!yE!FL1FyI##i;o zgc{&S=p*VBWaR?~^+G=p3c+QSeNVqJ3ckk&Ys^H{y8Fqr)eZ|HwJCRR3!IIG{_ zD8;vG=D)$we?2B_|Mr;J+d13YnEpS?V`UF#7gJkNCnseWCsRY)e`;tFZRHmgP)5Jp zF4W3Y=YE`Ha3H!eX6y?ru3^p*5W3p`#LODzMf7uG~HdIdFB8kIFdtlQXCf54Od7Y{VMuJ`-onog**o zglm5KJm!Z0Ab6OV&*7o6W;BU;!f5)4wdI4bA*xt2P>?jpP)hjCg^QGd!nsxapjObZ zavM@Gy|d;N+P);oCSUcO5@TsW#pa5!rgWzwE_l4jb<997tC(Sm$_=Ca)rmcw#0;~^ z3>VUGfDttr?6}S&p=Oj8T@iBxh(-)+*%M-zS{?o4HUJ1b+=o(6!i+ees>XG2^l*CB z=gxyk?je6Y>_5DU>lRyw^AO`}^@RgS34(EHM)TZaLiOx&iT;rY!funy;VT7Eh<1`; zJ1HDk4HrvcK}#4h|8`Qtq$8|9UfKt}^7$(ugLDfiNeofnD{+g4SwWCaa}?J!hSf7H z48vg3?y}WiD^$hxVmn4Mwo0;!Dv`7{p%A5#g}MZvAbR)|$&6{qq|6gZ#cK^BiLNg- z9Z|Pvz{JbXcI46ezPm;)6w@-bp}VFsV*g&;5h2g=fBL(UE3yImnB}`JHU0-^|9?@J z@~$rbvo2-r7X=VPcA~S}SVPbj&?FX-@&q>KI+~6^gytYfq!C4-CW^^Nw@GSnxbMO7 z`Jv$i_xm78KqMUgg8YOrT5;T3q7r(kV}3i&HV3RcmG0Q@2o7)oRAlzb95FD5-SUEe()Bcvf+pgWWvxU2_+x<^& z!2^G|!MF7$2yPjUX~&=|BzljA2jC5#^x#JLxcaH%BsXI^y>-Hz52B;t2eBcdRxwkU zFu)kbcgclDftkX&opmj1sAcLMYQM+Rnx#!c#>j%UvY-t6N)O^3 z4=W)}HU!v)On+rZdq&`OT%8rc#vJZzustorW0)B)Gj7-L0fo00#2NN5KJnk#KA-MK zkdMI>*Gn0PZt?$Wzpuqq@E6)ibcZt72UzfmcG^Zn8Tnqpu2D-l%~_~Y0^JZE0Lv+t zM9XjlHlmz4OZ{kej~(9^qVdk6FtIdbr0vRfQPU%44@$cFNN3O|Ly(HdQHyez$a&_R zEM-hkGTQ}JexplwoJC$P8L0pWz#xbGO<`HAX1ZTL}%%pxstj;TDS`4NggN?Mw z^hrnFW)`h0>IA|^JAlbpb0D3`brsc)(_q6<>W7mVX(NNr$IRt^K#+*1^v=9;iQSPB zih)MEBV=fa&E#*FN$rK{fU>N#oZM7|-!A0jJRR$GvWvfx391*22I^pL3W7oo(@7zt zm7ln9ZKSbN+7#FHkY@sV%%En>&0U=(-C*=WXTBd$d8Z+sQl}C6?p} z(i{0NI;1_!9>)aHnDNMOTzM-LN3^+o(pk!ny)}HLH6;m`nhtPB7quH)M76zP~V}D2-I_^oYZ&O^JV%u=}W{c7|^u0{@5cFUZItrT+#sgzVU>ic<&CH&xkYUpU zVTL#(tjkrkVHqqM;&Mntn5F0tHK!*eZkx`q8&Y-}k#5Z{h%Cg3D)5lguU`!GJM~&s zklleoVEREYN=fyvo)5xJPrJ5xm zQz|KnCz6y%kW=f!C)m)Gutr5BD32mRSS))B_fnk-%5Ih_&lgdE0K2$4F!1`1Z$Smk z#$V+w3b=_gHtMS6S|upMokgW08mSUHou7Fxl-bk!uiy_27V>ti3c$11MS z&MS$m@^!FWaduFC#S`gK7MwtitT`v~j7sI0sCtK%e1senXRGODL#Qp~ccWGSTadk_ zS$%QBDI@0^Zq0>lxPdRxggn;}at99h)460#O6nXPj_sP>Z>t9EE2& z=T|eNBvcC$%ewM%U&cR%_!v`mgnECFAGRF(`uiddm-uuW{OBjGErZX-UOZ9A!OXpy?IrwyF)#nAQCh-?LZ`&_$_L}(q zRvwOBVMC`|TT45H8f>4-ZIbRxsC68aKR52Ty7=#Hnq_u~0m2JgRF|zD4xRAIj*Z}< zK4~G=MVLwHgoeEPgSc(V$1zY3&s{IRgx3S`T^!$=I@(4f@jV@DUHlG*9qF$h_DA*J zha%s)-33bUQCdR1UnqUaMn80(yfi#}Z}(E&McCew(a9rjDXtOA{biI9@5Zz zANHU1-UaO*+F0Zv))Vn~j)oWYc!=3ORsv7FUx+_RrXTdW2*`U+2XpTd(COd41+)A8 z`n>L{hC1pe9k$uDn;k1|b~ZNlY6`Yc!?J25b{F4@6+AhN*PGkeM9PVnmS*hEjE8>y z;DRL+>ywe+OvNZ&)zq8XE!A4>q9YzqJt&e^WPWLu&dv{;S60dGKncMv zn;NB?Er^j6FPp6wosS)LcxTm{2BT9F_T2-NcLuqLQbExQk(g{mp1t`B7>rMAvOZ!C z;Pj1Rg#1QVY7~+Uk|n{g<&Ju$p%DMjsur1zj2nhH{;# z7uAb}T=JFB+TGGEtJSRoh7)r|4{LFF#HNZ0Gdku&GSowg_PyJtPuSYk5T+SvuAZJL zG}owRLrvHeQldv>pz4XJM0YO$W}_p(xx^8ZpvF++SykAA5GMJ@gx`13v^>4Ys zCe=0!d=UsrcU6=aWf7rJjxJ+Lmo9!C65vDQBPJV>a@#OeFaNPf8xe#T)9WSU86>*Q z7D*{cd#g^}G}Bc{^jeu`o@Kc0mm&=^HI=iWVHaN0v@Xe|4E}KgctHV0eDE7dx=f{< zi%>`c1?N>!|5TnOd|Xq3EZj4A^{2%ETSfz|6!tu;)P5lY5rU?KoM85&Jn^}V6f!m> zLNE}q73f< z1AVCNfnsCL_W4yY$#iE_*wrc9P7_SLI2nqZ54sLdRK#-)M2Paw-?nu~^?CFA7J%dN zztpMK7Yzs}-ll4^`TKe^Vq!8BBm!gX;Pn=7*}G~8K^W&G;FsqD^@97poOoe3>xG3e zE{=+Nt=ljZVeRv@2l;PH2AUGzS{W{v=fIT*M{gZrQ+JhM?e~cwN>0`AWtZT@u0w+fe3gnSfkG=rO)7X#(hpAJpMXKk=A>5GUd0 zIDvSJ=9T|IXPqc|WK5*`+|ShhrbsP;s!KiBPtP|1;pR8c_O~M@=wlN4vBAoQaLP_B z;!s_(HK4#3F%sc`1FP{Ztl-ONOhLdBE!o^6M_B*|@+2YI4qM+ePjv8<8+f!bxTIQ? zoJx5BV2{8hOnuRlltXJEcE%<-vxxy1g2aL54dro*No75TVm`v$lhl=iC&Zo0h-57* zG?WjP++(TcmnbJ{%OR}_giJ#*V;93XqYxR0{hI>SRFsYqSyT3nI=Ql3_7L?t`Cb@4>4rrRwuFwsV+Glnc= z>a)Oyd*skwwR*{VnXQ6x4%#0|sJ^jrKi0GawTC;J~aOJj`(<&tc+T{oseR ztQ4UqZ?1ARDhRDeq$PEzb!-Tc;Sk)ZE-ly((1A3YQd!8xJZY-KYvqP$#9JhI9@^WD z$GzX?Etm5cKJ6efx4Yj^Yp7LVJMOTYwp}v}g4HJ2lL~oXHreke8Z>5< zc9I@Dm2aHEf zejLmG=%uUb?u~S(vda^3d$yc|j$_>wBDpz7-b9C7bCgbv>U15`!KK({GG&fsl>_E^mgLqvr{A+8f# zOno*e{HC$P-nV@Xnrv5X2DSi6Tw$_QJF8Ob9%4;`gPtC`bBuOWfAm22eMMcB-T^lM zWm{T7l{hF6gPmrAhfmZWoMNt-qJ$!mQVLU4Q$SH}Fi;~Tv@WYw9kHCs!$yka>}mv0 ze999>q1HoAo+UdL`Y3y}ne3DAXE)_EYn)iwmg;hni3U_IvsVDR*Al0tQv#K90yh3( zO_kIgp-$39%rp;W==leU2)2r`s0J|eTJ!0HbHnR89p4y8Dw>WXxT!iM0!<={(L!sTxT9WZx* z*%1`MU!mG^hu?&&*7Z$-|1d!-%c8;pYoV4V&+09(#JNdK!2HNqpG@!GZ*Dar#C3p( z+yE5~4pIY}hJOW*2#&zjvRdMbLnws1$u2E{O z@{od#F*Yhc;TTCpOY#J(f22a0;&GSk;kuoH^#EsX)r)aVvZNX*w@fQ2F-EK0Y^Sk9 zFW1zlF)NI}uTe8yD?8o=QjJN=fX-w=uaG(!x$sC8wI~Xa`BfSJA-@m|jd5y@EYbbA z2wj#u$#Fuc)4IQSh!DG#xiHTG_G^{_qjAlk?30EQq=zOtQBh%grh99DsUYYLhg|QN z{{t>7K2+FPS22t0An*z&8Bs?1dC)bi%u9YEc5*1Tyzc02@2J$*ImNHGdT%Piv_`V# zBaPk3?<;*=c%q?CH4#i**l9YS+d7SIaZlqqhur`JLpnt&oXjsiL=K!?%^BX?b#^Myj!3%|Pbmjq^oV^W_8j)nR39L(5n?&`5X?yG6}t z%(6PyL8o#!1L)ZXi;*94YvZM)^yU^D;y5s+ps764O7kyzF(hkEOxHCqw-uo3I?>ES zW9z{|w*Qo?6))I+4$q{jvyG|D5zI`y)01tve-=6aF z9vtQ+8h!^EzI}jxTFp%s>=gA~A9;ljA1P$Mhsj(q_qOl!KmbAML8i|EUp!d2tOTU zyc;H*&j(kS^&JNGZvQ&e!Ttnyo`mn@IJ(~RJKam+!t(j3zcR1}>XwSjxJXTc!V4+a zv|ViGtVEiS#wRpNsd$MI?GTu3h?v>i^7Ij%l<~v1ape*Hbkj(P=k-h!(&CT743me| zT-@mP?f(I=q4~c*X@19d8GeIo|9eW}-{1EB@y=8%ob25UjciPn{+_b-U%3j=s^3VP zDu%DzSVP^m6eS8I(eFgEBHOB!+90J3pky`>EQAcD>Pa(5X<@d;bqLRSO#7@m@)zi~ zYIe!ds2TTz;IHA{JU(;wqI?==IkTs%ho0F7-|T1J*Na?zKXLe)-SQAe6P7N2OH_82 z2_`Bt7K*lVL$p?vt&~u1s$-QY>5qUA=C(?~L3AoKRv3wn5HBY;eNnaHgb-piW1rjfqhqf)6!XL1_i5jA_4 zgaLK-8fyouyg`w&m}^bOs8PD>yd6+1qSxyNg3yLAVa#T?=`_TJfN>*qbb&hitMM3K zrt*AUE_l}>U24)!NGcSL$gllhRhfwjVA`{zStZfyr zyXH|>EwNO*;4+umd5*5!wv+BbXO-?lnL4j^ZANPakZ`{0f?9TmwH9;>&0=P$?x5=U z5~F`47g8Du2Ha#ApO8{~6D%scE6Q!ydX}CsZe|+=gQr#p`4*TFZtPw1<9+ix4`;-_ zJEe;^u^?DWN5N$WwSRa_(?Hp_=W=6&?q8@SF+?=Dn+;H;mk?QA&3Rllmrx|1ZhrWU z^B9-@2YP^Hq-?jxZ(!#sBnMAUrE2r)e zkT)K3iKyaOav^MfU!`;Ky9M`7_2MS^CzlocLcBr^?_j*cTuB}-HPmB)gg(v2YbTxV z!iT$`K;<}IZ>N7a>RI2sCjBbVjz~Cs*&&7wG70sBP1;7-0XR4?KWoe4fctK=d3=Uc z9aKv)5PBVu`#0aMbo`~moMe9O$-xV_qu)59y5lF>0_Qp>YmmMI#h>5;ck}H5=kg%^ zwPDiU8N~7X!wC$Sc^|U4d+B3INIpN@q6M@#&ZfZ4^4tmdoUnki=7ZKE7;Oe60rpfj z%XYt62O5|pOIo~^g&|GNXd)LQM$}je_=Fv3ey`UL-$9GB^vvRK4BU z<9)%u$4?;Q2sLW=Cmz3v&FXF3sz>$~3$0(2yt~)zi{C3HAF(=vkq775KiWoA@`m`v zcN~i!_k|}hZ+?lW`mgawomHh&JPu2ODi5*L_DVdoLLO;t|PA>16Y-zp|N!w3ycq&0g=7FQ~NCe@f=1NRwER(xpjAN*2Y!Q zqw&KcIBtyNMpA+?w9gt_vBa_9G$p7gC{qwYYSKVHpqsSjEaHpQOvW2W7uM+!EVyTC z%*cRgstF^y+)Ql5FnOubZO{>#IlVg9X`LmVz~{G-Fm=WXAl>M6^5}{}k0$dX*$zwfao((5B*RuS#leJ3 zokg~$sB+CCna{B3a(mY^_YhmhvaPrj^0`fof^&@Y09`t4HIInw7mMSojLONZ{#~tD z1{fz?)NYCLwjevy6Gy>e@KZ&G$^vL~)v3Mw2>CmSyaR}(t`nuFaINwo^983Q2Z3Q8 zG!>qaf(UXNzQKe5Q`B5z(SCHQo-8& zMXoPMGRO@}^RzQ`R$vPeJQ6llSu6gp7A`ATghU5j9EUoI@WatBB2npIKgx>>s< z-Vpmsk3iPlQxdz65@ui51Y#XwuT4WWMv6qAs7u8?JBq<#;ljep-#sr|?#edbgRD9A*EX47FvspMFACvV!i9&h1f0U! z0|mx#I2lCqXNYwl{OogL$;-k*X@{SJCX~RVd=HFMU3@ft;Z1YSET!dLFjZIDVbk}Y zj&=OX5G#$d@cs9zFIN(twag9DB@pv?B+)&B+UKx}vQ`x_G35T{$R2E0b|0_An-}i( znOdg>#NARN)JrQYf)_*+?znko?%5@w(W|I!W%F8tCB0xOJObR~q!D@}miL_Evufxr z6Pg88q6GpSu{MWrb--uhN2 zx9Z#rP`0(F!PiRxlFHkmqTCV*mk zGT;g;i1HbmpfDs9nJ!?^hu`-^kcJ^%Tu*-#s!^GlIzn#@-oMo8;mM^-ZV2WPCUMi& zUQ}|Ot}2O$u}xcshWWspwBgD)qp|v}I>VqsWy-|cBHh+cAWJ)y6xqn$0Atevp9go( zV!x)dilb+!P*Yr+%6#_fV%E|m0_W?*u}hc)4c%_j9@ovKO@o?3f@6HU+9uYC#5q}0 z(iBp%>Rw@|N^Vzb)%9x^z|3093D+u1)IMU1g?LbRjU_wC)UBFPX=zqGleyl>WzW&H zKw>4r;V{ntd%`5F?`;#mZ(0SF?Px#4;NkmwhN)G0!znv*Nuxtef5}F8?N`xGIc5;@ zjae!yWzGz>-h0+lO!GNHGw|ItN@QFA2->_qnH$sgJ9tHR>49;#Rf~Qr=h3Ef=ISL` zD<<6&)aTMv3jq04Pu4ApH6VLa%D`Z_;l=`Pa2=1*f-OpArb3NU3J{$+6PzQHK2sMN z=^Apt{a3yaZEXz$&LvQ$mae9w$2D_BiRpt`xtX?oE0pMPvDT!h_43MV6k&;&XUb`j zK=HuH^^gpxF$XD@YCj=QB>`0iGDq1i%M6I4azA!ku>lHWhzh!EZ9zHZW|_(>Af2i$ zKoWG85N{|GYQjCz(AykC`v~VU+n<01^rWszKwL%;6d8sbK&H^Kr5kgVoQB(t>1-!z z9Bm;JJ8~_Ss2E?Yx66wv;%XQ6LzwB)W!d%D$%`LXYtq^i>VSQ8By0_~7O!$)*ic>R ztyh_&&1e$_om-$M($=^xf_?P(jgk@RsMXboqURL&4+)GB1h|Ds4w;nMD{-z%a|Qws z$-)#L3~>TqV4?i0^}=753^A^kymEd>RorBhoxI_5(Gx-6yYAv#H=?0ImLWESZu~De z(O*IFU!ZcZ~nDQMZVM4%i9+|di9aqEgx0BkiEqXvU2-V- zy-8TETA%Cxtqt;Hk%m`)x53u`5y$ke&Rd56)CT`|S2=YLZ#KAnjlbatEGee_Wy`utV?D{@B9mvo-SQjN(Sw3hy+rNpftha}XHe zg(7MbJl(F`HGXM}k_T~6@F%0Oeko$`BM6e;<0EwL&EqA&%SF@XDceQBQ@Uk<19uSV zCw5oq2k{oG;-gj*4}8JlqgR6u8#NYsfM&u&pU_viCH2-+z(anD4PX8ND!<$2&Qrci z$wLdEhuG7@Bsa-Qx{C^e%nsSMxfsvRq~Wz>!2+bN(-}G$h4yI2mj0G8-(uog5L<}p z>?%eYP_dM_XxB;nrMonj5Wpl{HjQA#%;u_jjMx2bUB=)a`rhP4+<)AS**RIKED8A; zshpnFEfdh%Vb%zuAGj`89U($x%yQJZ31gjTO`gS&=;_&LS3Km#KcCB}u93~@^nLnA zG8-um7(KuDRn)0JlSEf#Gclvwt?N=&%*v&ynd{7+kJAz7uyLbbht$#W~ z##^$}3>K*6ZM*c6h*XAZ&`r=)V@8y&wW{X;AJy1z_Cr8difx>-F|pkx z6`%Rq1sTlC^g+56=Ab${y?AgZ$0QOMS;LR;DIsMB-NP-OuUsu(`y!#K#*Q!#ILJ~G z2=3QqzMc|M)a#Aw7%4P%Y?I1W1xZm%8>961IvEQMaHx|QuQ~cAUd^U^P+OuTGMJM* zs7?IBMz@^5yrppMSD5@j5|(F8I-eaURsA%E`2W8Jgcrxrt-2OxmG-z{Qo@2jNyq2axlUPE~z} z9c3VCUNRm_rtu}rn`~H5d6)QcMfQPLzbm?~H(6eW#ZP2%MmWGrM!Wqz3Y>UXf-%0fqDi3;P-(H_-R+D(?vV z33mk%-!670-->Jq+KLxg-^zWrmu`l8EkBZx zG7wb1z6++$vVHl1f!sTEO#8AI>d%t>8+YXqewBA+15arC$`|xsCfsjdZ@YD6?Zf|z zuXkY1G-{VdXJXsN#Kse2V%whBwlT47+qP}n$rIb=nSJ)DI{Vx8)>pNv?mw{ZT77l* z)lHm*rBucvEk?{ARK|kUuHlF&~ ztgV{vE>nU@`cEd8LuV#-k|IGjfTM0G_W<*+;bSfWy%~>aB)vy2WPug8@yL$Lb{vMiae=fCMo#IfB1`TC5HytBB?xl?KqW{R94jfH|K)3;0E6IJ*MsME>@ws>HlD-#$)>?!Hey z;$Bww1WAatXTi>xQ*^TAQ|4nJa|REH%p0bZrO2ghgFTrgb1DqGmT@WwLeLi3?VpN* z6T>gB{i!y)MPy7*IwkaJY<4s*MH5l#T!dPSJ)Ld5=<;_LIr<4wpt4$!CeD3Or4K&j zSoSQ5g%&eAU>PTSGlEKniObsuwm?yVhKT@9`X}b%yNP9YLaBk@L}NW);z%Piu?t#_ zFhGxizVdklCRLMSgt`Tdu}b6~ld;S1c^R_tH{p|oKZwa9WYZtQ_5qfrKR+8_+;+Up z&?nA3M3mm_+KQEjVN1(k&ByJ9ha{s)<7NwDNiB3JQMdxbq1?e2-_{8+paSRvZkc4l z0=+h1cd3TO<-;rM-+out`}~mK6k$=wO*_xG7cr!(8?O=!mmMZ?_<1jD(2W`Wlkij1 zE>b{i26j#=^{*rqi3~Nt#b@e}DJ&X9OT2&9@a*y)=;UP8I!ibt~+Q4XonpV27xd_NFCGuqWI5$qXdi+A4WYY`Lrfn#{#iJ7E50N@ad-jqa>^iCdX zjBAg}7^YzA&~#_&hHDSe8X=zRQoWsDDZm-m$bj*A4|$i5?4b+%b!LHGUM-zxT9L1_($P~m7}Vw_mY?x zXDR8-*O8Nth=9|&h|9*)JWL4{COs@K_%fqvK=l$k5Re=*a*81hlMY=WlP?)Gc6o*9 zJCf0=pidNy---!lTjnUS{j~qQ7F#*U1@Bkzr?iLJR_)g(OU$zOh>7VyB)a8J44R%s zmAH2t;oX#zA2zDG*Jqs;8jvA+@qc zk*YFr8nXuf;^ty%3-3j-r8D1LU;nq)SNG|xwY90MfTzEkZI0LOAJd#Yo>v!I-|mmj z$_AicXCrLVs>I<`1hThw=^-)7zyh~XxrUhAn_9w{-F<4lzKNLfmqJ1ua_<*3e!_d8 zy$>I7AmPKS9LMy=oRDvzKj#rxNtiRRz?WG;Vw&^35BriI&hUC`%rh|HPMB@nR8za^ zNPDkB*nKpx^7@Gjcas4J34a@387?Tw#f>L*2 zRyZSxJvL`u$e4(YJ*VW+S+U}M$|9T4dV+GZZT<`1GUT_h)H(7`;~MOetaTgGvS*{= zkcUO!s=Q!2TZmy8Xn^L6t=nlkqrv~CroBAc;rF6A8*Txr+x>#tOROcI9W07 zYL$w`(3&QQhhud}z7v{?2&px%8r4e?;yQ{`;`TZNXPJU_KpLfa)bnoAXJaP_Ao-1+O(cmRj_D)Q@s8g#nlp zSF6EgmQaJIm~6Dc)fO&(MqA|nwo&r?fdpMX?=CJmkqgg>j7#?F6zAiS*F8^S*;FaL zD~nx0Za~Fr?u;Cmv&d$<8w7rtems)~x7ZrTym>WNkYV z5LfqhKoF)9DGjsOhVn@@5U+dyh46UIu2d3FfZT89=yLtc@`3s1p-W9e|vx0un^lFAAVH;8Yv+$lG}N{vM5=NT9WINsoANsN~fcFk$GC~ zG`@3ok?^crjZ^b$RBJ8P2V|-#;s;M}vM116d$s4`Wh35v#yx#+H>#!y}Ka0xff2!sNW7v-@xI z!Sf1oA6L}tTAEh|u`3`t!jQ)IB_-6o8oiAxW&1&yeXMeuLNDW6D`R) z(!cT_zwmnG7 zQtt+%X{%#59&S^G$Ep2|5XskW{lCz1JSd{2aaA+ zRFg}0{C3yY?G;@ki1?g4qYvY0Fm+~!q2d~{P6_Q!0dP2n9$!i*d{Xu=uvk$5ASAdG zr`-^ritj?b;ol>BFhe1d)$PSwuF_!U(C4O%6s>d(ZYv&+Pl$}qB&rZN#q@GFj#H%@ z9G-Jv?NJou@()p+vPQcsG|!ZiCNxs*oL(Je&LF2w5&MAIGq zML*G+952hl2IS)+#semz=JlsEq5?VNflvj3e_oxffMOUl#mH9(Glqxm$~q!S7!?kG zGOTNVp&tCHHfV~f3r-L5{n=z{{)ki6Bf;%x)@unho1)9&-C zqNCLnU8UJvRLLP{8katp-Z=;1KK?Br`Yi$eg;{jD13ql2v)@z?sI$i>J@oSk_k#f^ z0Ji;;@RJq?Nhscgi?P3&rb zm@p&(x|Y4Du)V6)fTIC7eJFk^2DiP$ML&8SZi4~h=i-`Fk0F=wxL7Ha7*(Gk zz6)N-Rq?zYg{=Jjv6lHZ-DqcLa!{tdP)%%u&U6(k!$gt1^6^QyIEu>j?2^7gK;^+k z{l5_tfvG+7N`)|8XykWl#v-jvPT!qD^h2)f1BPAUc93!mD`zgE_*dRu>ZMaRtOezo z>ni&;Z8L_w#)A;@bG{_ppExX94hz7Q!i0EK!Z-MT@nJe?I^h`qU=}m#|Ablpn-BYs z5~aAZjP(E10+Q6Az0j7hzkAkXT;ge0B;|$e)WL-iFo+E#k`rqse%1bB(g^)Smt|#w zxOq{{jVf5ExuF^3p(VGdh(6R2fOI2Rg>hZb6ryt5ecjO9EZAfFG)lfElD@-WyZv7M zymh@n@wC~1ilH1fZ$LZnDslq^(WP$$<{PNnGZFd>Opr0tA6^?X)0B74SOI^Y@53ZReg zWxiu?^CMG?I%y4CBGrukrDg!IYbM-;hBKJA>w(s|+sLt)^p=`SbDi}Hzgb};?*{YR z^F*T#Eeh2det-pgn}6C@@H|>SW}EE51ZZF%S=KzWR$ExwT3PVP_5yXPsugsQ0XR<1 zSYdXo>NJ0rIy^u@AftNeF5tl$!4x8&n?26Fr>f{G(zVhx)tZ`bb%#4ZhTt`M@?KSh z&W|S2y|;(q-gpCq4FX|D@~7s0M>=U!$^QwA3MH36K@b}d&GIX<8g@|ZM?EJ$!LsEj zZ+dugGKbDtA96xq2n(fEL)GUi@lz#5TLvfhGz`m?imLdEJqjNTSgO#8@RI7%ZQ@_H zjNLYLnz})l>(y+Y@1#Rg_#23bFp|JrSRn1yU6@{EOsX@Ca_}eE$ZIW9+Xi0-4UJqV z0;l_nW25*j>ITO_#WIuO*C#A!op6i=6rK*-JPI#?i@RYTk%XnTkf4R*wgD+3g$h4y zPN=|pX!mbJjrZK?_Sie=g-;9Z^QRz`^mSf06J|PrpJb#69DFIdMHW2OB56#^BTN-5 zoXj9B6ArP*6Fe@BP)f=qn##GMc0w_I3Jx7mh9m4J4M07Y58NG?M5HDI)fq2}tpY3)`Ank%QrP{XA7YtvotHJ=bG;loQuC+jVd_@stpqVr znG?e_Or{)`+nh;}BOp${>TJ|3a)9&(?~-U&aDD3eIcO+D`Ge#aE=(}qM#Wgxn1-ol zUdeYPNWxVlZrZ)wcN0pI6MHDqG;@(L>L5nzur1h6>)dc zssQNfQ@9}bD%DpXZ%WyceKnVlP$i1p?Dg5R+bT0lWe&NdW@Ff{DS{!5LkH*S+g5G( z?%-ef9!Hg==z4-tXZrNkfISC5GY7iqDB~W0UQJJLXR@10))*7b>Yq9%?d#dy4oC~(Ly+l<7n)W2z`B{w`0yC?A zx{)pSDUkFN0P}nVH-%L#BShA)x#M1_ly?B7Frsg2S9PA4b6^M4oX$v@;=wAJFlRDz0_aCp11;h{ zesXhBPzzX1ZcEs{wM0f}&(R$Bq9}sR*|%_Qaj$lv)~N#nu-#7|uvI->tSv1$O3ZcJ zwIGvxRB9}!Pbt`tDj$=AQ)&})#W2m7h=~h`vJ758Q1x;^xG93C1#n^wchvD^SmNJD<64`-pBCNBTET_75iLEjp^hF z&gqx(+I!StB-}mlIorkCg-WACbCg-#^4Z`Gp$1|1VkEg|l2*f;$F(NU>X;nfpZuny zekFQeB_TWBoddJnOXd#$0w?7dS5c;0c8)cX4pTl_uZrO zcko8$B>G{vY9_e|<&7)PPmcz^BNNSD^5V9OLKC~t8FyRcbS<45W@ZJ> zfGpLF9tXeiyGx|QeXwQ$YC_YZn4%9|bu}a-ZkXo0+Rb|SW`~eYc##a5F^YK)Mi_JF z_{af;0CT%sJQ$4m>YvE{s|odUe<@$sRpD+IyPSUs+qv=AQ-7D|yS7MFW! z;tx2P$P=H-8bAv>QZ}*46ji0d+TX*BH%|vVo%H6|okh`wyk+ zLNwExJnSu~CQz8Ibp5pP4jJ|M0|$iNTGkcd`)+#j0rgbWcFNd7ShaEMn2OaMvQSjn z`agr5T0l_pl6nY)e!lY$mU>nkEf&8!xMG9vPK~rfzw%Ee23$^-kjrWvbpy$4K<1k` z2&2GVGTxraF%o;pFxOl=>{9WlMS@{IAZDY}rPEL9mW_U(q*WVAn^@GaD>blUkX4&5dKi%Z z6L-)-o5o3-VOhVR6^1=Ds#Sp}Fk{fLRfFfR)*x)FN@vK%AZDx1#Ss2H@hYv%2*xSp zCRvkV1=@gLBg970Lak6chN~2}ea-{aRSLm~?5R5s(dF>p`4+d;$`>xQ_(_Zpv=VvS z;y2kAy7jE^9EHamvMlN3*>mFMFqT`#bq#S%d>?^iRLJjANkGa-*`a()Zux4^QFxYf z!pcBcM^D#gsY3@v8Gg2Ld^gx$Rq$6y=WOIT%t8p+{FOjT(-8D=_htNKJura zLh=SoAbZf?4JKsIJTcDG6sXa9i^oePXULSz4qr*0lo`nTmq47x-ouXklD5*MScris z3i&9SP&#Z%wna;d?p8r8g{_czKr2o*u0X6%4d?!EXR5n9ld_fJ3+HZm^_0}%bVOPX zrcw&#{Xl0bxI5FMI}_}^0gpQqygO5rQ#+K27 zJE$#C=Aut)kEoN*WFH?m)Is9+JP7Wlw;72zIPfBWF)X%+>qQ$iK%ofEmxObhb})3T z_(M<8_f=9erUo*Ez+9-j(CE~mA=XWnlbfX_Q_6UxU@jjy$m!x6Sxf9)Jc1(C`L)27@Q@o}Zk-bz7}g?7~J>3mXKJuSWT*FeW5yPhZB3VaS!c!MhpACv-ARlK={^u{ytX<#j1U+Jkelx{GfBl>_$?K$> z{W;rn`I~lz;q#3~t^maPE*lDA_fYa;gr?m~C`C=kjV{2i;nM?ZCz2@A_B4jw>D7ho z3(l7SxZz5&>VF-4(*ghXEC;@@7pBs@E8>3@lU@(Ju&B=jxn^u_C!BQfip z(En)S`xe#sWR2`uBJ{-^-U+!yB>pf2gT0ZH{GK8HkP3A821Mor-P$I-xPF9;zsTu) zNv(Zpr|1RVOi=&pdvkiVUApxxzv+2ts^^%>35X5l^KKuY`B_$q(gWrM9sgJP#GH~= z-&=KFIZPfp1A(BbF9wtUs0(MOtq4^A@PAFV$HSJBE);dop$a z!L_&Mwv)RRHx5_X+D@7ybvBY^6?F^=d;6CvBjih)d|>}XSR)!QUit9CsegK{?eeyAcQY(8O?#x831zz$ z<}W8Vf2sso`+^bu*5dpI$|M!(B%e`z$nn(3!%rIl3a4vd z$Ayn2^Spr_t^}28gS0#^byB~nsx&UQtdsCLQBl#$PKP;*wi0ua#&OJfG`{O$eOS65 zWAa3z_;MSV_t(WH#$o=4(c4~G*R8gqZ%4*g|DX82H1@c|<-)9p<2MLEw92ipf%GXr zMz&Y+_Tl%)urg1Mp4Rd$H-hdIhbMWd!@^slm)!7Lp&Yp#2|06H{f~^%xYb;P?EDPG zwNt^E2#&saiA=5R?NUrx_m&Nxiiv>VdgIaex*`e8mg&<-v_4K>VlR#NUbF)3jwV4zmeLvBJ8Dg71B5S8X`f@6TS?+*pN5%Kt#;Jc(md4LY_wz&?{{O*^WA^Ov81#1 z=tVSQJXXLPRC08loMc{^qE{+~tgSj>ldiT74z*Mtf)c&U~qnX0Q> z3#VY?WL(%xQM=hbS+iI>hEtC2Cpc{c?X!zl)E^>rttij0^7%>rrRf>zo@0@{WwfW% z!a%~ofiJ-s)2B$U>b&Z1$Wn^5wu(P0zO)d zR$rk&#EyphjHvsp``VcaIFxo5v!b$1Bt=~^uG-1UJ}ukTVmDMIU|05pFch)sW0%Q5 z18S-#z4U=ZST|?$d4YIFbwSU5ohY?J^G0JR+J->3O=F3MMyP3bTq3O#NXySXXrqiw zs`AuAn`tdK_UigVbTL}<1efH;D}N_Z8d2J5e*;RbP;_P{wsv(Me3qgd`e<}+6;E+4 zT8;1xIt}s(I_(%lXp^MnZ1{oCPm}EvGK!Y|LqqR0pfZWeZ1kgLZ|jl4zvSw<6Ii1l zG8$v_y86Pc_@%ey_5>Mv+Yu)eiD9M6=DPk|e3s>*JF(I^dD@H#qf6~GDEPJZjb_8Y zL4wTMb_~{8Y^t^N@y+hw&w_Yn!Rfo6S?@aPFW<(ov_Cbl$CvhE01JU&REYH zeWSET+X2u4w5MnW%{B#foLN+}Z>)|TNS>JXo<;4ei}r7hSwRfM=KAs}6@aIl*a%t; zhU-5l-xx~%WSILlQthp~SXYQ+5K?S=f z0xP8P*NC~nEoc6v_F&15Y0<0jb+97Z4$~2@SpzN4dUzeu$UKd6L?epDD56TqQualQ z*RVo6l&Cz3rcVRVbioZOLl&N#HHzt~rc&L>R5{|C43jTXK*Rq8vk8MC|Ajk8Pu4C= z@6xI^AkFdGro#xbH;nxQMCK~QXZ&I?ID3c~9*Ed+bauqiqZ5Y<1nV7Q4{94#n8|AoWjcN=KIb@|| zzX^uHUa82Kwg`0`Ssy#@4-?->ldA8o zXG%~E-dkDideS%T;Lc(gT<~@oYssQ{r~SlmiITra%))VL{B2livoGK;o_vqyF?=_{n1X zSj6n^5m>b0=(sH%K0H*m*gAEls5}djCDZQivlZ=AzP`9+y>})p9&C_&l_X>_i=A$k zim*J*s^J<88?HB8WeW<7$1B6-zNLmWj3ra>FKWC_=WS~p=IP%(hI#dtzz2@|?BMsd zt;T?s_IB8TR||vj;cNcj~P!1lkP(@*%2!!^VdRJh+ICb9FDrd6G!Rq3ig zv$RFnSLXWQH}MR#BWbucKT6iE3HZjo`aHNngW|vI7YNvljzNPlIK{#nKf=GFnvH*#~cEf8Wp-cVk9gTb2`)Eng~p`J+2@ zz7Q2~qvokafUxStF$#?}HR|Z4h?C#62JH%jSRx}0>g%U5Z(5o;{q-=LNU?DX{5T7F zaS9OGhi`Z$yJ$zdmg<2uEZZemEBs7vl_iBDJSwwqWmB)MAHB#)lk@B9{|i03vB*Va?)Tpw%0 zTKM!S_K`#5-iZlAUFOOX%A7Jex=ubvG|WVYm)F+bm>L;`)ufeA1O`rNUHxo)8gi8y zlhv>3-upKz!*FMafC@l{-kG8Cc;2zIs(z&(UI~{&(q}iUG?=OGu zf(Sp@mY+|055RTBLdgl{Daa~{ciQsU#UPobPeJ&#UUqil2(1evn1ajUjiQntGm3bZ zC#s}!5Kbd%tv=X9FLY==%ta#t_JE`^{&6_bBwSlMv1}b?tEqaOWi}jg74RAr4E`d- zW0uP;XzWcki$C;+vOAW{Jp0*s8&vzns|@i8D57;q6yfLhn9#1K?()jLI1ITB^>qKM zC5G--1&>H{K6}QZSf3BO}73+_&zUsqiY3kc0-p%o?pW zyN^C-2!SoK!*d0=%866#82+*4dAomtGXw!p7Ok_l5{9|FcF#V}U(Bbb$Zj175SVgT@kAriZqH*(1zo#%OG)ODRc28xB8$%a6U?%h@C0QX4s)EXwOC@#VgX>3AcIdQo4xS?)R0j_LX3d*QTY@d1yHU zi^9KdK-k;BJ~WvJ5U0*aAqJ}b+4qxKL({|AxrUsh1A*kQIEmsm)NR)1LhdQvp=Hg= z0ff|m_0Z2EZNlQ}80q};gv=8(af-Ekiu`rG@H2|>{I?2`$)|i6)YAF?ekwBS=S1PHUlxE>=*H}Dh-`&U<$VX)_1ztnBTfPahPgA_ z*_@g@OodMBTzS}#{i)8jXHJ{MGcgakS;4<3% zJq#KB>*rld1rtPKq>IN~#JzIZram=GzKM=ow@_uIJl;W$^V}^gdm9{xFIp8F$M2{G zCv$VVN^ZGLg2w@uSpt_{b3|Htrs7)|@a7A!Vgn2Y+Y*(_#j6_{rjscV;h~ z7aZZ5-_*WRtRJ*4cq7xu7mL;|9oX$nnjx>qjah?5?-2`o^ax>dHD^w|o}rgmx-;oZiM=-@3}?AvGlTOiuVj*+f0LIlg0?ALzwn=9ACR7_T4dN3egg z7y{|_$eLeCR*x(C1#-YQ*x}80;Iz*xhLQE)`7SC3gt|Sv!g{^dF^8yjv^y^>8NX)k zJPmRCp5O%J$KvsKDW7?EFzmlLhVWnwuzSoJ!-7&*+!y%!@lpw#Mu^|Ggx+ZI4gp+0 zJIyrnV(i_sN%Ih-7AS$|AF+!HXW-e~?l+0Bht(LSk@qX_oWoUCWzQMdHuk1OIBp=^ z*sH2vQG0iu3L6&9CxvFYN$2oB(=H4#oRh4=JBnal6HHsKKl8f*X16+{_Jycfn;omJ zaqK%HuT5SQDhM~zIEJxLhx9YK^!pf0w(GA=sx|xC8Lar9a#52hKL2kQTy*I>tOe4K zA2|OUW&i(%_y5*G@&6NV@jo@tC`FzBie=_qNcO1%QAN821xJGwR0H1^3S*FgmSGDj z420Ahb>g-uS-Y|-23_|hi!Z(HBixN)-rlMbmz42J^E|%dHJ#?XoYC9yC5oc!q|f(T z;>kX^Z43qQ&=AEqAfK;>wjXm^9n~fY1rcAfravaAe#Yhg1dqB2*C)rb?e~xKOp7Um%Os&Ra zq~((IWJ7G*KyR+;%*wvJ$>Rb%7(I2(d)r`bC)U`)3z~C}-;3*fN`n=*^GQ5LQb@~y z2V+DB6Z3NGWw)y3c6s-43sQV$E0Uib7h+P*;!v3g%8WlI8b{NvnhVB=L>n6ZD-!d%+xLX#)rt|bMYuiKj4q-Jujtz zXMql59SmoAcs?g1?P%jA+Ec^;GUK%Wf|F+ac8~u1D6ZeY2q9OpyY$Fhc5K!?!G=vm z)Y)R6W|b2_m3T5aJV3UYzaWXh7_;#^7>IyzGHsVai5g#pEYY6$#wuFp9Ym5PFYkMe z(#{!ByvkAU0iM<_y#0-6bjcNO#NRv6NG}#Je-u4`Y#2^3LNp?b^+`)8>86$*uQs zyueTDm(_|Uh|nBuj$a};Isk3I0k4k zte`F&kgSvT$QN%=?pJ&c%xhY74rF$#&u2SS(2tuGpiJ5M;M$s^Yf@V=U4dM zXp_Y)W({yG-Yzru(>Yx?CoyQxR;DbV;1J=>)d^efPw5@krDZg9G`PFoh1E9G>*{%N zsDt0)z3uP%;^KhF@P{Gqq9{gngR_jTkPz2|o_^Y|`EA`C&I8d&GpTF#G}lHKo9b46 zKY7&WE>EVWjB~E%YN?U{_$5hvTD&<`XFJ*Ftxmi7fF=StjO$ zTZJd~iLJ88fnW96-?@9N6lXLSQXZ!G5Ik<>v1v>Vs?$rk9nFLv(alL>>$W=E4kZjZ z%e8fMF1STMw#-^1*0u!?*-WFLE$3;Cboe{{GXkG|)tA((<+qtBf@5-O6={Db*s>eC zx@*;KI`tKSPVlUeve)0TU7K6pNROwxgkgw{RN$1$9kW!cux@v5zS#A3&Ak_?s4 z+9}<2yR4Db0x2%N`gz*S6uP8j4=)$8bL7_@5H+I>i`9PE*hg1(VUI$E-`wedtTv4l zmsEN6oX+YNIhX%2$uh?9B5L8E?BA?k;n4Z?XH=Z;YJU)uhQQYU7yeZD>l+)#W=kzI zy1Q(kXbMNUsv=K0mDX9kh7o8URmc5eF<3Wl5tQNV{dQL05gT0v5gngUUj z{mQH}U_53i4Khg=`xLD%yH7}4gqL?P2~h)ISz#hvC$I7EJk`f)DaoLi7ozK3)O@&Z zK)2uSW`2ld(>3LJu&sGwa_%%mN{+4kaYb^D??>>x;lp(n;q%OQlD5GFz$%|W8mN+%Z!*19A@hv`)`$7it7tOox4AvHMHPg5(Zu| z0^b3}p&0cs1_SQ*lkwr9cGSWmrd1M9e_JqZ+(&e*(rSc<4cfdjl01hU*0wEjYHr8y z9-u5jszphg*B<5ufq`{M7@8(m2ccF6?K_D7g1UaIF$OP;8Ao6Y7sHrtOF5YY%ozV> z+Rny|IUQLLUvYJswO`=T3}S!xy60)850a08nYV-k+QI>^;efEgH!&zHQ4!U+r|Sgki@!Xj5bhorbT$noTAzF9pv1zpA7c5%WoxN;|LCbU{mkwRk1jwCV6+40<`<|!;U+!jwNFCnAUUT_QYYOz z6Lc-qRjbcC5SB8sUR5ep#oZW)1L(^Mso^>|#6kFyR?@nNk#yt5pU*3kXkig?bQ-vtZEXFd~e*|z#@jONUumHNV!biqdl_j z8)kMR#+Vq%w3QL&)mHn)%vZN7MzlXZ*|_}CGJjCrZBS-pjwHzC>fPd}CctO)k_Q~y zcv40Zyt2XE6?+o|v(at~Qz?|(n3E_L+?cagcrz{2;`*X@F&*Q^YN=F)mPDAU0tR_DKt$3*@H6HNmvYSm+#{FdJ`GdMp}&txL^-$5Z=|fGw4n>u^4m21yrIeQqm5pl{-l0k_7BpD>TbY ztsV8W1-CLfVZw!^Y0ObGKkPR0R2xWe(21Bb&9X))N!Qn~tak=2!6XqNrgdRKt-=c! zDx>3El{nHOe-ZU9kbF8t7SD5Kc-xC{r;}>^aVe-X0;6tNK9y`|BO}QWkP(j07+?}b z(6tUOGt!~OFoz$ZMy=AhWbCh}lZlfVGwb}z4WPAkK`_@zvxzH4Wb3dSzflo0Lz;Q3 zjyAap&prKA$3Bg8B}*q!*~69umsXj=pOS{7UPH1GlbVi-s|pUvAeqAQinNewET{*> zbI9Hk)pMdOJcRb3WT%!6QSQ_Wyl@O_&Gx|LTZ>y=2Ua>85>Ggps%Vk;@cH5fsV3uD zwfL9Brb-89{3##TM_YBE;{H&Fe}as;_^?va0dr557aU>tOiY)48n8j>+VR)&A@DO>))?#MQRQHflF=sk-hw>*seFlCApP4^LLVXq`jF#L)$ z1TAK*jAtJ<(8$?|%>etVLDki3X3?&SjgE+B9vUGCh{GsA+9~nWNXx+=J9;sv%ZLbE zc3yYG z!glH*-zJ-er9jv$j~W_~;17akxeD}GBJznoF2RUhwdc{8jDBt)y8z?Y8mE3WPRe1M z6%`$%G^K1UuP7pmzcH-P-8Y?3ugY0>!<|?S({({v>4Cly_f2IJZ)Za4telS7x})+@ zok?aHpU;$LN_Uy{yWB)WFTh?;wub1JD_O9xxrSiS0-Bc8FML>$=^Tv&`zGad3#7cP zomw@eWC2Z0?=~z~E%>!29M9bxFyy911M+tQ{8u?UmA(fZkM9n6vIE`wr$*A<<|h+E zbDC;Zvm0-JjVHi&UV-~?{hbb^BKD5{cVhX(B02eaHc z(4Ge}*hIL}A>XXfk0u%L`TedgG}4sMzswikA0@K4h4ew=M2|73yVBY{9}mO4CE zk60pPxF4q~m}*>7QkFcK?nA`+Ub>O74RLEwLf<6E3+0lTRY>aSBT zvPlvF`|{`#U}+3c&r zLl6=8Dx9XK$ZJ+SgoMCOHuN$a8OR=#B{WW|5M-bwS&sb`8XmtPg zt@Xy!MWX7pI<<4qteRz{~59n6GXSDW_u4IaV(7WpZ}`z4!|-_zg(-%b;cF zjZq!lPq7SsfN)7V13JoaVl@{CdJ5u@*ULHj8YSpNpA|BLq~|{hu`VB2PJ`U9UT@WgSDWsU$KK%FpWd3qJo{F-H7eH~=k+pr(DFtVu`|wg=f5TH0D*>kFXaJ zM&un;oV%5_C{eU%T>r!q4nxM*?UL}Jd$LD810|EbB-R$KHFnv_zZ4a(jYkcr0`W3;i4!|+DmqKZ&MIf_QB*j+P=rt+WI^(qVr6Zw!mZoMMF-g1H$<& zt??i;UNBLXT%DV6!W>y?W86qvo{!Z&D3arEQ-zUVXU8hs(88!XXYQhY@}mvAMXb-| z?f%!!0IPkQql5{tj=lgA{mRc1@{@K~_7Ql6G&3Q)83?-+LEvmZdFeFPn{Wg(<3p|4 z5EFi{m`EzpXt>up2iF;M@EK; zT++fmElR@EsGDnq)N^tiIrf3tmOp{p;S}8FI9tI?^{@wQr-__mxc%)P=%jXc%Q-?)?}Hu{(rk6O5A_H(hciT zIDwrQO73N&4k9vQs0mH6dMI(MM6DyNOCR6gjvyr19JSFks&ta6D@%p+M72b6Z`!)N zP)P4zj6h~?S-Lz$nV9MsyF9UVOe458FGLE=Bo!!$c$jOh{X{M-W*|JUrctZGx;QHu zXkUM1oYLN>wN@r5`Bxa=9PIWXvHC*g1~hm3z)lyRA))7ml;e>Tc>vKJ&?8Fi33Pjx zYLC?&hJA$@?ybNAt(oh3;NlhSDb882m4AcxK+g8~yItHf%l*LFg*Xp6DMm;g69N<& z*hd8(gMA$TI43>5{n16is~h+P7xOMn@Jti)E~3rMWA51#&CV|xtZpSv29Goh#AL|p{p%;rNV8raG$Tr{r3d)Z73UX9T za)gf02@N_C(gS-+@(&z<^w6*0L;K6p2hg(>lC;2ck~?^%a?Nta&>rt=iBWw!rT#yR zy#;I}&AKFN7&FtDnVFfHnR(32%;PaLGrP?mGcz;WZDxDS%sgKI=j_?Ly1H-mq*AJs z%F3)#XJu!75nn{u@+9m<={&nn8J(KW@Z(&9ADhK!_UNzVG1%bbatVxf^xXup%Pi<< zxjzh;O9$Z&(t~Y6t)WD*KvHvX6x8r|WizaAGk#g!;MDub88ykZ4a#v*69^XtZGLPH zy!`^s#T$P=*aASf0x?YvnBGLv-z-&ooH5umv7#fgjRu`uQ$(s#%4|D_;NYi~HL_)H z>%S!Q*eMj6_e^QO3RfHM14xSkj8f2SjGb)rtOWqOeh7!(yiqH$gyYc#Uiax+39wTMlixrCJl}vui6CHPkV%(e+4;lhb zWhz7r4!c?Wja zkYgS4;=6PQyZmmO@JCN% zP+w)RSc}c)np-?#RGs8@^P^FYai3)LnFoWno7j|&Ia7(HgbG_VIhtB#7@a!k=u%>u z-u%20>9#Yyj&-Pij%AXkny6-9#dhP#kYS9nH{{|NSwj{roBXs1RPCutOb1)2zb03j>%3+*+i_UZA1 z>tictz#j0F7*~WgNt9a_ht9m+Bx3zceIc1il=y^%yqYR-cQ0trvsWMt>m1&9lAQz1l4ILR+*iUzVUyxI7$)Hhfs_A zcOQrQ6!;drT%0PYcNFW&jk>tv6ERfnj;&N{a7+5(g-_8W|MYCxh9ZuMNGSf+yBS9H zI;$D^&mHR6i_L|c6dotdUZWQtH<+M{`!sg^g>5=2$D)YumJ>LltsSXs_W0mm)Bi-y z6sPlpYitqrS$?eUk?c4l6ls7i?E$}d%J;MOS>6V0J|GonivfFr9w80}*xmngl|Wg$ z?;jU@$TiRPj=uyK)!T9n(UsMDv$sNUYg-RbmL4DGnP!%5Qy>@6v*xS+r^eN73d#=D z@_@s#gG|2VjL>*DpQz^6E$!mA<+g9gKSI4qdb zm4u-Lewkz3RX_8wvKAO<|9z7Z$@QurAfcD*)QJ|7%+a_^jf+Ul{TjRe>`ll(ezp2c z?vOKYzBGQ=tIJ6y?{$fpXomsxvmm%-bn8&+nGDd<^oqER_==D2_>jqy4LIhG%mwgd zi#|;_c_3Y+PL`P-%2LqjYmgl>!=1zH7LNu_vk5mj@C;6 z@_2$`)FOMHyIU7UU)KZnsQ$x{5arQ3Vw0E8J%aoZ{DaaAuOz~8sjwfPJ_D()E5{$}*o*#ThtRBT0=6t<|@y^feE_qafc>JO^3LouCl zJ!VX?|Cd{tHLa}%^smmi)AojhWT*p}pLNU}~C7>78Oes}6!ixV=s zy5wtWGG9oT0G#4re3ky5k|f7pDc|D4SojQJy?p`6vkc_#deTf_M?^5()xh_%qv!;$nfmcGfo&_uZ)X8nIae7WEYFMK$x)osN1(x~ zB_m&;qDr-Ry}@b?>7#Ml9?LSw*b!A+-3j_dsby|CP1c7rOH)laf_*Si`78RETyI?b zTZ@`jV>~kDU#B$tZAbBUg+oUt5Wqh;xTDWb0Td-(%^m)N+{;40Z3x>4G0?jUT%`O6 z{KMpxdc>dN^ZbPwBb_tu9rir(hd+Hr^8++L&x}$m^U9(xik+S(dbd5_U!G>Ap)8Hf z^#yY}%^7omvIH9^0M$no>=qc-56WNSvvpWi3=nmp6vE(uwBSwumw(wQ$FFBwrDA}9 zSS$VC@!kIpmi~{a%W_}wT_bxVi~q>5r~IScw}}7QZ8~5}ffk5CiZUb&A&TnWH78^z ziU>moLq?2M7BY6ZKDBc`$s@_7V^itbxU^)@yb`ozJy)StEC1`}xL{{h$H)3=X{(C= z@0p-ofP;DcswwA-lE7|P#`b&l(+B=l3*+CTh*ISU_2;x`1-vo|DEkygUG$a-v2M~x zB>;!!P z7LA?o=!0i#^tdsuNE2l~2H$5Lbi+7fwn%2|eJ+9_G*k*xy+~d%KI&a+Y|R}Zbj7F- z>^fi4NQcM|`(0p5aD{`cCr9Mb;9CThg2at4I-``Qa=$FRMU#hXv%UP|mF?Nd<$1fg zje|{qrsC7|bhRmzC|#Q_?i^~UxjC9&bye0XJA9K}>Pc(n38H1_2=*WM+!ikx7q3jC zlcIJTPV$M0-;53pCL=_mo9I=g9u~UwO*M?qO30_Dm#5pSth00L>x)|`zLn$NnK`+a zHZ!yKxz1zD=~H*9fR5CznmAms2HVgS>4|BI#?DlnLzsbagJ#~{KM!IKFtpU^EgGC| zPu8L1p()_-2^_TYlDT<6`K^nC(ALcw1Z+L67L`oq{MB|(qzDubEf1_|>ZY{D`Yblp z31_2y_^^)RVeD#qE;C8l8HUan9teHskuCI@4xW%$ql8PchqJc28pVn0ZgkEuyC@?k z(S%H}&&-r{Y?^0-+lF%s$e|lmldP(aY`H}U+jfi+IU&mK@$4isF8&F99szv6Q#|yf zQ0+pNBy}<(tK+8MN^k>-&h>qgd({jpCR&S1nX@iq5_0sCPPPo+ZCKexGE^&Q%q-uY zSn22zj8{~KgW3?c%8TDsXUr7GzsbR4W=GP*lj!gloOB$w zwI>`ib>X!%G0iJmthg*J5iHcu$>>@`VDq0rz~B4XjYFS_BP6G9$lK0GN1GjadfPbE zb2(r!*1kBp>I%qQ@GV$*nYRx#f1v)B#lSteDTd)5A1Oyly@+yu+pV~_4ccv_h8nGA z;+%AJrxrSMF^r0Ev5yJiRKnOL;bmPEypeTHiN9A_NX z^~pAO6(qP+(3q>`+oM2Qbw0`DnctP#CLW6Zs_P=kCQH8<{813zdO! zfB>%VY8ETmyL8`|hG8fKD7}NOmwg8hB}Z{9jg>)qhpf`WjBVOkr<{bT)09S!P`K`9 z!A{L{mey7wSepVlf5l;&Mr^i1xlviv3<@Tww|3w5O`J5Q`GpYt(OXC6W3U&ym=cDc zLTTp8m5ti9VyA+UO#>gPe8_PH_NH8v%+tD5RC^G^+}R#H?%Kq7rG^ATmSSes>8ya; zl4pqJC8?S0Ar>92lHVQmROqLuKok`BYb1`#xV zpF%+Lvz5RfGry+d78h(}-=;5BpEx*0Cn*yxe;EO^e%3=skzj_?9p_3~1a87z*KPGC zkKgOw2oQkDA|kG(aAB)vhdn-vv^ShdtUVX2pjv)GW z11T<|x>&>GX3#x-fMH+?JAGD*6=EJaWAhBYwUey!I`V*tR*I`v8a}iIJmTGP$-cSw zFdkRsh;Wb&YmlEaU0x3Vce%4Fb8qJg5-3hKxu?U=ECLI35z{#HEG-E^WnNIJvJrNz zI9S&?T?mFg$nb!ux`Z;iA_FnKF_LP}QS~@^aiCb>n!cDFe0hC(@_WuO>Y9x-FM?8| zeR0dTi|EISVdh#u_YO$aov$(2x}`c8q+XQpT4fzRZ@4V;M&n3a!QQv;b8Gh? z)|5)zSW(dhry0XZyX$;6OZQwfID}zrW@glVAg>7qQEyHZ1cRu2VuJmIeKLHJ>Rfxe zHE?u0Io)@A(s*IJJl?Uh2GURfA3?rY(MFjyO$8zzuFzA{{cnHzN|=GsB33x!7bS-) zR)BOvCuo&FOe86B=-CkoR6@?4s8QGG1uuVkLce!0+&LSNGj9dL`Bej|2EjQ1u$@JuMYN7dNJ_&rn!F_?;`x#I|qPjOMI z)`S%(!kPBMTx=P;f4Wt~C_w|EPVqRrucf2>N2mAGT)ASjH5a~r z`A0C0Mi`EDNT_nQuEvZVr=o$C&8cC9h4)uq`NWcZwWU4IPm+0(PG1$r0= zN#M>t9(@|}JX_xXwb4W?wEc$j<@3t(wb}eHZs`ACB7y3Ehy_Rbkg5aad^RgEYVwdG`bMP_vK+DnIg35hM2=t;4TDIA%Acd6MN#eQ z`8r0N2nPinwBjodfxl|>-ISH|^nm)B!rC_;)BG;pNx8f(Xo;J}gwxq=Pq}v=IiK85 z9t0UjpRVUt&I_i{lLh zVah^_@4cP36XFlXn+=cWh3$j3tEqyk1tiZ)!>_~ZRy6lLoKo;`<^y;6nPui9_{e`e zNz?O|M$vybDevwNd+z%$%FpSfWv^S=+;=F(H^}ANO5a!Z&s$uAsL%WP0I!pl=;)=1 z%yn!G+YNl|Shiu(h^^siSDMsg{Q)W zh-`-WU$V%_6Fljnx55)GPC%!NNrcv`uf*lrfv&K%!et~&W)E{}cr(()Nn{C!Wc!}- zw1T_jo-S!Q)+Yla&Pn$Q5nw(hpEL7bLf8S_HUHK-v7A4F4bWht_&uQbV7{b!bMEp! z^PrvLu(m|awnci5vCnw1_s5Ckiy zSb0w=JaAkwYXzxdEviA2cag#af!zHD8EUFS^hB$(j+7@IPsU9$YmlGsAo9`#y*All zbr~ODY9tY6gHB4`vy;CbYO(DNKnjiOUCi4Kmor$_q_OVPH3!6*iaB;jK@$RUEooB3^7+0Vo^VMQKS9CLHQFIt2CexH^(A8&ig`_7 z2sTsPG^c=-}_st%(}m4$1cn#_q$_x`4O zK~3`d_DQt+lT^Zqr?sii^)^To2E}) zCjP(8pS+z@nUG~_n1H|7-%|(3I_N4_&Mc@$bj zc`fQLo3(%Y4A3oY@!1I76qzt77(7+d~UeK z#O3`JyJDir-B>Cq$j!AJkCV*EYfE3Bfd}^U(Zw0w6|w`~ltCwsJdSqG)B(}o}-@P-i zFyeInzJd5a)CERxoKS+ikP!JgNXCEawiBP-a*H*g8XuE&#SQB6TV_D z!{vgU+87dPPsWibidKdF>EVEHkiLzN=YaG8@ z7>lm&^kkdMxHnWdRXNLPxDx41=kj9JPHxb4rNSmcVt zf-QE1YNCuOIF#a9%aV(+wAas!Bv-AwmvXnr_T14jhx@_S!iySLgNDx-3u4V?AowEB zp}CjEyTsnYbUOm6i;CA&nLhVvKIP+%0uzRAu2OyO0V; z%*L^jdMsUGETQXjM&Ya1T@AojY;twAJ?*tPYo9vfFuq5U+!Iw6c#X1Y(e){$&WM&I z-I$iO$)cQu^28?Dv|=8HwaKDL#+JTAWURQzo-OqoQ`3PTh1svB51bv>;m~rhm5W4C zQd_s~TEkJ4nBSW+aOmn3;5H?I_E{KnD_1i$ohM{Irxd-&!)I_;Te7m_Ez!eeEB~XzBHdc=LU-Ce@1RXaMYL zVb#{c78gR24~3OmarR#e?j17oP9NCvPl58X`BZCBqVp zaC8?rdV%$+2y0;>brh(f2)hU!p|c%!-KbqbmCE^n$~oo@e5RNzF$Wew>AXuc3pmdB z8dAb19srRrxBU_0L61EWs}VT?T85iF9DNSC`ck}@wAF+D(m-^GO{RD>ZNW`Vco|L` zQ@9=J(@=Q*+LzgSML{$2b<*-SoW8iS2v}^nqjM8Vhk@c=kjwXy9anQy^iJ=I;WZ`# z-+F5or$VKtITNcggr%RZD6B#=5}cKYjZqXts+^t&p(yRrI8)nmJco zaLxR>Q+Leun2fLy)dYxWnuK|y6!^dtyjAbdUd$DyQUh6dffGU>-^w)c0H``@RU(UP z1zRAennEAL%oTBosEbhOgiXcP=kz;muNXp$F$=e2zdc67DrC|pSiZayE7hXyDV)>B zPz-6x?3v+Nfn`OIlSZQnvKR5T0&?D<7E+d^v-WPqND~Km+8WWU>4pg;`d~eNP_X09w9%f9ORR)S@Q1pm8 z{h;*pR-$cIwD*mE`7u8^PJeRHS^2mu;M_N633XsMB5~zkBsC^%G)nMaxX)gKd~p>l zFB08j3cUuOGv##o6iQF5kbb%&H$vghN|0Zy;n`K-M3Yn?-A*p#u}X`Akd z2F|Aq3W?rwhg8Qgs`YlqhZ0xFov$RP?~`%KJQ&GQd(==gJuQkj%n$=k*) z2LiY%ROR&3I<3qGecV@;GT+v3aS=?7Rtb|^C`Ja@w5nrfQ&EkW&l9+|2hwC%SUs^s zqbupA|AnRIx8vm_N~sMiUvQZ6DBxxDs~yW6Zcv$>ySCIX2&@*VB&k|D+jarn5VQbl zd+pQaeyK(&G?dip2JO0DRyy8Rvqg|(i(69qEx+D~Xc{lXoFgf*?{7E;S^) zyV&OA%k#ykYdw^gDf4&zX*}>7TP>xmps5jvi;0Waf|H{{lcOGO^c% zO#BYZo+a@rDqPGD6eU5(Q?q|x5mN6lw;cFNuH?YwKIdN*MU&hW)eQsG75bQ~`)63S z0$Y9H1#t~;T;%3UtbU{6S>e(ba9RqIEkff8h4-&cE9Ee&ruPajhkno(pgzr8wf-~G zzba1)FC`om0W44B9tVXVI+#@~`i(qcQSHmZqG%}{y5^(e`)m3EF>80g72I+kw3m%E z5(4~Kj}NDd>HyR!^I(05HN@F!_s+988;_49OK)Dc5utSiosFAn!RpNi#ljQ(MSl1- zgINi@tJkldKFKn-)HXSPx|3RR@@_qhGzuV0 zzcl}?&FcK0@xJc-VcE20HSOnL#E^~c0L_lSt?tW)0QV2}w(Q5F_!}JccEh{^{ZIOP zQ0g+>+|%!&XTjNRMssL9C=M#!Z}c>dJvn!ZMj7CnBCq*;vt1$fDZOOlH&kDsseh}2 ztB~}^n8oNYb+W^A`DnTWOwU8IKoHx^*_7(*q#-^ym_77!7+I%ebF)@IW_p!=m0c|g zSl2JGVPn~#D2y(xxhVCZsFMNbjZKjN>I~*Fx+FQV_HL0$6OI*(UJj*lr*;V4l3Fv^ ze~R7`vd89gt+%CWh)1v=S*5}FsVhC>u~jWY29UN;wYnw2^0McW^(MHsb^5*T;Ong9 z=K>KQmhQFydUxa%wpyRkV7s)Hb&Mra0|;98i1d5gT24?O)>^`BRChJwtI_#2Yv#Ar zAA*SIo4s3{K9!*fQ5?53r=%FXdMFeHB6@R^= zr(hX2d#1Qi#uw;(ZZ(N}H?~nSb)7Pd^&m3L_z6(Gh#RrX9#hip<0@Ut)3A2iWsv`- z{Tcl$Uj+R1!Or9bdeT&w4LQ`iNo{1nbs5W$U^rr<0XFiY;$SFeX)PmKBV01uuweX! zWF|Utyh-wcJ`E8()JLKIUN-XcB-Fn=X~7b@Fi=Fh-cqebnW$@Dm!*7L;G&eG;$XQ0 zDD+>%J3^6du*<^$RQgNn#R~>UCsTM}@&`1WFc~A^l6+dcEYj? z0-R?Uou_|1RbbNrD2jl=ML4-{zcc#;DBU*2U!En^sNGU>XVnieTq+e-d6VO2)&5|M zXoqPBsc4iZtJ9dJ$Y>Y;>r}>!?+Mx20Qk(r|0_|C)X@Ky2X^P^d~}#{vl%R0$~xi zz`afYXh2jZsE(e?9HAOC>7`)8%5d_!pZO<)R9zek)A-9WBT@SQj#d44Q1t&R=|$^* z$Et=jUsUl%F#h7Wd!#Np!x1AVB!JET;xg@}0wWo;3PRTEAZpY~WbLi}U4Oo_s{bt^ zWx$yPmG_By#2xiOX-|(OQka=T;e3$9{qil1O#KDUS?!=qjoWLJ6}}-X*tCsC?ZQ>D zhtn|N>i8*B)4<0a;-qZ&O5YRuh>VYJw~OI?_)V|TcPm6>(qiZ186<#@WLFuJo^7(L7 zp0`fZ@px!#g#X&ptraHqNm(EIdaTK0CWtbd{rF`RWl_}MU#zb#8i_}N!6DOwB68!Z zg~3B%CQlGWgQH1Y_&bPrdx0Q~8B@KrF~_K3#3JR(eU^S)T%g-2P92CAO9P7E6h``} z6XI8KO?`F{zNsPYA(a9_^3vG5V1?mU!F&su=9bu}+$6v7hdXqWAZohznA(hPP0z{j z7H8;3rd&=tt3YpwYXEGvu4uIhm#ZpK3#9IhBSl=>M4TYu6PEf;3H zgpx^>zdEKtNtxa{OLxm2KD;I2MB9lFVCa z0NMFkxZVSJ_4bXUkagne6yDTkR8K|FN|9e4C9+}e7KQnSG47Rh*PhGg=`8pN6-EVZ zX|`6_aM+7W2WTfi{6A(u@(MGAu!P$4VHd6erFImWfk(F#e|0K18npJrlJZR48Iz%y zAkRR-H8S6sn5%tpPJ{j^^g#6D)U%JD#I)Umw~K@-ic(ZHzAt9hOwz?EaMeQv*Y)F? zn)^y((gzcQ#-q}7rM@32t#16XWSytOaW`n8_|jv@8Hka=`HpT=N_~z1YAkhsQtJ(3w$r|cmNZPUAy_?{a|D-snNAPiP!eOl7!qwlIG&Q{LZ#HS@7A>nCY|hg zjK6{c&OPFs9fhD-O^Zj%!;6$Pz+lD!7dSJtvk*q$cf1&8?|1x1R5{TKpM^ZDLK!dx ztFje045n{H5bWfXQt%es)llhoZ2$Fg@mB>~wOI$L+D%278+fVtg$T>um^stym?Vq1 z)_hlM`r&#xT*cH)XEyIg3#4eJ#R;+1jJ!=tzu6n8P{WKnTh~55k#1HH6Db7lNE@#U zb1sSeWY{9-Bel|)jQbv=kemI(65^9KI7So4+o80@8wWe)ah#khw?rC;=lG-$#WkU& zFGwM?&5hi(K(})<#s~fH$J2;m{qJ;~-m^A8@L9%+ z;IxNXSl)+Z9jm~(gLm>Fh`{~0Y(efR!EN_IF2#O|I)U(GF@aplLyrCd(T)I-L<5P% z0@*VCX^R-21WiN<@(lk|7_FDWR}rM`?}hBB>^Ep~5O{15$t3JQZypRrE+oAt-+mf_ z?`W|Efqhn!+e&})qyp__+>&t2gAf|EodL||8Jx&|^JGKZ;Znc?p+xw}5hPr)339#u zNEXOPA=G>v2??FIsmMyPvt{0kfQ+X&pce))?NB50%U4Dy^>m!Vv>J5Gf@Ny{+m{`h z|F2#N8-ZM6BxpIj%ZVGWBDXeaA88qB%}uv3~e zr;(M(@#OC0fD9^jslO@H2%J?#APL)c%7H>id zWaOepqr^xkv<9NDkyBJ5Qz*kDbA~l?WK_p5CXSV>R4wbZ$G)#7QXRnLy$4c#pkO?s zrKAYL=^!-9LwN09hy~g-W`5I^|5XJkEC4qr_q3L*kaB>m4mEb@R&i75S9(JCoY20(bFVrpKZD)nwLI24@$m;+FPAxzzwKQldvT zneJlO-8|%$7dGo6t>Ru_XC#G>HvrJ9+~thYrEwN@zQGL<+wS%iHjGxX~m4Z@JfroAx2|j1ndMsZ30z!mYVYXR8s2L!(zA)sVZ{`@i-Z$Gc zi+QAZhpsBmMAs=0W7kO|8bU*)n?8O=sik(Dh*v}|G zcw7;Yb2QrbTXboDG)R}O7A@GmmSM9FYsYS`X;;7Wz1Ws`VdZsMU->KBg)iH5M3v&T|t zXq@Aj<`r^*k^^04Fl-QD|JQdbhkG9Nv^w7(6k$0&$75NY?X@O<7ZtCuKHN`JX)?wv zwek|t`tqRh)_ynm>ECdl4sS2b3p5DG+V}t07V3YNf^o3;Kb*1{bsJS&bu52Gm{l@c znBea^GAOdO#Cr1@oxdy*3N%EiFw22wUm3$gwNV{#^M64<;P87|SamF5-Ke(Q-glx| zdG-mNeP>q5ztxkx)cP=7xp>XIT=(HQ-D&cX(l1(zEJy9{9 zt4J7@3B#mLc=;Pwz*J>Hf1=yvH=5ZHoUv3+aOCff=8`+o#S8fecKA+Y&7;bLiqX2h}If&5>D5t-jYKo0ax{ z$D89X{x@Y6f(v&~@txaptsJ&j1~E^G=KEhV;ajY{1`gXCMV!Lb%+3Xz@3ye^m7bW4 zO!x1E+@epyQgeyIXud;m^>z~)*SV2TH-V81dP>&?k?5~#zGNEn$CwMzun4lSt{4+L zuo`N~N*YE#)cZzgXtY%40vl-Lv}mRak_v)o1kTlcwKRNJ?rQeDc02Y3*Fx=8Hx(3I zyrdtM_oSK&N9a1JYP58P=ue>5y)P<(I8N}cIB{Qx1DzH5$2pP9+sXdYG&0l^14zdShEpY14w?k>W+E(n}yg1 z){XgTS?oymLILyM<=1O%2gqIMLtQox)u4UWrUU8=P&7T-bFB%PXeLL>ICu<881EjD-A_g0Y7wsl~=I)nUb<;Dm4=YYLf5R8Q}uI7U^M zDM9)=Ckk+9j9g)qNrm=~$WlQ~8#o%D&zkFCZh$&aPN5;eoJf>-03*XfeUC=!J`Dn7 z=!=10n?Kk70>Y12jr9!xP>A<*4OwAEpL(d9uKYsfvyS0KgJb(z*&9Dto2A=5X3bp=tfuX zX&e8*>T~IiD$HJ3C3K&|^7j0(Z=~L$?ffa-9#DW0uncUNSdNNRBo_DCAofC(wx)P2 zyXF^(0`Gtp6yBdfMN2I;)NR{3JrNIo67M9_Oj2`D7Oi;!U=5{T`HS5qy&@*|kS5r! z51b5*NC^l9Ym~te0?gi|C?DqUFf!(zd;aO2|0!eq7(xD5dH85!Ycti^BI|v6;v?tC%b)S+{qD*z zU?2+mvg}w$Zz!r2_>-fvXr~^QaL<{UdI}@uu!3#5$V)qu+NwldZv+7X1_N|*bm({X zX7XVwTaDCR#V_s?d`%|C9eqQ2*hb3R5H-2&*(58{)TvU5Wn)%NiV=w9@)us0g$YfF z!A7A4Qvpr3hwQd|3)xW2pCn2xCEJTLvql+~=I;9W?8Gg`+Wcven|j);i4+O%Xc>CL z(F>GptwcLnlQlSCQxS60>GV}KSRr11tOQtTqov7_GiG4lsrOe`Z&z0`5Bfx0^9Z^fuM@7XIaaR!lO3_oLaG~AS>c$e=v$H`9 zI6O{r15}Xg(Zm(Id=hMWz1j$jQh(NQd_1Ig!exmPeYFS9JViyJ9b{%&*anNZ!vq2W z_M4QmD!ShSRTWdRN6#uD8!AjAmnRU$Bur$R)rBewNi0U2M!RPl7rDh(aiC!J7d4Oc zANBb*uc0=GkQ{c|94w(2)8nix_PEamow9!lVIC2@(QN#aXnqPqm0i z*NpGhIFsZ6AM@LeR(3tc30`aTJL<30 zSjbezS@SmG??@wu+Xd%<1P;E&s8?89klU2>(7ZTh5E!`XF5hoP@Y=Uo%#$GB0!hQy zdecrwrFCg~J1kewv)D)B#0>uUmdjX1#ccE<;?~_Tta^gNDbnwkH}PmjnCHWk(=`4J za)-3AYfOJQkX}Kx!;CR=DuiWFY(?nD@O;iz%?S5v9pl;ffxpyj9oszuxKizd0&<=f zy$STZa1BqSsBu3N4z!SuNM2v$pP+y>B#azyi2f)K>78nLY#Bw=ArT$m^)#?>3`;G1->AuRha&+L(|M(W=fBPy2TluAtIzT&JI4!lS@RfIFG1up8Mo zd>CQLeuz>hdndZ>@lRPPyQI(l8_m#{tO>jO(dA`{87*6(0PL<(yq!Am6&MN~BVS3I z0Ux2nFnF^p;tS+U#iMHXI$2ZC#OCdis-uPL;N}?;2%M+cVUOYu&}13jwTz`alIxn@WZRc3sBHqee2g$ zPK3JIt zfJn(3Id}-B?<(;9awdNw91RBpyFVe}PK@ zx(OZU-bGe%Tb6`{t<`RRnod};i9);ibjQ-39#KmMea68Mjf6>t8Z1tt<%!cZ815d^ z2mI!HGk8M>US<<5^NTioAiQXnQn~izbA9oA()*7cnZ#ed4S7(Vjqf=P2Si-($jH4D zK)n8h^%F}GFp3h`2gL_WzYPC|VlZJ>ou6n_`mS$8H{wHY(h-T{ljMT2(T_T5_|HU{ z-|m-~0R;ge2mgOfl>hNB?rWm_?`ffVrm41!@ri#pcEGYjMFkC6ss5waN^V}uw-Fi( z8oWeEhz*BvAf%0_W~XNmdTUD!uAp6IL`va0? z#~S0u(%N?06H70XzHCav)v8b4wtrqw&*zncKO7QIT@g{F82MwLl2VupERUnW&ms{8 z8DaW)=P@aF4SzqGKqPaJHkq`pN0LEVUQmZoxxQYTKh10%nAxz)L>LC|Nm zM4L7mPLR{t(UcRSmyI8~MC8ilO3H&W6CvZAocW)w*8NTBp8LCBXAo!&c0@;S7h^Nl zc?r6Mc1_4KAL=I7yRgQ=uyZjccLv7JOj?C>q^jD^O@RO%Y?9HMinlB$dZ}NsEQ96x zTOgI$0-&Q2MR{+@!uodHcI@bYlv9zhSe4spb!ue;oZmZw;Am;Cg6TC^nZZ;%#o2s3 zz^jrsb4~VSNm|lR|Cyk0T+-)jYqgnAyMH}fkKVqNsNaTgyH@0JEfM? zqCL6D-O64}(TstK$!IKGGcJ}~PCx5VIbhr|Qn|SFj(QVFN1F6~rF}S}TRpJR?D|Lq zWoij)d0%6=Xf}(LVJ?$0Ys@)m@!>A9HvYHEnZ%6Q4~zw;z@>Va?XH3l%YGMwJixlP z{P(~J*^{;OOnsn@*6N-GAQeDwCaZb^#B~UBgbQhH)F>d~Ynd&+ziO1hc07!EsAAX_R<^1lqzcAAPG)Ne?s-1GCD+ZUXQJD%=ssG`Ws>YTh_OYC8Td#Ql)B~4-H-9B1Pn?^D%R(xsc zy3PY`W^!Y*`a9SBm3JKB0Wx*Llm)625ZZ*UzuHaECdO!Kh8No_imO9fK-tiq5jD)x z@IKNnf2Qg+KVatTHEUCBhsXO8F8&hiiJUAtU6YT;KX3O;Ro=V*Ufl~C+2a7+dNKO?Vsg^9Y$Q*tI><%o2{0h8SL}SY&{|9#;N=zv)i^6S_*Q7|NMQ3 z1fm}jPFTR65$ztscDS-^aIWyfKt$?!*6tZqHI-MQE_QQ1!!J%n0{}fN*i>5$xA|DJoFBT2`z}I@@C@KQyvz<1E&efsm>N=oHy5zMgFq62>g*)|fshVS9}JA7!(r;6~>FuZWNe z2{icO`DpAc9H~{{*c7(y!K=f!YeMTSNmABTI+|M5=UUlk6co^NOkX;2c1Uq(Kp|w3 zF`7aI6I&g`LLs7d9fnsO!VKJB5gMF2vdn9Sr>h8j_uRJ#fpBm5eXhH%sEfB`e#N(! zrzBe>B!fK=*>b2EWglRw#5KL)7$t zarREpnMC2XXm@Oz9ox3ivCWQc+qP{d9ozY1cWj$~?BwR`bMClfpRxCTxDWMSHCENP z=9)EueP-O*7P3@e@~m;&f@Nl>k;+O8`R&aTd>aHI*p3_>RI6Pvv-h_$C3 zScz434-MzxEGWBda7nrbikt67e+=~FWsBxCa1SGANb9J1O@?6F47SQ6lC?@q+&nVOearcSdqxy<`n~z`E>Z;wyGL z;mkk6?v>>3TOfJPVbVi{T;-NG}1fI_qxwXsU{kw zp~#dPxdCfOiI|8*i1VwTb=N_=Wh7<4Me|zn+36iQk8D?>Fv8E@FWJF$-TaS3QqF3| zz%L+(yw7vFx;`jfQA?QVhXP!KbYngFd~d$0tUL-jON^P^zyIAekZ z+Lal(T#@X+LWPW@7-diNJm)$wua#V=tfv|en4LDEqiHjKnI(n5>9@(+71czjgCZ%G zwZ3^oj)5m~8#Q%pO|$@Sd@BJ472gJK0NdP*U z@u_v#)-B%?ySBwbT`?I@AcY8R#bIsd7>(?SI`Qtr?+>DXh4whfsr%#Rhia;mHGUnP zhPw80{?eT^nwC`>(lI>{V*=-keGt-pkA!*;)pW@0G2kaXd@Iv+q&j}+#>BT>ZG^yR ziyPP6JIu{KreX;kMxAm=iuRdKL$~1l0kPS}=v_`=2tnRi*84Rnb1>_6Fl*GKXCfTatH5UF@yP=w~ry zan9Nhm^fo2a%PKF{tf1=D08tax#O+r_tpA~g(Sm+P#*@A2QLr@EYMj!R>uoULLtRD zjm$^jYO^*R<#M_8+~pj1`@YUBZ|9@#w_WzL5rU-O8vd~Jc)9G*K(Up1n~f<}uni|8 zQ()o0-?J&0?nuBGPZsPZNp_wHS8g+=Q<4XH9Es&y+bp8FMzwc+%-QuB=&Hh91$zlUrV1Mi1KTsA{mF4jo=;Al@bt zW$93ioKS7oP}@WAcHXt^s#d9tRE#>tQ9y83W|Eoc@={tll5YzOaCC z)^u`AT$Twc>5|yj&;oa<@b7s?JyBNh#I9PAmTHXIy;201a#p0NT$5~pH1al-8G=yX zoige3t>-2sHB04U{jsOL9Oq7K2)l4*Fw&nt*eO61x!+jBR09TY$f#{y!N26BvHIhK zVcRGR{KcTn>{A&%+Y%);2HsF?iLZwnf~7SQ>|xEwy#4QjcfSaK@ypQtIF=rT+Jebw z4Jxo?RDlb<0v`z?{yoi>jX|=civAO67{Fkwe>Vn116N|Z)^wS` zUPcZ-e_`r4fqp$*C%5edT#j&M@x(^CyN}Si3hwTJ z{=0~>p$Aw!u^iTb^vhJZKTE02^WrO) zaZl(pn@UKTNihIz+108TVe5-BSgze2hUeh&v@V_r)znar$S-o&Hpq{9o9E+}&yRLP zKWl+RWCEF4hLe)-2$5dHWM7HoPr>ZZLG)MH@V`b-g%GGX(>D#F@}Fpk|C>N1{4Yn4qlKNLh4cTZEzD8fRz_7v`=rkz%)K=vM0W?JZ&aJ(v+Z%Do z-99cr5`?q`o{=LGfCmx?y>b29^Hsqp!d+s*~E;^+1P4N4-#1ahQwi1kqF8 zo|XNXfTD27ZKn=acD-j7*Y|#xa5YQIXmO@?lY>BxU~8yqB5#%c5)>oiS;S?ZnB8fHe8QRrIM-IO#GI~ z=V70#{@vA*^2bMLeeDKSau6Xiwh8W_f}Dm7BiYiX%-VihS>+YucdPM9SJn2sWodWW zqa$kbSC(E5Ri>>S_?=pf(gG%&ZRR6>7AhW1urepUFyX6+JNSq&mSC^obuUU7W9SVM z3a^YH;x1_|xkp==5>#3p<*ZX5-xOlD?22&-L1ok!>6C^W-*a0yh!E~n~Dr+MrL&)t_!rQ@-gv;V>2P?>L9s8W) zu}l$BjbqA>o~?hYg7*=mXAaSB51crsh{%oUMJ%P+shU4W7WH>%DA$3wnFM)2j z0p9(svig~Uez;+`aV44Ezw+AgQHgY6W#{gAzh5(tqygQQ@8T=a=hoO>m=PcdJBImrK?u5fmZVYsbm(eE;4BgbmD>Crc@)GXc zqQ-=yk&X%IHrB53g>GT;Np_TB`~iECUAs4^oC_RiRoYAbGufBy6QPgjSYcL_80wkX z2flX{R|&*7QWb1*OVob^y@L{@({N&Oq4+`h8(0VuDRo8;Cu6o@oD8nnJ+VpmkJItt z*q&g&xx1-{jz9l{m@P}K4H){Kh{gZum(u@D%+mbV6VcAz#L?N~o02uPFmrJ|&I3))*{@!^Z>*u->8Mo$t8ijkI?_RnZ2Y@xUiC|GzXnD7r!VuUeLYo!MSj?Z>%y z-Nzdoyl?v?aRCryIL|{%#8Y^A8SpAT^;o(2^k|NZ#js#7K87Zz#gljFw21 zb>|B-p_cQN5~Eh2_h1+gP?73Gd}O5I#$lskA9e1z7&C96tmIzXVyk4|*5gZV&{G_O zmxhIpBJTL`CNS1Z6r17fIT2BRSl#>C%UhMe54da9a3$agl;`gGyN}D=Lv`C#vcJxJ zkDqa90m70;wU=3ndbUIzJf2(SZgbNkZdYJ)i$t6iSV-pL}M&f|+zGa{faw{He~@QEV^9tY>FqGbiVgz)oJ z`SbSJjDZioNnCJB=6#h2>EiN{V*XiF%k66z<1oa$Nm~TUL7u4O&x_{3Xc|+`Rji1R zai^F9YFNiaAjjW+opNiGiSV*&o`s#Uij@JJxpm4&ifd)cNcfzS?`0P)GVA!Y%8Z<; zmo2!jF{egLGgJ~}8_ipIkK9jItlfiSlO$4*CKoHT%5ZXy#&%wA%cnx$EPm2to)tGK zl!-Mw;0Alw)1JC}EJ(XVgr&ajcszn}_d|M#%FfI)Bj%h0rCGGgQJkX9S%ieIwLe9ym0}mDMdPR>{$ra4C8WI$Pe&RuDvzeD^~*ktRgfijCHCb2U-3 zR`6k4P1PhQ42vU|J)q?E@)8@k#<+Is`j`YOG2?p_^n!h zbY$PPM08-tRa0rBR^E@t^iFvB2C>vAmgY@}V+wwUNd$M+nq3Wv2Xmw@?|x(BNeYUoLYN9HYhJW$Ui3SM6M^l|<+nRew*CP=X z(14B`1q1iyyDnOUW_1q#CRo*^sfMpz&?SP5?Y^8uAc)&Ihssej1rL;Nz?_rI!q6s# zxB<%{1+v(!5ez(|Bsrjmy=*!g-(kEcCQ4*16hqGtqCPey;qS1$Rk&)vNCR0D+i)iG z@Pi$6Bra+_=g2+D^jF=}UsdwH_Pt%v^qc|77W)darL|EMV!SPBkuT8WcLF1+#{2{- zt#X?=}5^FixjdKffUGR@aV4ouQZ-l{Cvqj`1L{7uSL zO!3#iESgp2$*IAap=H2fOboJ~D`~r{8m*p5jp-5pdVWdYWX~xq*W@a4YMnnk(N-9q zcH`1x)BCpBdKyN8q#b-MOe;0RtjKf$bK$kjV+6pH*;*L(_|JG{9IC1^F;$UQF-KWt zR1Qk4_)^8cqd#5*`zGQirz9a$PcNH64S!1B&RS?bMU4ietIx>KIi1sW{zJ z@XaymDuHjvpH;@a5tLE**}`fWaO)!}Jd;_tw#LltJV)&27Nz-719aF4^46RWf~HD- zoF)7-j(~uQm==a+&79B*urRe#?vHf4>k+@XqpKP3PeiN>J!DJHlJ1x|?w@&U_NeDf zQ)rV|LFz14-^ObOh=NkU2al|)++)l$ zjt9yt>(lH<5zW_WhCK7hJMlBANp?!5<%ZY3CZQovZ)SLF92+HUkVMg!n~M0-(~->* zxXSWET28;L9EGa+wvbZYLwq=tNj0ded6QYo@t2+6ADyx_srX12nZ#IGHjGgsQgE9h z)o@Sx6K-c$m03t_HpHypo}u`U;+x|F)Ah@{7rB&bL{|LecUfA#0~#kNa)iuqoYmqsP7N)!tW0x?fpSDxb6##`txiyV?7X(()!ofZSTSTl zw6;cd{j0bHn8v8^kZCy1>^T6Qj_QScCyVB=X%=(7oEZcKDnkyZbF&rC)!?6;371xR zb0CPi2D2f~32@^n5)lFW@l#HdGsB4l9V_|LCrUx|BAfob0~8ndkxflZU4`AN`4guw z5VDP9Xl|v>zhrdR${aKq6QS5cu{~bk5IIsIFv;D8s4mj|8?Dr^st%;^P7B~6bj8$h zo#A!QWvW4x5OvLF9~uhUO{-9IahyRnPYPlnYznjB)?|7aPfR;Pb}eFabinZUel^07 z8x<~UpR%tetiyMR+z6sjCPO^D$ABjMk)IZ z$?6YdglJIMQ+^6C*$!y1$0^P8O3Bhk14=B2ngWh@J%g@F-ehj`+Rb*;myC_4hGDw$ z2zEF()-?GKFM$8H=NC{9@#h*JOC_6_D7%H6EUdX?>z}1cLgoxih$%Ci>W+nmi3?7wRq1g(7>y7}mCiCtV$e z#%`^j`4!|ke=T$7lOE_4ncE$nuKovkNuw_Aq$I=LbW-i$**(-L($_gZ`cN|{x9Avu z@bou=d*&`R8fw+_>~G~&YUG`AJ-!wQ+&FCw1ttoMJGHfvUK~a#1$$s337W>MP za`V~ip^b*`lG~cwQi@9R#impg7cb7J+&gO20zYkJ+_+ znBTb4_;;;bj!|U`(SP9=2GKx$Wa=p@pzm=N>oJ(uwe0@EdxAqHcf>?{t(>6`%V9 z9YmjCBqJ_x>9YIW=n*b-J=<9gs@<{>F-OK)Czi;nTU|v;KNjLbXQ-B)tXc`tE#db# z`v&n5!VjDcgYY3;dS`O+I;pkj&rbryxrcVay|3WqFY2woNTr`6JuAWT$!#E`dL3Td zYhY{HlLDRjV^utJ3M;hHi+fL&I|V8=<(_9DS6Bn_5!8dC^0}7pH`i8j8cFYE1`bnkIoL8F+!5qQ)@< z5J#^PlEmhr>MG>#z8fx%Y{}rvcIGyNKc#Q})qzqjDO)(OY|M%1#$DJdY3cAa^`e}z zw)|rQ%+zHCeACCybAQX^O{nslxoTKkMu}Etid`z&f85O`G4ZruZAxgOxd72r4D%} z)t}aDSaG6FdDr(C@1bm2e_QXJ|0z_B%VaKI8Kcu8XT1GoPtxKPRm~WUUU=5tloG|A zD2jnyQy(4D8)jh45I{H9`ik$tr6~XnRMS%>bKA;zJ3NN0E%W}x%$f#@JuybU~d?9;tfMMH4N4!~&c4jQO#)$JeiWg!mwH;UjZ6J>b$kT>ZwuX+ zjj5Cjk3zYXLYc+fHP0^A1JlWUv6+f%H9UIV-0yR=zQ?I1C4}rCYh}>47x%#IVkfD9 zEIA!FDvU-8K!cr)dR9fnW9`b?MQ*|NIBaS5!XLsGF@%@-bXQ{+vEdO`G$q^@O@mF3 zvR6jVd3;x&I0oH~;7dIDMc7-uCcwCowf9N@Q{R?E?8rMbaV%OwahJJ1~e}1tZMGw?9iM@T^7$rp9V<#>b`g{_X#;WsU zzCsrFL`ctsgt!}fj6+s~K3-i`^q6@Bj+1)Wb?yDE9C$OdP46H#4o`%Vkkf;`)@7k7 zWyqeAosvV%Q=u`c8aS+}ag`%`+UH%Bns4!BrbE1A3a}8&Hj7{kUSEw@FRdFVVJYZ+ z8Ila1F`2s`G#Tje7FN_>UN|lVcf8?egcof4El6GyFh;U8LdtciJf_Ug{PNavE3DbO zSgkbHv`7=uc+166C7;o8^6#}dZizffpi5ulL$gSYyD6Wv2tif`Ni6wd-3$^^41)Rm z^vp|f+}4p6MNb*9nq8IOpairH?_vqaUZOqA{?0$FZ$yfzDW$l-dRV7(BE*N9kt-hd z^_1jKXbelwY)0`H0?+7)a?iA}y1(^y%|yExNv&oOMaAsL!h$5U?|2{r`z75Y@#DwX zC0lRfK@ezfSpW8pQ|XKFL(R_Xw(?nw&KGmZC*ohf6eazMhg#*c2c0i7sSo$RUo<5> z8Ry%@3nV&UZc-mmSP0vt3)=0Ux>7zg%f0dy0+SD4#S5)BQeRn0wY#5$N@rmXA0x@H z(D@T&48ICr=_={nLa5m2YEo0woJtlqsG9qAZu6(*8I~xkw;+ath!I|&xqh(v((en=82n=W!@dlc^b;o?lzHmMBwNP3b7|`D#|wWv zQ?`7Zi3V3eTc3ZfqcjuL(8ewUf*#MHnw>jxs%QTC$?Y8m_7n$heTyc45!$*Y(e3$u z2C)mZbcNY~)voq}f=oKM`H50Q)9wj;QTjR$`2HjiSi6FIJi7>FVqRsmYUpBa<;$p= z{4mI%=vKZyT>#A;ft8NrF}w)c3Hm5Nk}`<*Bt#JTg&W9-9y+jS|81Fa_1Ly(-X6k9 zhe@k?`miQlZ`a?Fcl^?|Z?)uT_F{`R1J51D#R#*O5$10JKfnfK7{4QFI!v#3kM)7fLt-w(=Xjuwi?QEt%HtFrb{-my=N>_QfXE z%Iy*-PHugiTbnl_x^;dOGAB&(ge*V1ARu;Js7f=Uirk46svp;Bsz5y(J3=%!Q->{C zA?VbM9>*=M?bNi>7kw+ z@r~Ck0%fIHE&X45>`iDgvK)mqz%&EtGYH}a;7>P{ulMhIc5Gj(vG|$5-kIzJ7u2eN@JY1pUY!Izp8AQs|ShcP5OD$|TA^H%+OPqBetxp3w*2g#S>of^ClG{OTVRbe$`kL1= zr+=!u>D%*_Vz$LLm`*a>t+2d~^MVxSLSjqIQ+Dy8=@kGWoFPq}47evljj-ttyOAmv zyr3sd(z9VEux(qJM|sCTZnvgBZhg1T{1Td5vjfz&YWuT*2=ilasHI6ym@-eqUDdC$ z>jn(Fg|NN?ZWC~gnQ_Hd z>XkHc&A90$^MsrxVAwJ9`~g1iGj?5Tf#)r;pK`g0;L$~o8;eQPM|U^}T{*Y|AE((( z;68lz&___U3`!JEz2XY+!pKo4W)wR!G)5I8RU+S`It(1*IuS9`im7%A07O}_{?IDJ>+JAnC+TQi+9$LY z1t@tzTIIuI7s((UVQcOq(#};Z);(X(mR~n8l~}{BfFFL{nm5bp(tPW^!6sM!#1NGw zP?Ejj8B5u%AsBItw&Gm*UHMWH2`!tTF7t zH>!D64YRGFPo$#YaOAID};rdLM|wBkG$ohB1_fF#zp0f>>EDqv4(dvlA{n9uG=`1 zzDh{CbH@F#)UchF-edQgvROZU2Fx2qyeUffoX3xj4?2|GnqqP1;OG|$poQivZM zTQi#3li=5$Sv{)zLzOoViv4!e5pcD$*@jxG2sv5OiM8oBwbmQf>{q+53u_26Jwk2Wz{} zyH)_WwS$g=uNz<5q>DZ|f#WXusHXx9W{QV(3nna!JU7c1*_Kdg);}_T= z;_BxFm-D%Q!O#k{y0f6IL*E^e&e%_Eb(_Dqc!ssiif@(_?7QP^Qt2@YRmP{mRxi)X zZXfrp{`8J_cvrD`Tg{rf6xGg#E=Jm~)L63^V=Wo|LPSk@2Gl$ZWVH@s&57Q z{aXjpbpv{C>0=9@>}fx+qfS7Z*JY!9qYUZPZniu)Sqc1|>N9H&NXq+gZ0Aj$@TwSG zt9vv&kSpeRO@1m-H`3;7tOmj&1YFzm!wd($=L4D|Y3r+gb~QY~YR2G_B_gbOt{D@? zad25ud-PpxSi3lO?z10#z7JTspo2FM1ZIJ6+cMo;nugeMWIel9fdQv=T34O8w3#6Y zDR+%7T>}#-c4A{#L*fGTZ#{k-qy6skEdzd}j6KN>J;^26h3)LqYiOa^y8(3hZr*F( zCKaYREv5fPf7y1L)$^U?_5{r>bqr}$2{!x)Pe&xsM>BA^LjQTq0^X$#?Osc@^D)kT zvyQae=juKRGdt0BwJlh#*LY~Zp7=({K0;SMbGF{Pc;)nP zxo-N9^76cK`JE$!Ki&Ykx;aaB_BTnXHM=)18G9```#szLx_+HY@agav4{rzH6lN?r zKGfIA56R=}DW9+bBLb>drLPwUvucOo_U??yFupDk>D(=_q>f1@W|4W#bL8MPIlZ70 zlkglN?8~cpD_HydW@JCF-!GBZ_jyl+CzuCNyayjy(HG9{301w9e>}9?!Fk1C|Mzq; z^A*r}+6%`cZVzIhXdAL`hMeuhKVy`)q&~6@L zcXQ2Pd=3O{Hgx`T4T^eJd@f*(vU2CiVa;4CAG|^nSDM0V|HRvdce7Hq*tRBKZ!z*z zwkCLMUJ6}&1F9W}M+*pP3qRb>a~c_H1B0X9k#V8Q{lS%uNIPWWPHeot352INiv}uT zSPv&L4vx9d$PJ^f^kILnb`jt%{^o(L?W;40-SLlM&}jgMNV8Fky3A|CB(N?m)Ykpp zm8Q%4n1a!l^c6NHyP(j-bkwe%qLQnh`3^6Y%}Iax8xuc5SrE8v>pp%HvWJ#Lr-+== z<{SZL)k&6&y6l@7L@=7B$4P0w|c7Ja(~ zyvw5mrJa{$2osoUa{P9JfrSCIeCd&MPjwi`x}M1F4Jr8m9j6lP zTAuigo>M+#Jv4ZoYsp=6*}uSm083peE=3lYavf#E(@N;)uyiz-pTy()UN`dn+nBf| z5C`k;R1njeH|2umuAt3NnWZy>%oe2BMGT>w7OYgO5s@G@L}VLi(xwvo(iS-Se{#Vz z&4>0yt|%LSYy3N#AlwD5f+?Cz-L-hY^%k^tU2Mp_%f)t`=pghhY&eB@QtIiaHPZUT zv{2N|FR}iq847F1m|0i>VQlF1N@@V-&GSI2OE_;i9@r;yv;DHQ_UCrj+}k8K11R1f zpsLo1pc97R;@I8Zvp*>QM6WmOqHw~k168K+V?!3H&z|-)VS6 zTj;2TQp^aJ`wo{y`e2<);*uO9^6nrk4=Lh=TRh(7Jx{oKsFZ>>YS8ZH<7g+?W>*Us z4#2J{rA30`8L!UF{XorH;y?Wr@MpnAgxRwUvn5x1zQ6I*(n$O%9QcPoSC)~x8xXPM z5!geitsS_sI=aXOxCcbndr5a^}f*}>QIN*5j)LPg}_%^_EKs0%iM zRoCHly2&nBQHhY!hKp(jhWi}}O`>97l!%ixC|)xjtanggNfk&9E}c9pq|3iEmX3Ot zck*7@7ts*G#+kXtl+A?x(9Wsh>=mvuvT#F+$T`G6ei+$ca^Y08_=i>wXP!r2&gO1f(!Jj z9s5d5>q#UCxuECDRHN!*(3ZDzgK|vX_@`P5 zcD#l9Um~#wQfM$t6~|Q~m$c{d&BQ&b9|E+J|M`7#I6@xVFZGgqp@tArZY_O;avihI zKh(-ayI^B5AMO2zudMmmAgugbe0=l&LwxLL=W5|(VP`96XZ(M3=RWZ>asz@$!@VIO zT0%(RqTx5;SeHY%!?03?7PF$4K2%u^#;2K|yWL&pg%J_z-EUz0K@$5-o=o2r%Pjh) zJ=+(&ej5VBQMygCSmk8$-TvY~&*4%Oz!GUBzzP;V7srr6c}yrDnhC`>;_&|dN$~RY z@x$(6Bfz?aoJ;#hB+_Yg-q-ld=0-7~w6>n7)$+)TeBXi(QB*q;SYR!!54XQ636|zv zELpL(Mn*tEy|`V7ENeVk_ppA;JL{BD%}&}&aHBeIVE!3l#>n7|*Y@X^@(yBDH&xyp zu?%a}ieQxCogb+#Wk%heB=rQcZE-}-C8<8^i@SIApv*I}NR3gMPvl#!3wx###pX|K zXE)FvBpL`Fk>Hig8u@TdLnuSUCZKc75p&(3=T{rVPDzg`C%WW_vt0og82?If%Kco5 zqG94qY048Z0hZjYkI?^1n;8PjT&(cDLigX-e=iRw|F1qzB|B?t3tKZ0Lu(UTW5fR= zLJCpQwMP3Eh);jIw$3-uqL+Yo1dh8(b!sTafBtgS)}S4lRVs?eG<@p7=bp57Et85N z$6-wfhBQ(r9HNx822&JWp@w1|HV5`&ZhPOwaOBE(6X$xFb=uhclfBAunt8c$^S%D` zJRWy>{uf$S6i$TR&upDI2T)AqE_4UWDsum>Ub2Z|wN9DacU;F1H-qmeEEj9#eG0DU zi>838Po&HYWh0Ixo3DQ|n*&>uEkAd;NVHnH3O9_2+Oeb1TC(kYoQMkc=TSt89zzn= zEw$<31M_Pz38w3oi=~@@kkN*VCFK4U2^jtv#dhv3DK%-^o3VMOo_2ov2`9DANxVL3HW820yvw?HSa)6uJ}Yd{DVC1=_%s>xA5{^s zy%q&0b-<}Fbzm$UW0NdcdH`Q-3_KD0H~I{$n*yGzmxP$Bb=;VuLm$o2NFuw=!DRKR9O=QYCTabkxe-0#y)Uib=9$vYW{L;+1khg7 zTD^5}8z_HsFY<7h=$*U~7~P~FWCK!9;9LLAxC%37D9S$Iw&PuUR3!Nvap_Hm`8H}e z&JPc6rR5_3k$Ewi;6oQy%_3?YZKoV}cT}8+-{HUl-4P*4B|$)t$iZ)CixV9u!z6vgxltT*&g)b>vf#Pg_=DNpUu*k;+_&Qf?ooOtY{x-iu>mqF{{lX z2k0eT)`ntIr|Yh1Lm}uHFR4HB9jZ0NU%Hds`N^xXd%fGZ5PV+>KB-ty;)YaQ6zNhD zR@o4$vh}VX5LQ<(u&BEmc~WBnHV&0rI~QX7!`YfZwO9&W2!$>(vTUvBmd)KlIjk7w zG;N26reFc;nqs0mVA)lV0hoEf1~_jasJcr-UNU;vlGx|8EVYj!ldqrEInS`$n$i(3 z_HvQoiSgtgWL1;fC5;-_+1KS~_tHx&0vSKAuhSD>DC*|nJ?L+(^!kE__nhshD)(Xk zD_e90!BgI=Q1hbsm*Pa%cGqh~bfi9HO9IiypPxHG_nxTtERIn)$vsz&Sb~s5KCiD- zo=L6@h?6sn{0b*=3Ku(noL)?oUC3Y`I=zeM6A|T1usyGyUQm0(qT46i5x#w@{VtRS zq|hCvquyti-Dh}3@S8{9D5yd!CX_6)YWl8{B-zXdo0|1}O;|fA`(~DQ%QHUWCOaBW@=ix0-Mg z1Ki%-!Qx)+RrGq!hm01Z`N$dK-v0Sh7`rQlmU%ztBFaY{zVY*tNY6;+?xO%fv2*W| z`k)zdpZ3Chvj?fL^?GMC2qm>uha`P2ohFp`|)!od(#G zqDLU$>;`kyS?g<{3?_jNn8{L`F#2?e5aCfiT*TtBH>ycI^^EpQaw7jm2==OB72$b= zB9tFsr(u=Ht=Ks?%QQ9~E!7MZi4T_zc-t=8(HFpDQ&QWIN%VO85|MmffX7-&rBXFH z)L8Z$K_MJRK$j07&kbUjvbO)Cogs0Y8=R^GOQ?#xBjm$@3H_T3VzkD# zN`pvgW7o!k8-pW0xwF-U4OlZ+&jc}vY%h~Osq$^r(!R8Od29Ii5MK*-c|g;{+jGg7 z^RfJi3(!BI#;D_0HeJ>-XylxBv>tj0WgZ-?KQkarDDfc&ZMj@CC?yNtX#@=+zK|NB zYl+`P3A<<)zEr6ab|GJH9p<|rGnr;jiVW+V3ixTN=Qk^1u%&5zYLs1n{^ApYBo82cc_W36>)*(wgc!;g=9Qwi6*-~e6ganljY(RaHbg8{jI zqn;cV@ln2izVa({LYSv?U-nzI3bXZxqWR9hRT@=F*rGzs0q^j%Rg3(XEBX{Gjrd}S z93N2%xhHhfShKVq9Rp1*X~Tj$tD%?%7D4Y_Yh=Bxa-TzEioi9CFQ1WO!Lp=rcus9x zxv*JaU{Rwpc6$$>T_+qiLMGxy*Lu+b-bYVo`G#QYX%7^?7XZI{7{>i**c(eQ*7&Rz zENkc+v2Oe}fYRxdFBTUG8a94r-h)f-8~{bo47fsMS7_%^Z8&g-B00XXl(T!#ENvWU zfROs&9={}=iC+%(^T_%muJ0;6|OV}ieYrpoL%+@%@=<=@pPr69Pf5rA?az; z*gRY+SMpf>5zz~{%YAgOF6dJJ{K8cQL@Aw9oDcp|#&10bZSap&O_h~l<_L}n`Po90 zKJV*?tF*mw^aY#8EaEW@VgIrOzyoS_+Xp%sjt{J%wA&wK0o~NQ#%h$za#FKQD6%~C z!W8c_1>!=y>-}}mdlheXh>`q2Cj}-Ly7HJpY7IV^855qr$`|o7-ER@Dh^9zosp;?< zK@9ETdkzBIhDEg|$@zr&y~Acsb#$zLa9cAnv!D#9lYatNWoAV^6Mvofw?P}XAn3Ow zu^aKRBMF(})<RUjhUfFME5^s@ILm55U`9DIhV5*4F%(W0x#NQ@4C#sRy<->kCz!Sz5 z8?{7Ld#rL#jpN#>r(;p9Z{vmF6g6#RzJ@Yh-~q( ztU3YrDcxu84sWDpLd3S-2PDhK{Pfm|JG!GM5J^!ijW{`R z*XI_udskGR3!@#Qb(r@xJ0TWN&v++M}&C{gvGUj}20_3!+h#1f#sYO`FXyBUAnPMMF?{Zcy0LBVfUil=4ui zuQ30Yu;p}kmAaW^9r_G6&KnNV|5u9O9_TaWV6{`h06K8zAv=SQ z#mv;r@BRH1-vO;IRY<@zu`OE&uF)cU2;D??Y6s`9nZd6z1O5=M!wmWPtH9fXL=DLS zy64SHmP&bL6rzQouSOS~&+ zyRhrU(WK@L=Gsd~dFl-ZOCi-)IOWvyRr1<9N7Zz;Wj$_2>DxLzR15(}+@Gr0JBNbo z9=~!IK~K2{f2-(R$3wzRh$mkzmsqs7$O=cv?t;;@OM)gh$(LgRF8oLhu##K$JqNZc zJg>4^ye(hQMM@9YyBgeyQ>;#kf#9ktBS;N!MP>2|Vwf&)1_~qawB!!TBXqQ64%#F5 zwC8P6UMl7tj5Yf`12h^YZO_XdOwnR{o8hL`l}1u;#C5?&kgA~>ey%g|4U3j}WtOdlzGkaib^9x2;7I-3|vn|O%Xy4aX}`;NZ3ng7GcDN8GV=K*|@H;x_EV}XGTQj|*$ z&`@Hb0|R)$z?*^#r6wlG;l@IZ)7GqMZzl7AJ43LT(n3UN8d{zY63@yDxnz`ac)S-f zGv1r}ZhrG``^#7A_RdDk;f<C&I0f1nm@oVE3U4Q8bS2m4)(K_mI0IY!+mPj(q;8 zZ3TO!kw4Lc;A9wCWe@K$Jqr)8UIx=OsiCyp;3h~HIE>Rnow5qJT>H#~8BFo{QZR#V zJRnR4wSFZ6lMN#?l!(YKxFVPqWHl}L1ZvkqdDZDP6+!6L^*C4}G)LGc;Y#+T|AZI> z_53EDIu{FLr?65Gd`mVlLwRk;osJaU8oxhAX-vHg4+;BoXy2bpD<)RCBsCZ{C~5JT zvePjc)nv399M8o|!rG%{ejOM4X6o$NsS+_Ky44%Dh&tymDm$^P-{H5Do0tVxVO_8o>eF%_Nxt ztaUqeK`w)L8wk(^J9r{25r$%YoM#rP-R9tgQbV(Mx+*yPYnC7V%2^<);2x)Ml;sK) z?+!|s_(f)&NH(or^Q(nMdzb`Fb9w3EevQg%%hn90;yDM7gki1SwY{?#8Qe18kza(5 zUS|aw@W7oVazw*HX6g8&a{ZPedj*`H7OoUVSk+81v(ILBWyj>2_p9Sln+b3q5 z6yBpffyv=>q{pScO(ex%^t-h2kHK^!N}d%lRf0&r)5)aQab$iAQFw z35pQPf|lEfQ>Nx?C#+c2&Lh8O&mM=+afdN=z3=i|BrxQ;3JS97-mZNQ+@?*Sq+IH} zIXt_sZ$7R$PLS|EJ01{zMCPIl$VajkK%A&|ju}w`ZtL$ z(+=Ij6{~r&g+H&34$?Q7R5~rhGWLRn-6TKGJv^jAW*rcLnSm21eoyR!TC4V`X&o`8RMY$E zGKHP*Dd)<0D!0Co3pcfbdvZCvJj8-;>b90gWyiYL<>W3cYb+&QFd61-zFHvY^9+R* z)XAT42=MDG`H5(@z%tNiltydmqjlkJHC?IZ&QaDd*S>PIprz0U#a)q$K7#UCcRIr0 zC-X_OdsqP-ZOH$flPj(*HX}Vp?iQ%JPK;b__m;4ls?`sksI_dDsMLxY3e*NbK3ag_ zr&K#>6D5pDIV3_}Eciut`e=y3JU&h3OVP8<Bj|Q4D%9K+&vkR74bc0*6YVNLT}nQbnh@w?6A#WB=_-r zadJd)HK&s+5C~_kVV#$f#EW8wn!1EFyHZ!R7$v?q{)ZcR195t&GsNn7EOMM8#=;XD^}Qc3jrCY_6H$6eY2#|in)d!FNmBRjF;kJgE5y> zb8QtnqAS%J!p~iAQKn~mK+gz6-i-%9?RCO2H4;(l!yF%>lB<2FA5wgnJ-I(a=x?bg zUtnEtxp;^0Uw~t7N&XD7xkcXGqUU{FIobZ?bb`=!OG3*SsZ+!sfzugKFZq3Pet_XJ zf_OW*pX1#CxoCRVZrF8)|Ch{9up*1#_?5kep#JsT|DP5NB>yghsebt{7(4uT(Je~V z+zELF^-ng9dNcRxckBT1Z)r=(R+~u4KcNy46wRXiYKP>~qpRvzzB8LJGsYH5YP8>+ zNwgD7ug?dO^80^nxRORUYjBlp!M_^2$$oO;u$J{~_i{C1PB!M)!|~i^eBQd*zM-{! zeDuv}^_OtkEh1MrxW=mN=Rxdb8SiQlZgca5ZP_7c@I1PcaqpCTl2JL>lJA7LNg}#Q z$a)sN^&>yGcV*!vKL{~;7+87YL!Lt62Qxe+*f>Y0?i5AZII9G|9$_W z#llOsuZysxi&6(Mm-k428vFIp5*Cr z?WXC;^l6Wv@#W?&=sanaakuq6pd2g z50ADuc&zml=%(%$MtOL@1Cw0axyhs|96h%&r@5R4XJeegSd=kU1@hd-2Od}Qp`?$J z$QyMbs%3*C+$OWAr0BdW=!s0(H6?+OEVk%I`iVS9Wd%$C(r5&Aks4jRyQxH*TfCR4 zD#@g(XS7_A%9zNG116?1EX;$kE-@JDBP_I5qe}XF&ZAV!_gB4p*Oi7jt479(#qij8 zqiP)K8W+*;UaqLFCg8NTTif1Vy>_rggw{W`IQ>q;mnnc%Ts*nwtOf`qq1n3YwMZ5+ zmg7dRzt3Q6Zj2jySXZl=nOqoQ>R0I$T5Z&~oUSQ}aHodf8c;l&1;u5@UqSUlv$P4w zQ!qCsOID?8b^8|JI~d>lQe{nHs83@g2ZJ1OS2jcyxG%6e@c0k}a<%qwUyLqb*OGRDR-#`7VTT6ttO;sD67!-lMsQWQ6rB*<1daf3} zn##SMtIwoU(>F)}`(CR!pnth+CqGT*K|@w;%DBuxgz8$^dJ!n~*qV`3)~fR}dN)3p zEOx#YuEnesz`3L}zE<_x_v6mjxCXUFD`B5wrMT621ma8~^Kl5G&2C;Kmn(Zoz2Oc7 z%Vkd-b|<(oDPV$G>xVDs&fKlGSe8P`O015sxXfu?9f5xd^QIqcVV#sQ#UzYN!{Nj< zJeNqh*mwUM^A}#9+`W)|!#C0}6K=_VEsK4FE9JVYba33?0>5HbBew=4B~{seMY^Ml zQ_%1IYBr`$;#t%3aa*m2!l2V4Yjm$-&%SK9ziZ^}r(Z2bN3~atF?~pr+C;d*HK)57 ziv>E~&cA508tlfm9EG8iwR8iYv2c^=f8}-&x%Cf5ze9%Q6HW;>WUt;c?KjBb_Mx5r z4g4GWLH8&>?>&JS`o;y9l`)v8lTCK1?-2NQz8XiVk4y#dx%wV+#@b{)9C$phQw=M< zet(~66+&$3R>qb5oSz9%bR}W~tX|K6_Mz7lA1nZp&I{MVCB1Sw-RRe8-7pAq5k|AL zk;H0(rcgJSaP>PR66hp}TRhR;i!jhxiWgfeJwY)r*9%6Mr7Ta!6eNdbXlsVO!7Ju8 zv$DIoTdkTSWXpqa<5+IlKo^cXlQMXS@>O_3$om^`N?Ict-=#R zAEGN*XW$_ShW}XSLKKFNL>1(N9#%Z!n3~x6D%vU&$5cQZ;^e_ut4a{el%JUaJPA^p ze~6=+vNmpp(*nrD%>mY;7PiHq$bEh_aDzR(*hY5&E>QcmUFe>X@_l^-0ZY(LOEZzE z7Gj}xWeMfE&|8}EYf*+p%>bH}^VR;3`_{SyQ*aZ8LC-Tzl*^GI4M4t zw|3Sw79<&-=ujHJa#Dx8EMnE(&*hDPZzNkRpEF4~-0DtpU=XhQExxrY&$+Y=;pgv& zoGD__`6gPDk<>u&-~A!_@aZEb288iYM~vZ#hE+&XT58@2+fX(IAIUwS=hUu*&5}%8 z(_LV#an5NAx@`dqhD;)e2km}>m2olhlbwO2!wP{F5`m`D6gXHVG<_I9`SJ`xch_53Yj334PdA^p2?Jz<+v|@XgP2UY=&WK4m37f&%{}*?hoOy>R(%e}YWh z(T#s*H2xl8@dk@Z7ZhjEj(0MQjl|ws?ww&8?@kNS`LSiG{?!c>xMwPr8l&Ohs&h!B z)N}w5lP>peP9-5}s_BQUD5tROiQv>YY#3cJerwl=Uy;Msl-QRsOg^o8P{>ySM>DY$ zZ!hx*Ty!#{48|-6`qInxEmRP#B)@I=6OeZF-Xm{>Too7+E>WjV#y0;VDViOQZT)G! zDVh8T)D&nZIaj(4nMCey4yTvCMN8qmYd34?Bfd`J`!)zeVdl{vy-BbjPt6sS(K^>w zm1Vx>0oCwG1XR3sAQ3>8YN+Xt^feNvXzbbL;>Pus}Uu znle+dq?fH40$vIlvcOF)(|oZs;9<4zR<`b!amK!u%Lvf2AYsGA$vcavgH)fUWQfUH z>aV>p(%m)6*||iC2A`_lnkfpG6Tea63P&m(W? zgcYxg)J?h}TM$U^i5kJdoyyuVi zEQ?KEN)Ovom#{b%+&((ozH5I{&&B6o{LNUuHplvly9uNGD}RG&_u>AcZ2x@ztwFP) znZCJ=qrNL0$lny8zyADH%Kq*7|5t!$zkauMFs0MC(>F9Trn9m&WwxOE=bQer19z~s zlGC>_wjyTuFA+%l%M=oYN6>O*IZ1#9A(5`hphHe2kqtJCHJv}4wQSG39e2aLnQQ8L zwtt2(FZD&w>q!*z29PTh=Y(%^la=XtyyZP*c1gMp(Sx_Ja2YJN6zt-hM8ZF*ETbA!A*e)_889S+x7MZf)D=WrD zE3fXx@lZZUh$!4JK9bU=H^zLPR^l)gS_bNUMG5gX{x40!W@kW9JG7hIsG<3N#8l&1 z1Q6g_2PLc(?VgxH#SK}4)>^T|9nY*RKRA@Htd(vZP+?3pcS3X(kr&$dxh}AszIr}s zhs{L2649N3?d}wTEr8NM0)~DSCq1Lv$ zLSC=;EE%*5f5f!$7Ci<`;}>TN1H@#l){f~OGaJ&(FsTOFf|NBIf`v7QN>$%~1OJ8V zE(ZJ(#xFR!{zqlye}P8EzoRip(OPyv4#np>m8xQ>4+m7&-QGY|CpBxN@ zH1P2A)|zNAWO%&{@;-)IGrh51#(=e>A91$A&WQA@N#r)IodaFPb^)bz+YVi%&jW!s z9hxB>ooJA_uYm*|ju_*`vE3uFiWv2nFgiPr!g8jm)s1c`_^o5z_^g|%9sB$i@FXTi z3$o!A=;&0Ud65OXu<*`xlZt$gN8ke;c?rQ+hurx^l!EP21dBRD@Iy~J9i#?Xqp>wY zc<|-iPf5J=#ma^Ny;_~%ywC|CS)?Cmref1WEEY?I9ic}XGFg(qH0!>IDB6e;&+3O) zP2z6V%u~z*O_TJ`J9dm?~p0XrU69F z>3x%Ha^mP~J<|@0*Ft%C(Q^n2X&BHhWeyrvqQi-T3F;U&=4K>F0$9{u-%&%v-*tNx zP#Yc(qUI%x&RQlbD9V2Q^tiXsGG)d(z^9SE0bRqWPH6N?Y(~kn)tfeer!XxGK{Ra( zc~q@0k;`Qgoa-eZJ!@>#>P4~Pr#Y0~#M0}^Jw@?$oJJ(TA@Gi*8X3*(PhJ0=UFtn6 zr}+C8C^6pV0M3tLvy1vv6!^Cj-09>ur>FYd9H_^MASuPv1&)W*W%Wjg^_ZQ%AnTMd zldk#&Sz54vO~wDyyX$`eS*HJj?3N6&Ji;Ft%?>AR>Z+h!I)BuSpnCF6^VTv0W-#gS zF21eoM$MLvscZAR7(HezZ)D`&K^Xkr5XR{>v@!<%HKUp7$+TCKi6!A&K?o0fcJPwX^t_g)9!hmYkA8 zQzliHk56&!*=V=JwiVr2g4dZ_)P|umgWYVNb(*qK%}^|HEQmncp1W@2Vo?|YjM0dy zduj^{9;YZK5^4zpBs4N5o6Ns{Vn8l-D6{tX1H8#1RvYx*x}}fA?-=G2h5W5QVVP;? z+F8u4y0LVgIL0V=2xf~y_&cYMZf0R>u|a3CS>~z7(hb;`&4!X<+8yu;O0yq80(?G| zA@`u%&s=Mv)}*(;Jy;YR&oCgE%X|XB1ij=?27ck(MPqetaCS*bDMJocH-SJ`I*mT8 zO%i3xK3KnV_NF5gwv6%xSBD^jBW87Fa1=o=YT0H=ArW$;G71npRq$& z*K<3p!WFUkz6=##-cmrnj8OFru@GNXC1*1Tum`@pauFh^IUcxD+Z+N@+dKkW)j0+B zvDXYo=hBF6cX>?Cml^n3i+W_T-}5)@z;+Q(3hj^hrRE4YAHS|5S5 zusP-RSD3fnB%lxONCEpTl$%5MO}mx)6dm}t2d!CTaIOIw1HSMasnGKa$X|%futB(2 z`9dtw{}p1H{{^u>Q2rEGX}8k?Hz9lo*M1%OXh~eKY{HSnxlpU``dsEMHl}0Oa=Y@8 zA_ca3z^QI~ATM&mOoDM(Ac@j0Pnk?7UMF09?-$Q8IbsF=B-nzfV}1SJ-YCEBdWWg; z*2(j%`kLrX^|Sk~?`ua_@`E8UC7Q@>JiIdAY4(ET9m}p>Y4An^Z#*pDGrXu!h94*d zZ47nGljZzocFh25x2hnBtQe%0*4sy(I`!D2#m^RsmlTeI^6E>_@%#I)Y2|TB_9)$Z z^G4&mFh;q_nA@;8%x0LTh%_shjLHuB7-e7zl{Ze!LRP?-_f4ZG`dK4>%bvrLw2?rI zktqt{tyuTOh(`7hhgw?s3b^$VYF%44cEY(s^L(Jfs$xe~LVsjJ0#7uUq#8Cy0SoBu zis5Qb`PJ;=3{pl$ip(-joE=9x@I0SMxMs@5R-w{gNtDha=D-I!3X% z`}uT#b2_ij)rEY#Xv?L*@{dj%E)2^jq5lV3#~X{g6~54l_kV>}mj6QQKPUmKYUvQe zKPUl)@Q^H4w-iIV^xr8#yTMBQlTEKIBNi+;{apZGFaFn_X<&bbUbFd)FFJ6-G2?z# zv%}{@7(tmV4bXSN0KYCPsEmFmJ-+P?j0y)D>Fx9b18o=lD5ovQ?15RkgB(==umSfv-rh@Q# zec@b3^9xq^$e2uQLh{74d?-$8{}wmKsraMeJM&{>YiBcEsmiC+VC68fig;1A=*7Ns*yeTp_Y$8k%kd^m{-r*aXkOT z(-&BEh338SJiBP2=n{+5j@yzkO=z7;P{K}!z3np%0!M|q&G0XdH8v%=>#$1m!%LuO zDXn0Hm1t1tE&2wPVTf8y^yd5{NI>9excd#Uu5(G4A}N*Fh~cg`mV<9g!`B)jN+HTn z7PW&bt0;3guPDvELIf*^wx-zUX&Af+lEU(gRL{xAmW>1$7Gv7_RDx2A1z3gB9dw;V zDUlAIK0}j8i_c84^QAG0b?v2^#I3;=nTp?>B?@@|EIB-)jSbsn6`~q779Dy)I37R8 z*`qzhIhVhWUd8hSAZ5AVgYz0>%1BO-e4%v_?+dL&l_`f=dA5CPM1eeqaCS%EUXd{r zb$tmfa#$7z^WG8vg%A9dQh`nvjeod8J#Mt+Vq*D+r}Y&^=L^sN1FZ}p`Xqm$mGJ)x zt*n1XYm|bvpIDDNs9e@A*cjN9|a~AF=3$aY-JJdhw`+w8~R44Os~-UTV-IUX!z!ndD4pB4~ha z%n8mm-{$U`q%x{EsVP$fp zp4a4b)GoZ<*YpG9>QYz>{P@a2ZWL8pMZUh?Gv|cV-^1+S(&V|IItJ{qw9~fM@lv@&X_d? zoh-oL^5*|m#c%(8V{{QxQTLI-R-r#*A>#;(o*Dk;uyY6V*U4LDfgIWYHCf^G zANMN#FSsJxKhUA5X^ZsN$t#Dp+=L$JVQH;g>7?1NT(M-9u9P1ZOc_@UKm27U*B@`Z zatSy42gTQKhExF={{x5@JIZ(1&4m9b&wSNrCe!g)tJ^Wnwx`ES7?^~c-X45~iC$jr zFqm+H)F!`lR07KdtAcb{jaWwbapdxE~eV6=AbcIY5FQNK5~=C5Lh(|!g9Yx==2eN&9I=0d2-{R?GtZEo>md`1ASh1$q|x?f#NJ+-gWZv*X` z{1@r9La{30b>o<4{Ww=0z1>Vd+VukQ2u&QCu;C*I%e!$GiB^A?9pPp8*KL+4BQX@^ zw26Z$#j6w@!Qe)8%S;H)LCavtf`aX`5ypI%Pi<8qGzVE6r0kE{BP=6n5hLlSVWh=_ z{MUKOiE=bVKGwZ2=J^M*vEhOAeEX<-g~2rg5;#s7v1GnAT-!>KKM7Bh{4Pn|4|iF?I&4UYxk z)7vFOyOSKr!5+jIR^2509oeYbw8NrRyg(dPc5?^u7hH)WUTGD-l9|PF$xO4#TE1>sN8-+m26PNOe^+^C8OFLwuVQ(90&jJB8L#<VrcMneM?cSiWjBuU$c0}(!(`vVic zX2&v3AupPr=B-HyHI5G0WIMZu8JS*^gDoVPK{s{|9f4f60W;lH1|@+Gn^XALd+FU| z`|m!R6nWtr9q4=rb&~x!mvH&`ow zNixdCYzc~p*Vfy4G<1ZeAvupQT~4tK35nbuRKm(H-Yle?OwmGCJRq)7il|OP+5##V zD(~01NE2rs>A?~#jyNUoUU%VAp1Mb3UyGXT`7%=QT2VoiiIYmpV^i4`RMk+ZdDwbA z3m_Xjoe?GYv2b~PYppu1`J15qXlQvDOL^IYY06n0=OfBM7`0JNdh)5FwI?fyG6&glZB4O!SyDivZTTRUYUuAL^Js(lE(4e2{FNddXf4oYO~b5yk;`dQQ)>Crb)EdoQ0aSh%4jrD)v%4 z^;R?0WA;FUS)$6lo;~v(sih8utN?|TQ-*w%_z4Fq0arjdyVl?WqYr3;{@d6kqZAkI zyv3@3WRr7rtT|S3DE`D(hin}3fJ4S(tkaS~nMr%_fl;TI0FiFo4T?`cHJ%FuQ-<%y zb=XT;WXc^AX3cJGBvEGP_}C1`D;S)jkw^)#F>z4u{N$NS`QoS>Y|VrlNRJV@-A?0L zo1$ap-XpRBsJ6((Jh%s?Q;tTXl0=kc;f3@^c;{GF663aj)^H8SD=b;h(V=VR2cA+$ zg5xn4{LTjBpPzi;FA0%+2c?m&x9H`+?wUf7BuL~WXk|%R7PcvAhMfN>5AWPoNA^6h zOOI*e5&j`K;Q4U;7(TXJ`b4_3#r*7hKNy+9?K$ndiA|M{|ahG--cN>YR+9b8(AwkLY!;6;Oq`A zqQ;4WrnIcOidM+*;CzWnRWYry>dTC8;C`8Oob_gY_$}hJ`^Z{Tdu3M4kG6~0GDM}h zW+gwlD_Y>5tditZK7yvDaT-xPj>O#`bh^8G)?Ju#OH(Lk!Rd+z2W)0^bv*#oBJwQR zvx>4Sm1!mBU5916V-e#S#l{NwN=!R3Cyju|*xUtaYH}T)6D?llmmSo}aI1`L?1rgH zMRO?)*Axd;S%6Z!WR#g}$#3Q+C%2&0*h$OvYgqi+hY>oJ0tug0h0;DbBSzT~L&vAv zdZ&ISg~?@ajb<%vu9|?;I!&ydm*m1_bK=*cEyeX-L=r>KL0J$}D6X3Fq$7(1U&dY9!Kba3v;fFLX5q zK8Wa#Phy~Dryx63zS}~o@_}M!`14OP))EmVuWHPLJi-MKf^yW21l0z zX0_oR0h?Fb-3NxFrAL!dAjbZRn?h#Z%Y9-9vZx>!${*M*p$Govi>0Wj;Wz<3rL zie%!Q+~+dIiz4CZCH6W|m7~I4AZq!ezh6ebP1nd7i3V`bGZLJ$6Y7r9g*yoSK{y}t zz=CC^-RV0z`Ldj91un`hjW~b~o*h-yjulCWqPB|#!)e=~O=EE~?MYRf^n-AWi*Zkl zd`%4pOAQld$7U(*b!SJHtVK96WH_IV^q_16rz{ci0!XXLW>VDwy43t=TEDHx|F9{D z?@S7}he+C|r5t8PJpiKYCxdhjz3lRDa>GSmNEt7Bly|_4jxTn#2g~?@PmX%32b0_I zP@B!72cqc*+JTT|MH5dQ9YyVj*Brx=#ij}yFfd(Y!vXjNIQfX=$JkCJ&w-rIKu>cu$|>;m2=%J)dC*UUIxD2N^S4EOIy7NQA3Eo1K!X6VJxw)+m@{CMd>zgvMRxvjuG zVXs2_Cn!fVFqmIffuER{3E<+aO)_SIaDAF%XbNy=5%omX5m{%Y2yb*m{7rt`?}0lJ zLZzvAa{$th7C24wB22&*$mL2kUGVtw^(L#M+cU;g|TqVPvSTOJe*pc$?reChb2`gip|sADdFJjlpB zo8t|J^R)gnC7Gy~mr3R2Qsj&7Fst+v<33>;hi_+W5PX&17LqK?1VW2h)j2rJ8&(9mL9p2yjhO)Uxrr~Xz)q`BjT19&nxE=OUGWSiK(<9DH zW+PlIosy!ED`#$O+sOT%&RQ|pPMz><7OmoYBJtt|esE|Jp+h5$q(%$6Dfzog(c&!MisModzoEKu2a+AWi{r}fDLTA3 zLFPd1H4u2w2F^?r5h)C#3%ul`yfjAB?M=krqr&RK?pbo~x2g=Ruy_d$uz^u>vF6a# z<_@?hFgT7%0W|6&vozXxmi0>%k{eWV+r1x>r=59tu$#rYua4oEjy1Tp)Jl?OGAJsx zThZQn6k;kiBw3xES(1mXzk3{F&l<l zjnUYnzxZPYX+Cmhn77Rh}mXxj{GK56OmJ}i;%VoI9z8P7NCHw zrBCKr}rZoG9s;h;o`b!d@lH_XcoK6h>5XUXj&|Ca0AB(~@F^$z^32y$)Jke%l%>WjvF`K@8*j}wQLsX$&4B2Yinbe<#LFw=v z>=?hnVf(iCr$l;gl5DDAqm1C;>Qw^%*eHsMRi#h8HRq zT6A{neSws#=8b{2!{96^OR;oids;(Q936KUK0HH4%}gV8E#cS zrdB-8E17Ryxn(Ejbpj666r`9yK4Vp0$aH3J=|Db*eMgxY96>Em%vYsN4KAct=5KXD zJ_kNYCedL#2NTf+(ieYhBcNu6NpOG?Us>;-)d+`>mIDw`(g_6e(~a_ACbPKPVHpH5 zB9*rg$o4R$7cmS-b?AkvQio2hM@J_C%!Nu4Y+B4#6XMDNX}B6xuEDUKaGm1Gj69m1 zk5=+$YYI{`$@V}ddMN0Y2F(P=p`0Mtbz`m*#Hz6f6PoWE9`ov!(w3Dy*5a1_&DI@8 z>Wd^4=}qxxdzZ#l48qo`qrCxb%tG4 z;%b_9_7;w}>WrzWV)VsR8Rf=PRiyRquX5cqLU0@^NkcN-+`87;ZC*B%BQT@f$j z)fry~nTjbE@4qxKYEve%L~tPMUYGVsYO3+e0!xxgYEJ5lZk^6g!i43?_AzL^8h91u zh}NtEBxnKWul{pAfn9iye7#$v43p`&kEo3!wO)xKf+)<`AP6O_L(} z(V!bm6MNIy$6P|aAnk#80eWFet0=e^r>enfs-yKmP{pualZWc%b(yWMQ7LCXXSls1*hGGG{@giKwn<2W*RSe%G*Re1jolcPtc zFs3zyNp4&5Cy$|UH30?BM}b>gU{Ht;arJlQ$eA$-@v2Gi1p*tcoF|W@Z?G#=5mE<* zGh=30h@7_JJGMG% zXeY*EUDtLP3C~U;?o~y(jkcF*n-YL9*S5XNZd`X!MfZ1AD+G zj@B|cA6SCgZZ<#<=`g7~&L#^5YI1%duy~U~p*%f^%zr3UHL?-;p zfeixpHC@((GJYv!R4qDUTai=)_G^EYOVr&Io#ca6ZtE)SGYde_?)9b2-=)YGQPE>} z*g;npKDf${RY*=(7kH?HWriT754oapIMhO!vljS3qRZO^U8Z=O&YYwuSv=RhK(l+& zF-|?6Q>j9n1H+Ri8KZ%s(C%vS!g{gZn;$Jy0w62HgJv$xrjFSer9acWM~*=9-D^1#^)d2RX(HplIHve=&xK5+quTuIo9tr@hf zA#Ybf5uWCC8Rl8Udri#L`iXlY3sK&?dUBFY( zsV`9RzTeZYN9&oqYzn$L?*KJk3C1Q0s=0nU!4>JG>+}I&!{rJGx5=HHeZ8M3KPZtZ z5zMs<@R#lg5nw~G_r)Cf|J&`h|2duTpLIuJ7h@Zzztcy@zf;F7C22=&VFYi(v3M1o zk!B=plo9dF*zZ*bkOD7aDE%Q;$k;?%1GqtJa_?@<%LM zlA+(fisE}ydzz3b)h$hnKQ_wO5@~}HK8W0ishlYZH|3Ou?%s=|NPj!XCB>mLCo2(m zc_@Cj|1trdllH@Ru$(D%a%=f)F(9{eBk7S&{}QkZr4ze?HFln&$@? zR+C%*DD=1{d!z@4^rPpuX3gt=i`N}w9fg5&Ob5>-$B0LA_@D>3r0^%6_TTWKxYhEn8J2zkVMmVxE%Yo#uC5N z&jP~1D^`s?wi0zX_v4;T#9>ZM1`rP)d5A6I;1K&!75C8`X9XMI!xVp}%owW}aCif2 z7nslBMFpS6fxnLQ$Yr zK^{~d56wy*+l#LkA~AnSK?%d;r8STQR!2h#PqR%=@0oxhj<+{`D<-V zhT}|j$1^dXkI$cQ*3Dkctl&;?#evr7jMgH>m*!~Z>qerW4)M(edwh5&?m;5dG%*8( zlGnOuGPm-*wDrJM3fKjJ_0j7Ipv(AdjnsFfs+`_(zPrIDxyTyE)}KJVoSIrj8Cp1a zu7JK`9Czi!xnb4LpMuJ+P?Ez?CFDVY zf?Kqu>|t~n?Q-iFz1NGdFnEK*f;J5+^QCi7PB4N79h*VnF&&C zb+^2-14{y2XFn;p-j72G@VE;cP%p^)^=TCR(+l^SYyyHAX_m@%i)EXii41GHi!;si zNO1?dP?G@XXfXuOZSm$erVtWd@)VCu=@n3YX?3w>u$1s?l%t)-pX0BoerZ=$S1sge z+!ecenH$74Fg!?2kBvjI5$%K!g%j1~Ak?<&N&LVKpYN>Xf^ucd#*)yp4>7VyyjTie zwcXh~`yHEnd=7y5&+o9aJ%zF?i7H*^GUhVn+kTY(9{ZtX)eGG@E~HbD$BKrYVqS&9 zfD|*Sz&?4c;pfDUi4YZ4bzeP7df-*6*{L#3kY|r@ARZ*VK4ZS?jVJIV$!FS*}R=iC{A+})d4ds z^}~Koem5Ayo{DU^*Ro#O)0b$a^;OZ6dpOQ*q91YIncIF(U}Z-9s9c`{0niN9iR?LS^?p!tut#HDQYjnt&2{x$rfRG~bPM=*U<(R2t{ zQ$rW{Z}U07V{ZTpU|Cp&GLW*5)?;`46j*SfsUnd#UlF6iCvZ)Vf9!@o^`2`q$NoNw z&?1h#UMzj{-hJ~Yl-Ju-g|VK7>&3mXf$Jgb=6TxdAmz{VrDN$2sy`PY0si3(s0Th$ zdh;`9p1)5ADNvtZ^Y#}NoOXTgo_@M8}8qk@W~w5GdvG6 zc7oZW+S)$sUHNo^+@Or#-0y7}c*TT2ztsVic)8_Z?A(k%-2S+GBH(l8y&S;2vtJI0 zdAXJ6;|-3fcnO5hK}qI48YuC8iG@r0BCrh_o6;7lzSI z-Tx5|d1#J54Re70(Hd&1q@^IQB!_&~BlyF6aGGRbxD-(~Z7(uw)0q&bEB!cU*@Q5rMJSnqY9!C}iI8E5neY$oe?;fq?KT?U+IhOE$y(tB3`2J64oJL0#n> zMqLzWQ~SQmdNaxN$=vX4xA3S?iVRm(ZX>RFep(0YU0^9*hq$qOjKGlH z@M#T-siEX76xfzc7j;p1J{gn7C}b)VMGhf!)t<<4aI|R1)qMVIeADZF=y z9KCco)&@1OnvEaqPj*-<2c^`JvQ$~?q#UfdNAG0RYFlNR-0W^X0_$*AEr*D%{)%Ue zTZ;O!T2Li$Q3{_)T|4kL=DU*$wrm_=(6@~$ws{~wnlWs<(D;Fj=ZFTawGl>`tp5s z*af|_UnviHdJ8OZr8GfssYKOsw5BIYUdjV2x0%5MZaUmDNRvTNO~JoUmv5cFWI34D z@;w))INy~H=b%?x3-(YhB`?W=mb?7mo81mdo%vfHFWmv4$I=(SVElbitS5sUe^mc( zZ;;lfo4lAzdHW++KK?ltFPJ{ndd7>)$nAy~3e&OiSU!Hblxm7uh*Gkn_nIevRt}nv zVlCab@a9-PpnFvAuwi>pe}2et2ls&ppt9uR6Wn^DNu_8_wcItm%c56?pu!bHmc<{aoBF= z4B%RChWOPfXcrY}otD)n&V;|&vLf5=YQ;Od!-Il-I%h1rZrmGCEJy`A!o~V56ygzL z;L&df@TO;FUtB1G2+DY}W1oaY-1Lm8tuHc+X6({@b>UdUBu<&jvZO zZ*U&GUk7`_%aD52v!gn60soQEWATFhr+N?nr6gEzmv={k$eMOyy)dGgabn%%3IWzu zNMxvo`2+jYeyRGz%$Tdf$a}?Zd+g4Lny$J+O276(P1txti>HpAQd5Wbvbo!4152C? zhC?vhYz0LnIpO-MCbcS~At{U!{*WAdmRbU~$l`iN?<2 zK3F-S*b-|$A7C=<6r&}nc64_GyG28+A}?^ch3Ut;w$_=aQ`dggo)H}jHysj+(N2y_ zJnmwn(8oA|bJGNx1;*5zc(1M%foY+Xk%l&9DbGV`rDl|N40%3@8-z`<*tq-4*m(&| zhb>gA#j|p9(-uphVRBL@8DnW?pkc#qvM_KsqgmvVW9Sl}x367n>F70)XPeJL17e;V zGJewz6}NL^I{MxYAuFS!H2SO!l||CqSvZY-W!&UiB<;$p@{kax^%RZGVbgm| zc`8zF#SQg3J_|4-;SF6QiI?kK3PkI)fn?}o(1APpf0Vsra3x&VE!rL1R>wvMJGO1x zwvCRhj_ssl+qP{x*|F0%@Asbfo^!tX>bZ4m|Jt>y_K#Vs)|_jMImRHPV94;bJB_Pw zq&ikf+Bs9FONwi@6xX^VzEj{>4S~ znGAHpLUx}SZl>5h?3T*3$QHD@V_8^1^G>O0c)_Nvr0UbdNdefkgGHaS4QLkEyrZ0@ zGZ={=vtb~&1SS1O>29M@KkW5Lzatzw#-L4_>S#fCX@R$@#f5j?6klGanhp1b0Q69# zCc_2lRVNz|4CzQq#@hvAqSe1U$t;*{3Ukm_57m7v#N z!O2FhzRp=ApT9lxM8iuv8SNAkvo@m5_T)k7jD%HFS#QxSj4KMzE8U_8h^o=s*FP~e zWeQm-ry?|B%qmlDNmEUEjQ0W1c&Fu`NFo)i=>+OgadN~oGK|#wm05Rf`&=>=pMLHx zD?EY~?X!o2T?L0TkBFzb*7}Ab7v4L7xT46o(*Z0?&*je_8e|Dg`MD$6dUEYzTW(v> z)wmnv#~T?H8q~L8i&_dQ18m@4%&l?<@ihY965=5e_av|dGj6l zZ2Le-#{1#|j{_SxhZ>?s`(Dys-mR=oW-kD9JM*pH-}g_*{AUmq{J>O;ev^%aej9u@d$tfS&a3@^ zkl!&Hg)Zi)iTxcRp>xCqyYVruv?n9PB?gQkWUc$PAry=U05n7O8b)sljjmV& zm40UUuS-5&U|qa51}GR3x$4q2N+%bj+S{xbVIQ)qt?v4#9~I6>gO5_9qwlh=M!TD( z(RS73%3Y<)#NnUhsv!;zb!qu-v*0U`#qE2`>eL*aYA zewZ1)9PJY8l5ow$vbG>+-Iw+Qoq*l36R}Bro2uuR7A!Tf{!gYa1<3F5autCH+#lCd zKwik;;+sHkk-&5@BSFt4YF2dDOH#AOJ-nHsB4h_)pVJk79?{|EM8#Ef!(2>6E$IBgt1@XE- zs{pzqytLjaBa0S#XgIijCVOx-c(~pLU}8Yd4Xg&HAVH9^ZAg~}N}k36(K2x3+c1vM zcG>KgSR0Lq^bQu3>^F9m_s>`eyb9*1Oy96EYt^6)hw_BCB8cT4h?51*46$qOa$ zbx-(9v$rLz6nwBKK}|qfaOa-0!_@q1aKLsy8Nh6|=t$+hZ-~>Szv@F=O&r8j+zXe-m`~Ubm;A=xS_$nhZ60h; zF?5zt$N}w9e813IGru)9cRz`tHt7__KpPlhY;ADIn0mH)=m{Zt7^C1t;4=yvrPBOZ zibcW|%_+GA$Jhg!Njh@D?=JFDt^vw|H;>pIT!3#RW4g5lP=_iqT7-01 z%J%JPg<1)lHLJguFrWLL-Y)ris<}ybSDfy}rf+@#yA`e{$Zc>02Oo`1nVqiPy5Ba_ zGCuCEzu-|^*WF`;ivbD7OvU)V-@h!tOH?v@BdOQoRc8b14c#Sr$ElS&h^?o=9drlF zX981^>xo>MU|J%OrXb?con!}TrO};Q2)mBZ(a_YXoBA;PMHsb}cfb@-u&Tb%Lo!y+ zc}om}V4!ylzYDBj7AvC{vvmY6!d^X%LEQg~;1 z(5JLYi9&yQ6(gAsfJTeYh~u*mQ>Ln3p|Q1aFtqTU7#zCLq{Lw(Ns3v{I-0dw;Rw4_ zTcln2hV;H2aW46#_wq?j!{H_r4^oT;V_%8GhRDyc-oIOHG7dhiY)3GLG?LPjoZ8c2 z@Wjol>pw3CRt}h6!-UZcnJ=PPTZ*+q&13GHXBL}(PRuNKFdDRrUDhR81U=HhRgxz6@1VJuhtYZ#d{|}HwVl@d%+f9Qo?L6w&EkZSX!5SCdr8Qu|-QJ9sHNp*;i z48ek65uUByae=qnff9P|KG0w3GGsE4D(L4v$L5H+q;yy6*J`OSz)~Bik?UV~4~1F2 zO^1qf1Hc(#_Ip;(>?V|R(U*wcWQROCB;~zD*|rJuWj1Ej5U^Ue?S|+V?1E}90*QDH zPb{mZ^Bh@e=v9^(*L4ojr#M}SDt3*$^LLcsb9SA;^~|3YYd&F8usJgjfAj-=FliO7 zM2H)!2Z7NccD1nvMv;l*GYlrM8LH};arqNY!B!S=2Q`r*n$cFz2-{X+Bm%m^6j!t1 zQk*xOS?;L#@SzUEy@)uz19I8>ABO@T`KK)M8AUMCC*Znr#q{w$qgMEqG41=#6Azi} zF0-GiDW*>4u#!A^1p}M?oD5J3@3ZxFb|NNkXRVQUrB}C^m$V7t7ABYEGoxu7igLf2 z%$}t=DAp3uQrwp%DlIv_cd8$#in1;N+Qs%~amr{KKtw`Q(Xa}F1Jk1VgN-+%zvH@& zcqx^;gt&k?Y|yu6&j>6({$j#==Cj$aq7BB=!kOn%X`)qNm80}HH$U2AXByCiO1D;U zLVP6fiH(qKUC2?hIB(qba+3}^h3ta#&(Q@h6`M_zW1;0xYR~1MtOCIbA^Zfn#~#{m zcmv}}J6INVva5*DpU@K!v)*A2BSbDduix&GM$*NSz*4{_d0WsV{D zwZa-+=6@1ZoeU?!7 zi&o>W5;pFj*M#NoSHMdwCyL+@tydc*{EAF%gjzq~B~ln#wlIZP_Zfeb7@MfaJQlcU zOq{rQbqqd7AZ|IrmLK7PC!$EEY1S$h&a*Qd{;`5|)*dJ}*IcuY1Jd9K8LtK0G|xvN z%8|gn1S2TWC|ay^_Wu!lt@kgC?W`Dv#ODiN6M_Aw@$-L--uQpp z1NB_EG!yd{kL+Byd>fLS*4?)1bl7h~su4F&9#+<1x0nOEDDTfS2ZYM@D#lTvWyM>7wT#E2dPDSn-8vvAn0W zy46$cpfYKGLwKg7O`=@(j8m%{CR7fpYPAtcejdlT(u*!fVxHA=-;I&5`A}(|ZvQ;i z`AXPqANjO%w$_!qN&l31re+!{wasz$gJ0HGYhBg?bpiB4XRm!X^T{KW)-v2#T~PG` z67L)39Z6!&$gIkK8{uDE%=C8(aQo`|i>nDQsAi1kNc;It9J6-s$B{?Gna3$MTJM`o zk(lpJ-y*f}jB>=xYtrYndoR=a+S3F-XsGY;7sp>m_LZ)5J)_$(JJLeNuYQU~ZQTK$ zY7ff8vfdsr|8)YEBM338zT`o8|0oY4{m0(^uM_aU8oIiNHrg`&-%ovm5Ql{tQDV!< zKc!(kmWEM-B!^L0{3NBlc&6$QSoIe(n*uDI*Q}lM?G~P7m7R0xEA$Nw68}O~+duBR zuHW9aF7`lZYTp^T?!3C6J~q3byu5Guu04>7%;N-L?RvG~J0^R4Ft%dc)Jbyy4&A{- znE;?aIO;K6$NaBgr-)~IPz}^X42=B>Vp(kW=3vQ=;hu)@Cr$O@lgJxhSj4?Nn2m_1 zjA#E~#62N$Uh6#)4Bm)X?B|wnxzy*va5J>Jm1&yHM<#av|zjYuj$^u`>_BiK>eC#emRkU=KKD&+_O7-x|V$MOMNa0 z_oMps!+nkorhi{X3Byt}l%&!iHI&4DDcV5mN1E?55R?d}!q78`r)r{#l+iF8Q5K5-fnVOYzETbAnuN_MmHx4FR1Zl7AEO@b3+r9~eM0ilpF41==&lv-grDoqF z9o|&Ty*2GcY4m;H$peLqePVHIhRxTZ$V`;wJ}nH{?-W>*g1<)j?TX)`D!+MH61qQ? znuz7FFX89@7Ve(H$9+*es*otonI;X7Z7CRnGb#V|YlresTIuOgb#C3aPL<1@rHHNh zGW`MgjxV#T=9JrCoxj!FU&09I&Jf#v73t`XU1I;hx1aZ!;-6E|e1)d)7?AKf;}WBl z$#w+GIJQbt`*p?{$mZ+@pa7YcQ)tK{&0Cj=c7wPo-C?TSEOR&gWjg$Hj5$IX6pMbc zwQqH~zLAIE#|>D?mVFz89fwt4lOx-x&CC@4xo3jb7p$W6No2N4Nhb?qiD}4F34f)U zxnUTkIE_I;SDIeUcPiOsh)kQ&U6r|$ef#T9mQo^$jyBr@t?=VOfTCzH1w8MGAq&1r z<)AJ}B2L4p94>uuo~yoa0?Qe6SjzN>=ny<9dqln--HC80K{rlFJ<}oZrdG(d??JZB zc{n-JHGiyeZUG6Pt%YTr<$&+&xd07Qppl@w16#Zb{Mk5e<;cs(&9~)|i}YvX6k#79 z`)>YwH?zQNoD?&SGCq>oo3E!k?PaXV?QV1|q%MMpA&iH+9QcS~3pCM9&|#+~}}BCKRZtU|RN<|Kxd)JH2w4!F3u z==TsptZQ`=mNrp>9wqDJ#w}FEfoGJCcnTh630PM_dnA%H2mM z?98dTxvX0?U2hv&_!*SAV+&K(8ck&wh0?88$=cypjmC9b$szIF$bY$K3{Pc_4t^*! zu}Hz51N;6opAw`kYinxU53c8F+8Eh1D?%on)&|RE<9NbJS5GOA$ux(Q6%ek$pVk~| zu9`_vFg0DIoLhGwxz(*6J+b|nG7(Rq+nh5R`L2a9_V8=`M{(>C3xhQ)-M)~J9FgbVenFL^Bz?y@!le<_0)u+OTgVx&X{AlmwlB!b1n({Jsh;{Zr z=Al+B)=PjNyydMl;^HXM_Hs;&4QtMBoNRMW& z@3b7DYr;#>ve_uwXfoYBXxKHPJxGUVPsAizK6i*EilGBdNY(1Vw=h$NPjHICl*PY@ zcuui3_`rf@2OYb4YJd@l_wW;!JMpPHoRD98ZGTgh}J0s|dg za(g9euBAh~0?w?f`I}Wd&G<79$!4bQ(2skIM`s4W0qhwJzPJ7k7>&7_TD-kQ$EwYX ze^syjYsEy=Gis}TlLtaDv@2%m%2{m83)P=iD*=aAC^u>Y0On&0XN;he2L`a^!s^Q6 z@WXN+M1Zq9cuTi$LWu(X0eZ1|%uKJ;DuO~l5;0}=MftHNl0{mh*435%B!HKfLXX~n z>8VXZt$ew%+9Y1{GH^UXaxRZf*yd*b0tsIl8-LAwW%;#(@Dw4$>Q^~Ed%%$b1dCaR z{d!ev=uQ;Mh0_8jVpnk!mLh^s>}X?FmWL8zu}-##g`` zvZ0U7aj+0zyX+jZW3g1La8Hx7{;f0x=boYu1b!QndS(?5hgwjgxhygh7w?8C+cq+O z&1g*te3mn77WFLO;IIQ2WZJ|xkz`mLs+wKm!gTyVWOAm|t~6L{9(k$!MB#HwNue8+ zYu}g4&I}ZSDd0T-lXZ*<`?VKVdR~iRAJ2H1xsTmMv78rSlGdZ()}cb10c+JnsdUnv zB{HG8GLv~USUkc_+ddG-#+~h|9!?uCd^MlNQE;Tg=#r+llfx&hKXP|nzlWrY75Oei z{$xi|F<6NOg48PsXB325I$VvC$q%pT)@J@f8fB6Ckyv_?9x}Ksvgz`mu`;i|@k56xyol!kUPIf_87Jw(MT;ESCPLas z!|#4hg4T}Os+4{_|IFM)!-X_*d`jO+>EL@sm}>cSlFO{h>|&9U`v7(Y)M?7`No`zJ zz!G(?c%UW`(&`ej1{8&T{^=)!(lVQyw3X=_dhF!!xqN%A9qO+_Muy#-F8fMiEVpnc6JEh zb}sE12Zi0^HgfcFyu%ItLc6^a6ey0(RwpPuT7oG?t``x+#@o1OUi9pTLvqLBTrsnt~7}=ZiKnR!3#nLfzyFw(`W`jUWiQSMZw36{47C(M-*%oNc0AON+mpMc}P#VU6^0d1;(_ zU;DJDldc~@tI7~n`;32L$s9S-W!fdrv@~znzIZb#~$TM~`9+=n$KEHg4?I^p9F&oSP{0 zmzU(gGhN?hp(os&3uA`*t0ZNO*^EtVQ6ZVQlfvouEapaEInn+3J@_J&=MYTNsZCiq z9p>&1#UXqSLmjF)fPq~L3e?+gp+DeW@_wso&(9Nc8a)hWZrp3}e^@zDrjxaeaCo(wp_ooc|8QOyWJDA!mX}=QfKDKI2B(!CQeRv|BF+r{0dM&Rr?B1Fis3MMu!hb$Dpe$ zC8{MSd<=}$2d|h#isvs?D9@M-rqyxVH#OQVn?Ihq=iz-;=X}W9m&VRRv?=L&s6H|J z8!_j^#-D4FI%8q#c-48F9lQO~LhZeBB3oI{(#H|%5YR%I!1d%)H;)?@rD7A%cOHH z#W>8A){81nRk?BkHKdWHA#-NzkFDw=1Im24ljZErylOZu3EX9?$~={m*s{2vGMfv< zAd=lGzhAaMdM=%im?)b^(__nsjha8v?^>3{k@6<`sdZ@yf6{K|rlK3m#X9WY4Hk}G zee&fhvTA{JoY(6B0SEWXbO{#fZ;X!f85*iNf1rf`DJT~6yG=Uf>>VtP`8N>-TI6NV z&q}tOp=MT+VbYFbi_vFcBQ-98Ia! z8W2Axnll$v_kY;WUu#IfF!dl=>BP?*SEN_ooVQVqjdm`l2qVF43C0p0qh$&Ti^}%m z9br%5WvgL(fWtm3_v)abZS?zKBcgeSgfbCO$tx)51~9pIH5StBsQ<1l%!Sh#s{1vq zps2r73!>y-FK-}D&}f7u%d+31qkV*v#IRsIxg=dbTRp4l)HZ#fz3Tclpax*4@K?Mq zE?p!NxCV$WDgeGWFr*dk#Wa25G5?LSEVQuVU*YVVr)N=t3_b%Y7_?jy7N~)T?Z0ur z*}Oi28l1#D{X*(yaq)o&|}Om#w~F6CZ$YE(D@^^*0satvKo1&OBVznv9xSP
    JN5nX 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
    Tj1!v+$xtx*dI+GHLe_`0!x-QO(~;6cfZ-l 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%0AKWfE$qTJhrf;L-7QRzS1a7;?kZ7Am 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

    y3E z293 ztf@XDj!67oeWb{A{xj#CC``F#BA9MS=ZQP`IvDO)4qXoWVoNNSFz<(Dl6K^O{vYv% BkMRHi diff --git a/lib/ostermillerutils_1_07_00.jar b/lib/ostermillerutils_1_07_00.jar deleted file mode 100644 index a9931503cb366bd2b378faebc2ba7ef847d93be7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 525947 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

    mobibot was written by Erik C. Thauvin as a replacement for the channel's @@ -122,7 +123,10 @@

    mobibot: paper
    mobibot: rock
    -
  1. Posting to Twitter and Mastodon
  2. +
  3. Posting to Twitter and Mastodon +
    mobibot: tweet hello twitter
    +
    mobibot: toot hello mastodon
    +
  4. Some of the internal features include RSS feed backlogs, rolling logs, debugging toggle and much more.

    From b20783a18e68d5605795c7053a8cc1b9da7db44b Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Wed, 4 Jan 2023 02:55:12 -0800 Subject: [PATCH 695/844] Added UrlEncoder library --- .idea/kotlinc.xml | 2 +- build.gradle | 11 ++++++----- src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt | 7 ++----- version.properties | 6 +++--- 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index 4251b72..2b8a50f 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/build.gradle b/build.gradle index e3d2267..d05bf6e 100644 --- a/build.gradle +++ b/build.gradle @@ -5,8 +5,8 @@ plugins { id 'io.gitlab.arturbosch.detekt' version '1.22.0' id 'java' id 'net.thauvin.erik.gradle.semver' version '1.0.4' - id 'org.jetbrains.kotlin.jvm' version '1.7.22' - id 'org.jetbrains.kotlin.kapt' version '1.7.22' + id 'org.jetbrains.kotlin.jvm' version '1.8.0' + id 'org.jetbrains.kotlin.kapt' version '1.8.0' id 'org.jetbrains.kotlinx.kover' version '0.6.1' id 'org.sonarqube' version '3.5.0.2730' id 'pmd' @@ -45,7 +45,7 @@ dependencies { compileOnly(semverProcessor) // PircBotX - implementation 'com.github.pircbotx:pircbotx:-SNAPSHOT' + implementation 'com.github.pircbotx:pircbotx:master-SNAPSHOT' // implementation fileTree(dir: 'lib', include: '*.jar') // Commons (mostly for PircBotX) @@ -65,7 +65,7 @@ dependencies { implementation 'org.jetbrains.kotlinx:kotlinx-cli:0.3.5' // Logging - implementation 'org.slf4j:slf4j-api:2.0.5' + implementation 'org.slf4j:slf4j-api:2.0.6' implementation "org.apache.logging.log4j:log4j-api:$versions.log4j" implementation "org.apache.logging.log4j:log4j-core:$versions.log4j" implementation "org.apache.logging.log4j:log4j-slf4j2-impl:$versions.log4j" @@ -82,11 +82,12 @@ dependencies { implementation 'net.thauvin.erik:cryptoprice:1.0.0' implementation 'net.thauvin.erik:jokeapi:0.9-SNAPSHOT' implementation 'net.thauvin.erik:pinboard-poster:1.0.3' + implementation 'net.thauvin.erik:urlencoder:1.0.0' testImplementation 'com.willowtreeapps.assertk:assertk-jvm:0.25' // testImplementation 'org.mockito.kotlin:mockito-kotlin:4.0.0' // testImplementation "org.mockito:mockito-core:4.0.0" - testImplementation 'org.testng:testng:7.6.1' + testImplementation 'org.testng:testng:7.7.1' } test { diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt index 113a0ab..bc9860d 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt @@ -33,6 +33,7 @@ package net.thauvin.erik.mobibot import net.thauvin.erik.mobibot.msg.Message import net.thauvin.erik.mobibot.msg.Message.Companion.DEFAULT_COLOR +import net.thauvin.erik.urlencoder.UrlEncoder import org.jsoup.Jsoup import org.pircbotx.Colors import org.pircbotx.PircBotX @@ -46,7 +47,6 @@ import java.io.ObjectInputStream import java.io.ObjectOutputStream import java.net.HttpURLConnection import java.net.URL -import java.net.URLEncoder import java.nio.charset.StandardCharsets import java.nio.file.Files import java.nio.file.Paths @@ -152,10 +152,7 @@ object Utils { * URL encodes the given string. */ @JvmStatic - fun String.encodeUrl(): String = URLEncoder.encode(this, StandardCharsets.UTF_8) - .replace("+", "%20") - .replace("*", "%2A") - .replace("%7E", "~") + fun String.encodeUrl(): String = UrlEncoder.encode(this) /** * Returns a property as an int. diff --git a/version.properties b/version.properties index 2090357..61222a3 100644 --- a/version.properties +++ b/version.properties @@ -1,9 +1,9 @@ #Generated by the Semver Plugin for Gradle -#Tue Dec 13 01:22:17 PST 2022 -version.buildmeta=876 +#Fri Dec 30 11:11:04 PST 2022 +version.buildmeta=936 version.major=0 version.minor=8 version.patch=0 version.prerelease=rc version.project=mobibot -version.semver=0.8.0-rc+876 +version.semver=0.8.0-rc+936 From d9e50166899696b31a2336dc90c0dd2070d07a86 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Wed, 4 Jan 2023 03:00:07 -0800 Subject: [PATCH 696/844] Fixed nix3 IP --- .../kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt | 4 ++-- version.properties | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt index 734bcb3..5ab97d7 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt @@ -48,8 +48,8 @@ class LookupTest { var result = nslookup("apple.com") assertThat(result, "lookup(apple.com)").contains("17.253.144.10") - result = nslookup("204.122.17.9") - assertThat(result, "lookup(204.122.17.9)").contains("nix3.thauvin.us") + result = nslookup("204.122.16.136") + assertThat(result, "lookup(204.122.16.136)").contains("nix3.thauvin.us") } @Test(groups = ["modules"]) diff --git a/version.properties b/version.properties index 61222a3..593b23f 100644 --- a/version.properties +++ b/version.properties @@ -1,9 +1,9 @@ #Generated by the Semver Plugin for Gradle -#Fri Dec 30 11:11:04 PST 2022 -version.buildmeta=936 +#Wed Jan 04 02:59:39 PST 2023 +version.buildmeta=939 version.major=0 version.minor=8 version.patch=0 version.prerelease=rc version.project=mobibot -version.semver=0.8.0-rc+936 +version.semver=0.8.0-rc+939 From 8c1327655661967752286238eb1389c367b8c3c0 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Thu, 5 Jan 2023 17:07:01 -0800 Subject: [PATCH 697/844] Allowed longer response from ChatGPT --- build.gradle | 2 +- .../kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt | 7 +++---- version.properties | 6 +++--- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/build.gradle b/build.gradle index d05bf6e..178326f 100644 --- a/build.gradle +++ b/build.gradle @@ -82,7 +82,7 @@ dependencies { implementation 'net.thauvin.erik:cryptoprice:1.0.0' implementation 'net.thauvin.erik:jokeapi:0.9-SNAPSHOT' implementation 'net.thauvin.erik:pinboard-poster:1.0.3' - implementation 'net.thauvin.erik:urlencoder:1.0.0' + implementation 'net.thauvin.erik:urlencoder:1.0.1' testImplementation 'com.willowtreeapps.assertk:assertk-jvm:0.25' // testImplementation 'org.mockito.kotlin:mockito-kotlin:4.0.0' diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt index 8e8423a..3a03d03 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt @@ -98,11 +98,10 @@ class ChatGpt : AbstractModule() { "model": "text-davinci-003", "prompt": $prompt, "temperature": 0, - "max_tokens": 100, + "max_tokens": 1024, "top_p": 1, "frequency_penalty": 0, - "presence_penalty": 0, - "stop": ["\n"] + "presence_penalty": 0 }""".trimIndent() ) ) @@ -127,7 +126,7 @@ class ChatGpt : AbstractModule() { } catch (e: IOException) { throw ModuleException( "chatgpt($query): IO", - "An IO error has occurred while conversing with GhatGPT.", + "An IO error has occurred while conversing with ChatGPT.", e ) } diff --git a/version.properties b/version.properties index 593b23f..c234d1f 100644 --- a/version.properties +++ b/version.properties @@ -1,9 +1,9 @@ #Generated by the Semver Plugin for Gradle -#Wed Jan 04 02:59:39 PST 2023 -version.buildmeta=939 +#Thu Jan 05 16:20:43 PST 2023 +version.buildmeta=948 version.major=0 version.minor=8 version.patch=0 version.prerelease=rc version.project=mobibot -version.semver=0.8.0-rc+939 +version.semver=0.8.0-rc+948 From 6894e05610612b50a3445aba8c87c24af75e9dca Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Thu, 12 Jan 2023 00:57:12 -0800 Subject: [PATCH 698/844] Added max-token property --- .../thauvin/erik/mobibot/modules/ChatGpt.kt | 19 ++++++++++++++----- .../erik/mobibot/modules/ChatGptTest.kt | 13 +++++++++++-- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt index 3a03d03..e2bccb0 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt @@ -34,6 +34,7 @@ package net.thauvin.erik.mobibot.modules import net.thauvin.erik.mobibot.Utils import net.thauvin.erik.mobibot.Utils.sendMessage +import org.apache.commons.text.WordUtils import org.json.JSONException import org.json.JSONObject import org.json.JSONWriter @@ -54,9 +55,9 @@ class ChatGpt : AbstractModule() { override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { if (args.isNotBlank()) { try { - val answer = chat(args.trim(), properties[CHATGPT_API_KEY]) + val answer = chat(args.trim(), properties[CHATGPT_API_KEY], properties[CHATGPT_MAX_TOKENS]!!.toInt()) if (answer.isNotBlank()) { - event.sendMessage(answer) + event.sendMessage(WordUtils.wrap(answer, 400)) } else { event.respond("ChatGPT is stumped.") } @@ -65,6 +66,9 @@ class ChatGpt : AbstractModule() { e.message?.let { event.respond(it) } + } catch (e: NumberFormatException) { + if (logger.isErrorEnabled) logger.error("Invalid $CHATGPT_MAX_TOKENS property.", e) + event.respond("The $name module is misconfigured.") } } else { helpResponse(event) @@ -77,6 +81,11 @@ class ChatGpt : AbstractModule() { */ const val CHATGPT_API_KEY = "chatgpt-api-key" + /** + * The ChatGPT max tokens property. + */ + const val CHATGPT_MAX_TOKENS = "chatgpt-max-tokens" + // ChatGPT command private const val CHATGPT_CMD = "chatgpt" @@ -85,7 +94,7 @@ class ChatGpt : AbstractModule() { @JvmStatic @Throws(ModuleException::class) - fun chat(query: String, apiKey: String?): String { + fun chat(query: String, apiKey: String?, maxTokens: Int): String { if (!apiKey.isNullOrEmpty()) { val prompt = JSONWriter.valueToString("Q:$query\nA:") val request = HttpRequest.newBuilder() @@ -98,7 +107,7 @@ class ChatGpt : AbstractModule() { "model": "text-davinci-003", "prompt": $prompt, "temperature": 0, - "max_tokens": 1024, + "max_tokens": $maxTokens, "top_p": 1, "frequency_penalty": 0, "presence_penalty": 0 @@ -145,6 +154,6 @@ class ChatGpt : AbstractModule() { add(Utils.helpFormat("%c $CHATGPT_CMD explain quantum computing in simple terms")) add(Utils.helpFormat("%c $CHATGPT_CMD how do I make an HTTP request in Javascript?")) } - initProperties(CHATGPT_API_KEY) + initProperties(CHATGPT_API_KEY, CHATGPT_MAX_TOKENS) } } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt index f230831..b861c55 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt @@ -34,15 +34,17 @@ package net.thauvin.erik.mobibot.modules import assertk.assertThat import assertk.assertions.contains import assertk.assertions.hasNoCause +import assertk.assertions.isEqualTo import assertk.assertions.isFailure import assertk.assertions.isInstanceOf +import assertk.assertions.message import net.thauvin.erik.mobibot.LocalProperties import org.testng.annotations.Test class ChatGptTest : LocalProperties() { @Test(groups = ["modules"]) fun testApiKey() { - assertThat { ChatGpt.chat("1 gallon to liter", "") } + assertThat { ChatGpt.chat("1 gallon to liter", "", 0) } .isFailure() .isInstanceOf(ModuleException::class.java) .hasNoCause() @@ -52,7 +54,14 @@ class ChatGptTest : LocalProperties() { fun testChat() { val apiKey = getProperty(ChatGpt.CHATGPT_API_KEY) assertThat( - ChatGpt.chat("how do I make an HTTP request in Javascript?", apiKey) + ChatGpt.chat("how do I make an HTTP request in Javascript?", apiKey, 100) ).contains("XMLHttpRequest") + assertThat( + ChatGpt.chat("how do I encode a URL in java?", apiKey, 60) + ).contains("URLEncoder") + + assertThat { ChatGpt.chat("1 liter to gallon", apiKey, 0) } + .isFailure() + .isInstanceOf(ModuleException::class.java) } } From 66ca972b9b64ea309cd957f33a053369ab82cb61 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Thu, 12 Jan 2023 00:57:20 -0800 Subject: [PATCH 699/844] Minor cleanup --- .github/workflows/gradle.yml | 2 +- README.md | 8 +++++--- build.gradle | 8 ++++---- config/detekt/baseline.xml | 9 +++++---- properties/mobibot.properties | 11 ++++++----- src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt | 13 ++++++------- .../net/thauvin/erik/mobibot/commands/seen/Seen.kt | 8 ++++---- .../erik/mobibot/commands/tell/TellManager.kt | 8 ++++---- .../erik/mobibot/commands/tell/TellMessage.kt | 4 ++-- .../net/thauvin/erik/mobibot/entries/EntryLink.kt | 4 ++-- version.properties | 6 +++--- website/index.html | 5 ++--- 12 files changed, 44 insertions(+), 42 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 4a41aff..94687dc 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -68,7 +68,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - run: ./gradlew sonarqube + run: ./gradlew sonar - name: Cleanup Gradle Cache run: | diff --git a/README.md b/README.md index 2459b1b..4dee7b5 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,10 @@ # mobibot -[![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ethauvin_mobibot&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=ethauvin_mobibot) - -[![GitHub CI](https://github.com/ethauvin/mobibot/actions/workflows/gradle.yml/badge.svg)](https://github.com/ethauvin/mobibot/actions/workflows/gradle.yml) [![CircleCI](https://circleci.com/gh/ethauvin/mobibot/tree/master.svg?style=shield)](https://circleci.com/gh/ethauvin/mobibot/tree/master) +[![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) +[![Kotlin](https://img.shields.io/badge/kotlin-1.8.0-blue)](https://kotlinlang.org/) +[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ethauvin_mobibot&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=ethauvin_mobibot) +[![GitHub CI](https://github.com/ethauvin/mobibot/actions/workflows/gradle.yml/badge.svg)](https://github.com/ethauvin/mobibot/actions/workflows/gradle.yml) +[![CircleCI](https://circleci.com/gh/ethauvin/mobibot/tree/master.svg?style=shield)](https://circleci.com/gh/ethauvin/mobibot/tree/master) Some very basic instructions: diff --git a/build.gradle b/build.gradle index 178326f..3515d31 100644 --- a/build.gradle +++ b/build.gradle @@ -55,7 +55,7 @@ dependencies { implementation 'commons-net:commons-net:3.9.0' // Google - implementation 'com.google.code.gson:gson:2.10' + implementation 'com.google.code.gson:gson:2.10.1' implementation 'com.google.guava:guava:31.1-jre' // Kotlin @@ -82,7 +82,7 @@ dependencies { implementation 'net.thauvin.erik:cryptoprice:1.0.0' implementation 'net.thauvin.erik:jokeapi:0.9-SNAPSHOT' implementation 'net.thauvin.erik:pinboard-poster:1.0.3' - implementation 'net.thauvin.erik:urlencoder:1.0.1' + implementation 'net.thauvin.erik:urlencoder:1.3.0' testImplementation 'com.willowtreeapps.assertk:assertk-jvm:0.25' // testImplementation 'org.mockito.kotlin:mockito-kotlin:4.0.0' @@ -188,7 +188,7 @@ sonarqube { } } -tasks.sonarqube { +tasks.sonar { dependsOn 'koverReport' } @@ -219,6 +219,6 @@ task deploy { task release { group = 'Publishing' description = 'Releases new version.' - dependsOn(clean, wrapper, check, deploy) + dependsOn(clean, check, deploy) mustRunAfter clean } diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml index 19b4dbd..57c71a4 100644 --- a/config/detekt/baseline.xml +++ b/config/detekt/baseline.xml @@ -11,6 +11,7 @@ LongParameterList:Comment.kt$Comment$( channel: String, cmd: String, entry: EntryLink, entryIndex: Int, commentIndex: Int, event: GenericMessageEvent ) LongParameterList:EntryLink.kt$EntryLink$( // Link's comments val comments: MutableList<EntryComment> = mutableListOf(), // Tags/categories val tags: MutableList<SyndCategory> = mutableListOf(), // Channel var channel: String, // Creation date var date: Date = Calendar.getInstance().time, // Link's URL var link: String, // Author's login var login: String = "", // Author's nickname var nick: String, // Link's title var title: String ) LongParameterList:Twitter.kt$Twitter.Companion$( consumerKey: String?, consumerSecret: String?, token: String?, tokenSecret: String?, handle: String?, message: String, isDm: Boolean ) + MagicNumber:ChatGpt.kt$ChatGpt$400 MagicNumber:ChatGpt.kt$ChatGpt.Companion$200 MagicNumber:Comment.kt$Comment$3 MagicNumber:CryptoPrices.kt$CryptoPrices$10 @@ -48,7 +49,7 @@ MaxLineLength:TwitterOAuth.kt$TwitterOAuth$* NestedBlockDepth:Addons.kt$Addons$fun add(command: AbstractCommand): Boolean NestedBlockDepth:Addons.kt$Addons$fun add(module: AbstractModule): Boolean - NestedBlockDepth:ChatGpt.kt$ChatGpt.Companion$@JvmStatic @Throws(ModuleException::class) fun chat(query: String, apiKey: String?): String + NestedBlockDepth:ChatGpt.kt$ChatGpt.Companion$@JvmStatic @Throws(ModuleException::class) fun chat(query: String, apiKey: String?, maxTokens: Int): String NestedBlockDepth:Comment.kt$Comment$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) NestedBlockDepth:CurrencyConverter.kt$CurrencyConverter.Companion$@JvmStatic fun convertCurrency(query: String): Message NestedBlockDepth:EntryLink.kt$EntryLink$private fun setTags(tags: List<String?>) @@ -64,8 +65,8 @@ NestedBlockDepth:StockQuote.kt$StockQuote.Companion$@JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List<Message> NestedBlockDepth:Tell.kt$Tell$fun send(event: GenericUserEvent) NestedBlockDepth:TwitterOAuth.kt$TwitterOAuth$@JvmStatic fun main(args: Array<String>) - NestedBlockDepth:Utils.kt$Utils$@JvmStatic fun loadData(file: String, default: Any, logger: Logger, description: String): Any - NestedBlockDepth:Utils.kt$Utils$@JvmStatic fun saveData(file: String, data: Any, logger: Logger, description: String) + NestedBlockDepth:Utils.kt$Utils$@JvmStatic fun loadSerialData(file: String, default: Any, logger: Logger, description: String): Any + NestedBlockDepth:Utils.kt$Utils$@JvmStatic fun saveSerialData(file: String, data: Any, logger: Logger, description: String) NestedBlockDepth:Weather2.kt$Weather2$override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) NestedBlockDepth:Weather2.kt$Weather2.Companion$@JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message> PrintStackTrace:TwitterOAuth.kt$TwitterOAuth$ioe @@ -76,7 +77,7 @@ SwallowedException:GoogleSearchTest.kt$GoogleSearchTest$e: ModuleException SwallowedException:StockQuoteTest.kt$StockQuoteTest$e: ModuleException SwallowedException:WolframAlphaTest.kt$WolframAlphaTest$e: ModuleException - ThrowsCount:ChatGpt.kt$ChatGpt.Companion$@JvmStatic @Throws(ModuleException::class) fun chat(query: String, apiKey: String?): String + ThrowsCount:ChatGpt.kt$ChatGpt.Companion$@JvmStatic @Throws(ModuleException::class) fun chat(query: String, apiKey: String?, maxTokens: Int): String ThrowsCount:GoogleSearch.kt$GoogleSearch.Companion$@JvmStatic @Throws(ModuleException::class) fun searchGoogle( query: String, apiKey: String?, cseKey: String?, quotaUser: String = ReleaseInfo.PROJECT ): List<Message> ThrowsCount:Joke.kt$Joke.Companion$@JvmStatic @Throws(ModuleException::class) fun randomJoke(): List<Message> ThrowsCount:Mastodon.kt$Mastodon.Companion$@JvmStatic @Throws(ModuleException::class) fun toot(apiKey: String?, instance: String?, handle: String?, message: String, isDm: Boolean): String diff --git a/properties/mobibot.properties b/properties/mobibot.properties index 5551173..e82910c 100644 --- a/properties/mobibot.properties +++ b/properties/mobibot.properties @@ -28,12 +28,12 @@ tell-max-size=50 #disabled-modules=dice, joke # -# Credentials for: http://pinboard.in/ +# API Token for: https://pinboard.in/settings/password # #pinboard-api-token=user\:TOKEN # -# Configure app at: https://developer.twitter.com/en/apps +# Configure app at: https://developer.twitter.com/ # and then: java -cp mobibot.jar net.thauvin.erik.mobibot.TwitterOAuth # #twitter-consumerKey= @@ -61,14 +61,14 @@ tell-max-size=50 #mastodon-auto-post=true # -# Create custom search engine at: https://cse.google.com/ -# and get API key from: https://console.developers.google.com/ +# Create custom search engine at: https://programmablesearchengine.google.com/ +# and get API key from: https://console.cloud.google.com/apis # #google-api= #google-cse-cx= # -# Get OpenWeatherMap API key from: https://openweathermap.org/ +# Get OpenWeatherMap API key from: https://openweathermap.org/api # #owm-api-key= @@ -87,3 +87,4 @@ tell-max-size=50 # ChatGPT/OpenAI API key from: https://beta.openai.com/account/api-keys # #chatgpt-api-key= +#chatgpt-max-tokens=1024 diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt index bc9860d..359de74 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt @@ -47,7 +47,6 @@ import java.io.ObjectInputStream import java.io.ObjectOutputStream import java.net.HttpURLConnection import java.net.URL -import java.nio.charset.StandardCharsets import java.nio.file.Files import java.nio.file.Paths import java.time.LocalDateTime @@ -189,7 +188,7 @@ object Utils { } /** - * Returns {@code true} if the specified user is an operator on the [channel]. + * Returns `true` if the specified user is an operator on the [channel]. */ @JvmStatic fun GenericMessageEvent.isChannelOp(channel: String): Boolean { @@ -197,7 +196,7 @@ object Utils { } /** - * Returns {@code true} if a HTTP status code indicates a successful response. + * Returns `true` if a HTTP status code indicates a successful response. */ @JvmStatic fun Int.isHttpSuccess() = this in 200..399 @@ -214,10 +213,10 @@ object Utils { } /** - * Load data. + * Load serial data from file. */ @JvmStatic - fun loadData(file: String, default: Any, logger: Logger, description: String): Any { + fun loadSerialData(file: String, default: Any, logger: Logger, description: String): Any { val serialFile = Paths.get(file) if (serialFile.exists() && serialFile.fileSize() > 0) { try { @@ -237,7 +236,7 @@ object Utils { } /** - * Returns {@code true} if the list does not contain the given string. + * Returns `true` if the list does not contain the given string. */ @JvmStatic fun List.notContains(text: String, ignoreCase: Boolean = false) = this.none { it.equals(text, ignoreCase) } @@ -290,7 +289,7 @@ object Utils { * Save data */ @JvmStatic - fun saveData(file: String, data: Any, logger: Logger, description: String) { + fun saveSerialData(file: String, data: Any, logger: Logger, description: String) { try { BufferedOutputStream(Files.newOutputStream(Paths.get(file))).use { bos -> ObjectOutputStream(bos).use { output -> diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt index 66a3259..2b97f5a 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt @@ -35,8 +35,8 @@ package net.thauvin.erik.mobibot.commands.seen import com.google.common.collect.ImmutableSortedSet import net.thauvin.erik.mobibot.Utils.bot import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.loadData -import net.thauvin.erik.mobibot.Utils.saveData +import net.thauvin.erik.mobibot.Utils.loadSerialData +import net.thauvin.erik.mobibot.Utils.saveSerialData import net.thauvin.erik.mobibot.Utils.sendMessage import net.thauvin.erik.mobibot.commands.AbstractCommand import net.thauvin.erik.mobibot.commands.Info.Companion.toUptime @@ -107,7 +107,7 @@ class Seen(private val serialObject: String) : AbstractCommand() { if (isEnabled()) { @Suppress("UNCHECKED_CAST") seenNicks.putAll( - loadData( + loadSerialData( serialObject, TreeMap(), logger, @@ -118,7 +118,7 @@ class Seen(private val serialObject: String) : AbstractCommand() { } fun save() { - saveData(serialObject, seenNicks, logger, "seen nicknames") + saveSerialData(serialObject, seenNicks, logger, "seen nicknames") } init { diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellManager.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellManager.kt index 3c1f6b5..74ed301 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellManager.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellManager.kt @@ -31,8 +31,8 @@ */ package net.thauvin.erik.mobibot.commands.tell -import net.thauvin.erik.mobibot.Utils.loadData -import net.thauvin.erik.mobibot.Utils.saveData +import net.thauvin.erik.mobibot.Utils.loadSerialData +import net.thauvin.erik.mobibot.Utils.saveSerialData import org.slf4j.Logger import org.slf4j.LoggerFactory import java.time.Clock @@ -60,7 +60,7 @@ object TellManager { @JvmStatic fun load(file: String): List { @Suppress("UNCHECKED_CAST") - return loadData(file, emptyList(), logger, "message queue") as List + return loadSerialData(file, emptyList(), logger, "message queue") as List } /** @@ -69,7 +69,7 @@ object TellManager { @JvmStatic fun save(file: String, messages: List?) { if (messages != null) { - saveData(file, messages, logger, "messages") + saveSerialData(file, messages, logger, "messages") } } } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt index 7d8aaed..c9333c9 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt @@ -66,12 +66,12 @@ class TellMessage( var id: String = queued.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) /** - * Returns {@code true} if a notification was sent. + * Returns `true` if a notification was sent. */ var isNotified = false /** - * Returns {@code true} if the message was received. + * Returns `true` if the message was received. */ var isReceived = false set(value) { diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt index 59f4e73..ab0fee4 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt @@ -130,8 +130,8 @@ class EntryLink( /** * Formats the tags. */ - fun formatTags(sep: String, prefix: String = "") : String { - return tags.joinToString(separator = sep, prefix = prefix){it.name} + fun formatTags(sep: String, prefix: String = ""): String { + return tags.joinToString(separator = sep, prefix = prefix) { it.name } } /** diff --git a/version.properties b/version.properties index c234d1f..c049177 100644 --- a/version.properties +++ b/version.properties @@ -1,9 +1,9 @@ #Generated by the Semver Plugin for Gradle -#Thu Jan 05 16:20:43 PST 2023 -version.buildmeta=948 +#Thu Jan 12 00:57:56 PST 2023 +version.buildmeta=975 version.major=0 version.minor=8 version.patch=0 version.prerelease=rc version.project=mobibot -version.semver=0.8.0-rc+948 +version.semver=0.8.0-rc+975 diff --git a/website/index.html b/website/index.html index 2d134f2..ea78552 100644 --- a/website/index.html +++ b/website/index.html @@ -1,6 +1,5 @@ - - + + mobibot From 4fcdce522938dff23090504b733a7c5ebe2b4bbe Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Thu, 12 Jan 2023 10:27:01 -0800 Subject: [PATCH 700/844] Added to no-ci group to avoid rate limits --- src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt index b861c55..98f0052 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt @@ -50,7 +50,7 @@ class ChatGptTest : LocalProperties() { .hasNoCause() } - @Test(groups = ["modules"]) + @Test(groups = ["modules", "no-ci"]) fun testChat() { val apiKey = getProperty(ChatGpt.CHATGPT_API_KEY) assertThat( From c3d1930592a0b6289e0ecccdd6b19c777fb55601 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Thu, 12 Jan 2023 23:06:07 -0800 Subject: [PATCH 701/844] Added rate limit error --- .../thauvin/erik/mobibot/modules/ChatGpt.kt | 47 ++++++++++++------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt index e2bccb0..d62d364 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt @@ -50,16 +50,16 @@ import java.net.http.HttpResponse class ChatGpt : AbstractModule() { private val logger: Logger = LoggerFactory.getLogger(ChatGpt::class.java) - override val name = "ChatGPT" + override val name = CHATGPT_NAME override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { if (args.isNotBlank()) { try { - val answer = chat(args.trim(), properties[CHATGPT_API_KEY], properties[CHATGPT_MAX_TOKENS]!!.toInt()) + val answer = chat(args.trim(), properties[API_KEY_PROP], properties[MAX_TOKENS_PROP]!!.toInt()) if (answer.isNotBlank()) { event.sendMessage(WordUtils.wrap(answer, 400)) } else { - event.respond("ChatGPT is stumped.") + event.respond("$name is stumped.") } } catch (e: ModuleException) { if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) @@ -67,7 +67,7 @@ class ChatGpt : AbstractModule() { event.respond(it) } } catch (e: NumberFormatException) { - if (logger.isErrorEnabled) logger.error("Invalid $CHATGPT_MAX_TOKENS property.", e) + if (logger.isErrorEnabled) logger.error("Invalid $MAX_TOKENS_PROP property.", e) event.respond("The $name module is misconfigured.") } } else { @@ -77,20 +77,26 @@ class ChatGpt : AbstractModule() { companion object { /** - * The ChatGPT API Key property. + * The service name. */ - const val CHATGPT_API_KEY = "chatgpt-api-key" + const val CHATGPT_NAME = "ChatGPT" /** - * The ChatGPT max tokens property. + * The API Key property. */ - const val CHATGPT_MAX_TOKENS = "chatgpt-max-tokens" + const val API_KEY_PROP = "chatgpt-api-key" + + /** + * The max tokens property. + */ + const val MAX_TOKENS_PROP = "chatgpt-max-tokens" + + // ChatGPT API URL + private const val API_URL = "https://api.openai.com/v1/completions" // ChatGPT command private const val CHATGPT_CMD = "chatgpt" - // ChatGPT API URL - private const val API_URL = "https://api.openai.com/v1/completions" @JvmStatic @Throws(ModuleException::class) @@ -124,23 +130,28 @@ class ChatGpt : AbstractModule() { return choices.getJSONObject(0).getString("text").trim() } catch (e: JSONException) { throw ModuleException( - "chatgpt($query): JSON", - "A JSON error has occurred while conversing with ChatGPT.", + "$CHATGPT_CMD($query): JSON", + "A JSON error has occurred while conversing with $CHATGPT_NAME.", e ) } } else { - throw IOException("Status Code: " + response.statusCode()) + if (response.statusCode() == 429) { + throw ModuleException("$CHATGPT_CMD($query): Rate limit reached", + "Rate limit reached. Please try again later.") + } else { + throw IOException("HTTP Status Code: " + response.statusCode()) + } } } catch (e: IOException) { throw ModuleException( - "chatgpt($query): IO", - "An IO error has occurred while conversing with ChatGPT.", + "$CHATGPT_CMD($query): IO", + "An IO error has occurred while conversing with $CHATGPT_NAME.", e ) } } else { - throw ModuleException("chatgpt($query)", "No ChatGPT API key specified.") + throw ModuleException("$CHATGPT_CMD($query)", "No $CHATGPT_NAME API key specified.") } } } @@ -148,12 +159,12 @@ class ChatGpt : AbstractModule() { init { commands.add(CHATGPT_CMD) with(help) { - add("To get answers from ChatGPT:") + add("To get answers from $name:") add(Utils.helpFormat("%c $CHATGPT_CMD ")) add("For example:") add(Utils.helpFormat("%c $CHATGPT_CMD explain quantum computing in simple terms")) add(Utils.helpFormat("%c $CHATGPT_CMD how do I make an HTTP request in Javascript?")) } - initProperties(CHATGPT_API_KEY, CHATGPT_MAX_TOKENS) + initProperties(API_KEY_PROP, MAX_TOKENS_PROP) } } From a1ea25ae74ea2981f23b0fc6699464eb21c11b6f Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Thu, 12 Jan 2023 23:06:21 -0800 Subject: [PATCH 702/844] Minor cleanup --- config/detekt/baseline.xml | 1 + .../thauvin/erik/mobibot/modules/CryptoPrices.kt | 6 +++--- .../thauvin/erik/mobibot/modules/GoogleSearch.kt | 10 +++++----- .../thauvin/erik/mobibot/modules/StockQuote.kt | 16 ++++++++-------- .../net/thauvin/erik/mobibot/modules/Twitter.kt | 6 +++--- .../net/thauvin/erik/mobibot/modules/Weather2.kt | 6 +++--- .../thauvin/erik/mobibot/modules/WolframAlpha.kt | 11 ++++++----- .../thauvin/erik/mobibot/modules/ChatGptTest.kt | 4 +--- .../erik/mobibot/modules/GoogleSearchTest.kt | 4 ++-- .../erik/mobibot/modules/StockQuoteTest.kt | 2 +- .../thauvin/erik/mobibot/modules/Weather2Test.kt | 10 +++++----- .../erik/mobibot/modules/WolframAlphaTest.kt | 2 +- version.properties | 6 +++--- 13 files changed, 42 insertions(+), 42 deletions(-) diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml index 57c71a4..da082db 100644 --- a/config/detekt/baseline.xml +++ b/config/detekt/baseline.xml @@ -13,6 +13,7 @@ LongParameterList:Twitter.kt$Twitter.Companion$( consumerKey: String?, consumerSecret: String?, token: String?, tokenSecret: String?, handle: String?, message: String, isDm: Boolean ) MagicNumber:ChatGpt.kt$ChatGpt$400 MagicNumber:ChatGpt.kt$ChatGpt.Companion$200 + MagicNumber:ChatGpt.kt$ChatGpt.Companion$429 MagicNumber:Comment.kt$Comment$3 MagicNumber:CryptoPrices.kt$CryptoPrices$10 MagicNumber:CurrencyConverter.kt$CurrencyConverter$11 diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt index 66a33ae..05647bd 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt @@ -65,7 +65,7 @@ class CryptoPrices : AbstractModule() { } val debugMessage = "crypto($cmd $args)" - if (args == CURRENCY_CODES_KEYWORD) { + if (args == CODES_KEYWORD) { event.sendMessage("The supported currencies are:") event.sendList(ArrayList(CURRENCIES.keys), 10, isIndent = true) } else if (args.matches("\\w+( [a-zA-Z]{3}+)?".toRegex())) { @@ -100,7 +100,7 @@ class CryptoPrices : AbstractModule() { private val CURRENCIES: MutableMap = mutableMapOf() // Currency codes keyword - private const val CURRENCY_CODES_KEYWORD = "codes" + private const val CODES_KEYWORD = "codes" /** * Get current market price. @@ -153,7 +153,7 @@ class CryptoPrices : AbstractModule() { add(helpFormat("%c $CRYPTO_CMD ETH EUR")) add(helpFormat("%c $CRYPTO_CMD ETH2 GPB")) add("To list the supported currencies:") - add(helpFormat("%c $CRYPTO_CMD $CURRENCY_CODES_KEYWORD")) + add(helpFormat("%c $CRYPTO_CMD $CODES_KEYWORD")) } loadCurrencies() } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt index 76451db..02af2b6 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt @@ -67,8 +67,8 @@ class GoogleSearch : AbstractModule() { try { val results = searchGoogle( args, - properties[GOOGLE_API_KEY_PROP], - properties[GOOGLE_CSE_KEY_PROP], + properties[API_KEY_PROP], + properties[CSE_KEY_PROP], event.user.nick ) for (msg in results) { @@ -91,10 +91,10 @@ class GoogleSearch : AbstractModule() { companion object { // Google API Key property - const val GOOGLE_API_KEY_PROP = "google-api-key" + const val API_KEY_PROP = "google-api-key" // Google Custom Search Engine ID property - const val GOOGLE_CSE_KEY_PROP = "google-cse-cx" + const val CSE_KEY_PROP = "google-cse-cx" // Google command private const val GOOGLE_CMD = "google" @@ -158,6 +158,6 @@ class GoogleSearch : AbstractModule() { commands.add(GOOGLE_CMD) help.add("To search Google:") help.add(helpFormat("%c $GOOGLE_CMD ")) - initProperties(GOOGLE_API_KEY_PROP, GOOGLE_CSE_KEY_PROP) + initProperties(API_KEY_PROP, CSE_KEY_PROP) } } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt index ffca08b..6df2317 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt @@ -63,7 +63,7 @@ class StockQuote : AbstractModule() { override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { if (args.isNotBlank()) { try { - val messages = getQuote(args, properties[ALPHAVANTAGE_API_KEY_PROP]) + val messages = getQuote(args, properties[API_KEY_PROP]) for (msg in messages) { event.sendMessage(channel, msg) } @@ -80,17 +80,17 @@ class StockQuote : AbstractModule() { companion object { /** - * The Alpha Advantage property key. + * The API property key. */ - const val ALPHAVANTAGE_API_KEY_PROP = "alphavantage-api-key" + const val API_KEY_PROP = "alphavantage-api-key" /** * The Invalid Symbol error string. */ const val INVALID_SYMBOL = "Invalid symbol." - // Alpha Advantage URL - private const val ALPHAVANTAGE_URL = "https://www.alphavantage.co/query?function=" + // API URL + private const val API_URL = "https://www.alphavantage.co/query?function=" // Quote command private const val STOCK_CMD = "stock" @@ -145,7 +145,7 @@ class StockQuote : AbstractModule() { with(messages) { // Search for symbol/keywords response = URL( - "${ALPHAVANTAGE_URL}SYMBOL_SEARCH&keywords=" + symbol.encodeUrl() + "&apikey=" + "${API_URL}SYMBOL_SEARCH&keywords=" + symbol.encodeUrl() + "&apikey=" + apiKey.encodeUrl() ).reader().body var json = getJsonResponse(response, debugMessage) @@ -157,7 +157,7 @@ class StockQuote : AbstractModule() { // Get quote for symbol response = URL( - "${ALPHAVANTAGE_URL}GLOBAL_QUOTE&symbol=" + "${API_URL}GLOBAL_QUOTE&symbol=" + symbolInfo.getString("1. symbol").encodeUrl() + "&apikey=" + apiKey.encodeUrl() ).reader().body @@ -232,6 +232,6 @@ class StockQuote : AbstractModule() { commands.add(STOCK_CMD) help.add("To retrieve a stock quote:") help.add(helpFormat("%c $STOCK_CMD ")) - initProperties(ALPHAVANTAGE_API_KEY_PROP) + initProperties(API_KEY_PROP) } } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Twitter.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Twitter.kt index 4fc3770..ddb82b2 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Twitter.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Twitter.kt @@ -84,7 +84,7 @@ class Twitter : SocialModule() { const val TOKEN_PROP = "twitter-token" const val TOKEN_SECRET_PROP = "twitter-tokenSecret" - // Twitter command + // Twitter commands private const val TWITTER_CMD = "twitter" private const val TWEET_CMD = "tweet" @@ -118,7 +118,7 @@ class Twitter : SocialModule() { dm.text } } catch (e: TwitterException) { - throw ModuleException("twitterPost($message)", "An error has occurred: ${e.message}", e) + throw ModuleException("tweet($message)", "An error has occurred: ${e.message}", e) } } } @@ -126,7 +126,7 @@ class Twitter : SocialModule() { init { commands.add(TWITTER_CMD) commands.add(TWEET_CMD) - help.add("To tweet on Twitter:") + help.add("To $TWEET_CMD on $name:") help.add(helpFormat("%c $TWEET_CMD ")) properties[AUTO_POST_PROP] = "false" initProperties(CONSUMER_KEY_PROP, CONSUMER_SECRET_PROP, HANDLE_PROP, TOKEN_PROP, TOKEN_SECRET_PROP) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt index 5c5ae67..ec963fe 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt @@ -65,7 +65,7 @@ class Weather2 : AbstractModule() { override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { if (args.isNotBlank()) { try { - val messages = getWeather(args, properties[OWM_API_KEY_PROP]) + val messages = getWeather(args, properties[API_KEY_PROP]) if (messages[0].isError) { helpResponse(event) } else { @@ -88,7 +88,7 @@ class Weather2 : AbstractModule() { /** * The OpenWeatherMap API Key property. */ - const val OWM_API_KEY_PROP = "owm-api-key" + const val API_KEY_PROP = "owm-api-key" // Weather command private const val WEATHER_CMD = "weather" @@ -246,6 +246,6 @@ class Weather2 : AbstractModule() { add(helpFormat("%c $WEATHER_CMD paris, fr")) add("The default ISO 3166 country code is ${"US".bold()}. Zip codes supported in most countries.") } - initProperties(OWM_API_KEY_PROP) + initProperties(API_KEY_PROP) } } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt index 56d3a3d..204ad17 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt @@ -66,9 +66,9 @@ class WolframAlpha : AbstractModule() { units = if (query.size == 2) { getUnits(query[1].trim()) } else { - getUnits(properties[WOLFRAM_UNITS_PROP]) + getUnits(properties[UNITS_PROP]) }, - appId = properties[WOLFRAM_APPID_KEY] + appId = properties[APPID_KEY_PROP] ) ) } catch (e: ModuleException) { @@ -86,12 +86,13 @@ class WolframAlpha : AbstractModule() { /** * The Wolfram Alpha API Key property. */ - const val WOLFRAM_APPID_KEY = "wolfram-appid" + const val APPID_KEY_PROP = "wolfram-appid" /** * The Wolfram units properties */ - const val WOLFRAM_UNITS_PROP = "wolfram-units" + const val UNITS_PROP = "wolfram-units" + const val METRIC = "metric" const val IMPERIAL = "imperial" @@ -137,6 +138,6 @@ class WolframAlpha : AbstractModule() { add(Utils.helpFormat("%c $WOLFRAM_CMD days until christmas")) add(Utils.helpFormat("%c $WOLFRAM_CMD distance earth moon units=metric")) } - initProperties(WOLFRAM_APPID_KEY, WOLFRAM_UNITS_PROP) + initProperties(APPID_KEY_PROP, UNITS_PROP) } } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt index 98f0052..6c30297 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt @@ -34,10 +34,8 @@ package net.thauvin.erik.mobibot.modules import assertk.assertThat import assertk.assertions.contains import assertk.assertions.hasNoCause -import assertk.assertions.isEqualTo import assertk.assertions.isFailure import assertk.assertions.isInstanceOf -import assertk.assertions.message import net.thauvin.erik.mobibot.LocalProperties import org.testng.annotations.Test @@ -52,7 +50,7 @@ class ChatGptTest : LocalProperties() { @Test(groups = ["modules", "no-ci"]) fun testChat() { - val apiKey = getProperty(ChatGpt.CHATGPT_API_KEY) + val apiKey = getProperty(ChatGpt.API_KEY_PROP) assertThat( ChatGpt.chat("how do I make an HTTP request in Javascript?", apiKey, 100) ).contains("XMLHttpRequest") diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt index 8d12ab4..9d052cf 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt @@ -75,8 +75,8 @@ class GoogleSearchTest : LocalProperties() { @Test(groups = ["no-ci", "modules"]) @Throws(ModuleException::class) fun testSearchGoogle() { - val apiKey = getProperty(GoogleSearch.GOOGLE_API_KEY_PROP) - val cseKey = getProperty(GoogleSearch.GOOGLE_CSE_KEY_PROP) + val apiKey = getProperty(GoogleSearch.API_KEY_PROP) + val cseKey = getProperty(GoogleSearch.CSE_KEY_PROP) try { var query = "mobibot" diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt index 162550f..2721469 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt @@ -59,7 +59,7 @@ class StockQuoteTest : LocalProperties() { @Test(groups = ["modules"]) @Throws(ModuleException::class) fun testGetQuote() { - val apiKey = getProperty(StockQuote.ALPHAVANTAGE_API_KEY_PROP) + val apiKey = getProperty(StockQuote.API_KEY_PROP) try { var symbol = "apple inc" val messages = getQuote(symbol, apiKey) diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt index 6c67536..f1949d6 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt @@ -46,7 +46,7 @@ import assertk.assertions.prop import net.aksingh.owmjapis.api.APIException import net.aksingh.owmjapis.core.OWM import net.thauvin.erik.mobibot.LocalProperties -import net.thauvin.erik.mobibot.modules.Weather2.Companion.OWM_API_KEY_PROP +import net.thauvin.erik.mobibot.modules.Weather2.Companion.API_KEY_PROP import net.thauvin.erik.mobibot.modules.Weather2.Companion.ftoC import net.thauvin.erik.mobibot.modules.Weather2.Companion.getCountry import net.thauvin.erik.mobibot.modules.Weather2.Companion.getWeather @@ -86,7 +86,7 @@ class Weather2Test : LocalProperties() { @Throws(ModuleException::class) fun testWeather() { var query = "98204" - var messages = getWeather(query, getProperty(OWM_API_KEY_PROP)) + var messages = getWeather(query, getProperty(API_KEY_PROP)) assertThat(messages, "getWeather($query)").index(0).prop(Message::msg).all { contains("Everett, United States") contains("US") @@ -94,7 +94,7 @@ class Weather2Test : LocalProperties() { assertThat(messages, "getWeather($query)").index(messages.size - 1).prop(Message::msg).endsWith("98204%2CUS") query = "San Francisco" - messages = getWeather(query, getProperty(OWM_API_KEY_PROP)) + messages = getWeather(query, getProperty(API_KEY_PROP)) assertThat(messages, "getWeather($query)").index(0).prop(Message::msg).all { contains("San Francisco") contains("US") @@ -102,7 +102,7 @@ class Weather2Test : LocalProperties() { assertThat(messages, "getWeather($query)").index(messages.size - 1).prop(Message::msg).endsWith("5391959") query = "London, GB" - messages = getWeather(query, getProperty(OWM_API_KEY_PROP)) + messages = getWeather(query, getProperty(API_KEY_PROP)) assertThat(messages, "getWeather($query)").index(0).prop(Message::msg).all { contains("London, United Kingdom") contains("GB") @@ -111,7 +111,7 @@ class Weather2Test : LocalProperties() { try { query = "Foo, US" - getWeather(query, getProperty(OWM_API_KEY_PROP)) + getWeather(query, getProperty(API_KEY_PROP)) } catch (e: ModuleException) { assertThat(e.cause, "getWeather($query)").isNotNull().isInstanceOf(APIException::class.java) } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt index f0fb424..0d9ed9a 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt @@ -58,7 +58,7 @@ class WolframAlphaTest : LocalProperties() { @Test(groups = ["modules", "no-ci"]) @Throws(ModuleException::class) fun queryWolframTest() { - val apiKey = getProperty(WolframAlpha.WOLFRAM_APPID_KEY) + val apiKey = getProperty(WolframAlpha.APPID_KEY_PROP) try { var query = "SFO to SEA" assertThat(queryWolfram(query, appId = apiKey), "queryWolfram($query)").contains("miles") diff --git a/version.properties b/version.properties index c049177..8d6a471 100644 --- a/version.properties +++ b/version.properties @@ -1,9 +1,9 @@ #Generated by the Semver Plugin for Gradle -#Thu Jan 12 00:57:56 PST 2023 -version.buildmeta=975 +#Thu Jan 12 23:03:48 PST 2023 +version.buildmeta=982 version.major=0 version.minor=8 version.patch=0 version.prerelease=rc version.project=mobibot -version.semver=0.8.0-rc+975 +version.semver=0.8.0-rc+982 From 6ec39c6d6df7367760f64de1c3f79286268ef3e6 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sat, 28 Jan 2023 23:19:12 -0800 Subject: [PATCH 703/844] Updated copyright --- .idea/copyright/Erik_s_Copyright_Notice.xml | 2 +- LICENSE.txt | 3 +- build.gradle | 2 +- .../net/thauvin/erik/mobibot/modules/War.java | 3 +- .../kotlin/net/thauvin/erik/mobibot/Addons.kt | 3 +- .../net/thauvin/erik/mobibot/Constants.kt | 3 +- .../net/thauvin/erik/mobibot/FeedReader.kt | 3 +- .../net/thauvin/erik/mobibot/Mobibot.kt | 3 +- .../net/thauvin/erik/mobibot/Pinboard.kt | 3 +- .../net/thauvin/erik/mobibot/TwitterOAuth.kt | 3 +- .../kotlin/net/thauvin/erik/mobibot/Utils.kt | 3 +- .../erik/mobibot/commands/AbstractCommand.kt | 3 +- .../erik/mobibot/commands/ChannelFeed.kt | 3 +- .../thauvin/erik/mobibot/commands/Cycle.kt | 3 +- .../net/thauvin/erik/mobibot/commands/Die.kt | 3 +- .../thauvin/erik/mobibot/commands/Ignore.kt | 3 +- .../net/thauvin/erik/mobibot/commands/Info.kt | 3 +- .../net/thauvin/erik/mobibot/commands/Me.kt | 3 +- .../thauvin/erik/mobibot/commands/Modules.kt | 3 +- .../net/thauvin/erik/mobibot/commands/Msg.kt | 3 +- .../net/thauvin/erik/mobibot/commands/Nick.kt | 3 +- .../thauvin/erik/mobibot/commands/Recap.kt | 3 +- .../net/thauvin/erik/mobibot/commands/Say.kt | 3 +- .../thauvin/erik/mobibot/commands/Users.kt | 3 +- .../thauvin/erik/mobibot/commands/Versions.kt | 3 +- .../erik/mobibot/commands/links/Comment.kt | 3 +- .../mobibot/commands/links/LinksManager.kt | 3 +- .../erik/mobibot/commands/links/Posting.kt | 3 +- .../erik/mobibot/commands/links/Tags.kt | 3 +- .../erik/mobibot/commands/links/View.kt | 3 +- .../mobibot/commands/seen/NickComparator.kt | 5 ++- .../erik/mobibot/commands/seen/Seen.kt | 3 +- .../erik/mobibot/commands/seen/SeenNick.kt | 3 +- .../erik/mobibot/commands/tell/Tell.kt | 3 +- .../erik/mobibot/commands/tell/TellManager.kt | 3 +- .../erik/mobibot/commands/tell/TellMessage.kt | 3 +- .../thauvin/erik/mobibot/entries/Entries.kt | 3 +- .../erik/mobibot/entries/EntriesUtils.kt | 3 +- .../erik/mobibot/entries/EntryComment.kt | 3 +- .../thauvin/erik/mobibot/entries/EntryLink.kt | 3 +- .../erik/mobibot/entries/FeedsManager.kt | 3 +- .../erik/mobibot/modules/AbstractModule.kt | 3 +- .../net/thauvin/erik/mobibot/modules/Calc.kt | 3 +- .../thauvin/erik/mobibot/modules/ChatGpt.kt | 3 +- .../erik/mobibot/modules/CryptoPrices.kt | 3 +- .../erik/mobibot/modules/CurrencyConverter.kt | 3 +- .../net/thauvin/erik/mobibot/modules/Dice.kt | 3 +- .../erik/mobibot/modules/GoogleSearch.kt | 3 +- .../net/thauvin/erik/mobibot/modules/Joke.kt | 3 +- .../thauvin/erik/mobibot/modules/Lookup.kt | 3 +- .../thauvin/erik/mobibot/modules/Mastodon.kt | 3 +- .../erik/mobibot/modules/ModuleException.kt | 3 +- .../net/thauvin/erik/mobibot/modules/Ping.kt | 3 +- .../erik/mobibot/modules/RockPaperScissors.kt | 3 +- .../erik/mobibot/modules/StockQuote.kt | 3 +- .../thauvin/erik/mobibot/modules/Twitter.kt | 3 +- .../thauvin/erik/mobibot/modules/Weather2.kt | 3 +- .../erik/mobibot/modules/WolframAlpha.kt | 3 +- .../thauvin/erik/mobibot/modules/WorldTime.kt | 3 +- .../thauvin/erik/mobibot/msg/ErrorMessage.kt | 3 +- .../net/thauvin/erik/mobibot/msg/Message.kt | 3 +- .../thauvin/erik/mobibot/msg/NoticeMessage.kt | 3 +- .../erik/mobibot/msg/PrivateMessage.kt | 3 +- .../thauvin/erik/mobibot/msg/PublicMessage.kt | 3 +- .../erik/mobibot/social/SocialManager.kt | 3 +- .../erik/mobibot/social/SocialModule.kt | 3 +- .../erik/mobibot/social/SocialTimer.kt | 3 +- .../net/thauvin/erik/mobibot/AddonsTest.kt | 3 +- .../erik/mobibot/ExceptionSanitizer.kt | 3 +- .../thauvin/erik/mobibot/FeedReaderTest.kt | 3 +- .../thauvin/erik/mobibot/LocalProperties.kt | 3 +- .../net/thauvin/erik/mobibot/PinboardTest.kt | 3 +- .../net/thauvin/erik/mobibot/UtilsTest.kt | 3 +- .../thauvin/erik/mobibot/commands/InfoTest.kt | 3 +- .../erik/mobibot/commands/RecapTest.kt | 3 +- .../commands/links/LinksManagerTest.kt | 5 ++- .../erik/mobibot/commands/links/ViewTest.kt | 3 +- .../erik/mobibot/commands/seen/SeenTest.kt | 3 +- .../mobibot/commands/tell/TellMessageTest.kt | 3 +- .../commands/tell/TellMessagesMgrTest.kt | 3 +- .../erik/mobibot/entries/EntriesUtilsTest.kt | 3 +- .../erik/mobibot/entries/EntryLinkTest.kt | 3 +- .../erik/mobibot/entries/FeedMgrTest.kt | 3 +- .../thauvin/erik/mobibot/modules/CalcTest.kt | 3 +- .../erik/mobibot/modules/ChatGptTest.kt | 3 +- .../erik/mobibot/modules/CryptoPricesTest.kt | 3 +- .../mobibot/modules/CurrencyConverterTest.kt | 3 +- .../thauvin/erik/mobibot/modules/DiceTest.kt | 3 +- .../erik/mobibot/modules/GoogleSearchTest.kt | 3 +- .../thauvin/erik/mobibot/modules/JokeTest.kt | 3 +- .../erik/mobibot/modules/LookupTest.kt | 3 +- .../erik/mobibot/modules/MastodonTest.kt | 3 +- .../mobibot/modules/ModuleExceptionTest.kt | 3 +- .../thauvin/erik/mobibot/modules/PingTest.kt | 3 +- .../mobibot/modules/RockPaperScissorsTest.kt | 3 +- .../erik/mobibot/modules/StockQuoteTest.kt | 3 +- .../erik/mobibot/modules/TwitterTest.kt | 3 +- .../erik/mobibot/modules/Weather2Test.kt | 3 +- .../erik/mobibot/modules/WolframAlphaTest.kt | 3 +- .../erik/mobibot/modules/WordTimeTest.kt | 3 +- .../thauvin/erik/mobibot/msg/MessageTest.kt | 5 ++- src/test/resources/current.xml | 31 +++++++++++++++++++ version.properties | 6 ++-- 103 files changed, 138 insertions(+), 206 deletions(-) diff --git a/.idea/copyright/Erik_s_Copyright_Notice.xml b/.idea/copyright/Erik_s_Copyright_Notice.xml index b9f5293..055999a 100644 --- a/.idea/copyright/Erik_s_Copyright_Notice.xml +++ b/.idea/copyright/Erik_s_Copyright_Notice.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt index 085f7c7..f5fe66b 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,5 +1,4 @@ -Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) -All rights reserved. +Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/build.gradle b/build.gradle index 3515d31..70e3d46 100644 --- a/build.gradle +++ b/build.gradle @@ -30,7 +30,7 @@ mainClassName = packageName + '.Mobibot' ext.versions = [ log4j: '2.19.0', - pmd : '6.52.0', + pmd : '6.54.0', ] repositories { diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/War.java b/src/main/java/net/thauvin/erik/mobibot/modules/War.java index 9193072..d1d7882 100644 --- a/src/main/java/net/thauvin/erik/mobibot/modules/War.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/War.java @@ -1,8 +1,7 @@ /* * War.java * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt index 8720e95..020edf4 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt @@ -1,8 +1,7 @@ /* * Addons.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt index 543511f..6766f62 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt @@ -1,8 +1,7 @@ /* * Constants.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt b/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt index fc43dbc..f56af2e 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt @@ -1,8 +1,7 @@ /* * FeedReader.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt index fcd2d08..f811764 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt @@ -1,8 +1,7 @@ /* * Mobibot.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt index 1bc719b..b829bab 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt @@ -1,8 +1,7 @@ /* * Pinboard.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/TwitterOAuth.kt b/src/main/kotlin/net/thauvin/erik/mobibot/TwitterOAuth.kt index 2b5ecfb..ab078db 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/TwitterOAuth.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/TwitterOAuth.kt @@ -1,8 +1,7 @@ /* * TwitterOAuth.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt index 359de74..165647a 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt @@ -1,8 +1,7 @@ /* * Utils.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/AbstractCommand.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/AbstractCommand.kt index c404b89..5f79472 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/AbstractCommand.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/AbstractCommand.kt @@ -1,8 +1,7 @@ /* * AbstractCommand.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/ChannelFeed.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/ChannelFeed.kt index 8412af0..038e378 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/ChannelFeed.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/ChannelFeed.kt @@ -1,8 +1,7 @@ /* * ChannelFeed.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Cycle.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Cycle.kt index 31a9c65..9608ca8 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Cycle.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Cycle.kt @@ -1,8 +1,7 @@ /* * Cycle.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Die.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Die.kt index 97ca12e..f271bfa 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Die.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Die.kt @@ -1,8 +1,7 @@ /* * Die.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt index f47f057..a696fa8 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt @@ -1,8 +1,7 @@ /* * Ignore.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Info.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Info.kt index 9f7e855..ed0b6ef 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Info.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Info.kt @@ -1,8 +1,7 @@ /* * Info.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Me.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Me.kt index bbd5479..ec7823b 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Me.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Me.kt @@ -1,8 +1,7 @@ /* * Me.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Modules.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Modules.kt index 456fa7f..f64178d 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Modules.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Modules.kt @@ -1,8 +1,7 @@ /* * Modules.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Msg.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Msg.kt index a758996..20a6635 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Msg.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Msg.kt @@ -1,8 +1,7 @@ /* * Msg.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Nick.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Nick.kt index e4cdf34..85a03ab 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Nick.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Nick.kt @@ -1,8 +1,7 @@ /* * Nick.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Recap.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Recap.kt index 3647bcc..77154c7 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Recap.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Recap.kt @@ -1,8 +1,7 @@ /* * Recap.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Say.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Say.kt index 0141206..7f76d35 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Say.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Say.kt @@ -1,8 +1,7 @@ /* * Say.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Users.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Users.kt index 66c4ebf..33d6fef 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Users.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Users.kt @@ -1,8 +1,7 @@ /* * Users.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Versions.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Versions.kt index 9513aef..896c569 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Versions.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Versions.kt @@ -1,8 +1,7 @@ /* * Versions.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Comment.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Comment.kt index 5a09836..1443d44 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Comment.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Comment.kt @@ -1,8 +1,7 @@ /* * Comment.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManager.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManager.kt index af6adf4..fba6b99 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManager.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManager.kt @@ -1,8 +1,7 @@ /* * LinksManager.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Posting.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Posting.kt index 9368d37..ff4278d 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Posting.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Posting.kt @@ -1,8 +1,7 @@ /* * Posting.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Tags.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Tags.kt index 785e3a0..1662857 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Tags.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Tags.kt @@ -1,8 +1,7 @@ /* * Tags.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/View.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/View.kt index 008ccad..825e374 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/View.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/View.kt @@ -1,8 +1,7 @@ /* * View.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt index 8d068c2..d29b30d 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt @@ -1,8 +1,7 @@ /* - * SeenComparator.kt + * NickComparator.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt index 2b97f5a..4a45598 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt @@ -1,8 +1,7 @@ /* * Seen.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt index b53414d..b09cbf4 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt @@ -1,8 +1,7 @@ /* * SeenNick.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt index f591283..e073184 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt @@ -1,8 +1,7 @@ /* * Tell.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellManager.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellManager.kt index 74ed301..b65a4da 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellManager.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellManager.kt @@ -1,8 +1,7 @@ /* * TellManager.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt index c9333c9..6d2f313 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt @@ -1,8 +1,7 @@ /* * TellMessage.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/Entries.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/Entries.kt index a81a737..e8676ec 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/Entries.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/Entries.kt @@ -1,8 +1,7 @@ /* * Entries.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt index ac2c259..9c09626 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt @@ -1,8 +1,7 @@ /* * EntriesUtils.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryComment.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryComment.kt index b0b138a..bc64191 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryComment.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryComment.kt @@ -1,8 +1,7 @@ /* * EntryComment.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt index ab0fee4..7bf003d 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt @@ -1,8 +1,7 @@ /* * EntryLink.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt index 1ae2690..bb3838a 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt @@ -1,8 +1,7 @@ /* * FeedsManager.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/AbstractModule.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/AbstractModule.kt index 61e2eaf..8c8e736 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/AbstractModule.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/AbstractModule.kt @@ -1,8 +1,7 @@ /* * AbstractModule.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Calc.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Calc.kt index 76f3786..b7aae28 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Calc.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Calc.kt @@ -1,8 +1,7 @@ /* * Calc.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt index d62d364..8847bef 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt @@ -1,8 +1,7 @@ /* * ChatGpt.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt index 05647bd..d14056e 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt @@ -1,8 +1,7 @@ /* * CryptoPrices.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt index 3d0bf0a..d41e7a1 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt @@ -1,8 +1,7 @@ /* * CurrencyConverter.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Dice.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Dice.kt index c32f781..8420fb1 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Dice.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Dice.kt @@ -1,8 +1,7 @@ /* * Dice.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt index 02af2b6..f426d1e 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt @@ -1,8 +1,7 @@ /* * GoogleSearch.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Joke.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Joke.kt index 202dc68..a0e8fd4 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Joke.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Joke.kt @@ -1,8 +1,7 @@ /* * Joke.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Lookup.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Lookup.kt index 90a0316..9ab2ead 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Lookup.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Lookup.kt @@ -1,8 +1,7 @@ /* * Lookup.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Mastodon.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Mastodon.kt index 9a4e914..3be3a5f 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Mastodon.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Mastodon.kt @@ -1,8 +1,7 @@ /* * Mastodon.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ModuleException.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ModuleException.kt index 2f39854..a569d21 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ModuleException.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ModuleException.kt @@ -1,8 +1,7 @@ /* * ModuleException.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Ping.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Ping.kt index 0818120..944dbc1 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Ping.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Ping.kt @@ -1,8 +1,7 @@ /* * Ping.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt index bc02a4d..d698888 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt @@ -1,8 +1,7 @@ /* * RockPaperScissors.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt index 6df2317..dcae5e7 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt @@ -1,8 +1,7 @@ /* * StockQuote.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Twitter.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Twitter.kt index ddb82b2..d4c02e1 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Twitter.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Twitter.kt @@ -1,8 +1,7 @@ /* * Twitter.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt index ec963fe..567728e 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt @@ -1,8 +1,7 @@ /* * Weather2.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt index 204ad17..a72efab 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt @@ -1,8 +1,7 @@ /* * WolframAlpha.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WorldTime.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WorldTime.kt index fc0edf6..18072bc 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WorldTime.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WorldTime.kt @@ -1,8 +1,7 @@ /* * WorldTime.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/ErrorMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/ErrorMessage.kt index ae5651c..0607936 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/ErrorMessage.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/msg/ErrorMessage.kt @@ -1,8 +1,7 @@ /* * ErrorMessage.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/Message.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/Message.kt index 20f8725..23a33b9 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/Message.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/msg/Message.kt @@ -1,8 +1,7 @@ /* * Message.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/NoticeMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/NoticeMessage.kt index f88b8dd..037d504 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/NoticeMessage.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/msg/NoticeMessage.kt @@ -1,8 +1,7 @@ /* * NoticeMessage.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/PrivateMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/PrivateMessage.kt index 827b682..842fee5 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/PrivateMessage.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/msg/PrivateMessage.kt @@ -1,8 +1,7 @@ /* * PrivateMessage.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/PublicMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/PublicMessage.kt index 71b2a5b..9c5e088 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/PublicMessage.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/msg/PublicMessage.kt @@ -1,8 +1,7 @@ /* * PublicMessage.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialManager.kt b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialManager.kt index f3a86fe..cbc1936 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialManager.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialManager.kt @@ -1,8 +1,7 @@ /* * SocialManager.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialModule.kt b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialModule.kt index e31ccdc..b594670 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialModule.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialModule.kt @@ -1,8 +1,7 @@ /* * SocialModule.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialTimer.kt b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialTimer.kt index 3edb06b..267a59d 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialTimer.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialTimer.kt @@ -1,8 +1,7 @@ /* * SocialTimer.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt index 826e784..8662392 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt @@ -1,8 +1,7 @@ /* * AddonsTest.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/ExceptionSanitizer.kt b/src/test/kotlin/net/thauvin/erik/mobibot/ExceptionSanitizer.kt index b1c6dba..a3994ec 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/ExceptionSanitizer.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/ExceptionSanitizer.kt @@ -1,8 +1,7 @@ /* * ExceptionSanitizer.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt index 2fa58b6..0d66a0d 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt @@ -1,8 +1,7 @@ /* * FeedReaderTest.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/LocalProperties.kt b/src/test/kotlin/net/thauvin/erik/mobibot/LocalProperties.kt index 7dba11a..e4af75a 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/LocalProperties.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/LocalProperties.kt @@ -1,8 +1,7 @@ /* * LocalProperties.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/PinboardTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/PinboardTest.kt index 3ee0f26..87617e8 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/PinboardTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/PinboardTest.kt @@ -1,8 +1,7 @@ /* * PinboardTest.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt index d6fe27d..22e37cb 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt @@ -1,8 +1,7 @@ /* * UtilsTest.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/InfoTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/InfoTest.kt index ba5af62..265009b 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/InfoTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/InfoTest.kt @@ -1,8 +1,7 @@ /* * InfoTest.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/RecapTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/RecapTest.kt index 6894b3d..f1fbe11 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/RecapTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/RecapTest.kt @@ -1,8 +1,7 @@ /* * RecapTest.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt index fa4a099..8e49b5e 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt @@ -1,8 +1,7 @@ /* - * LinksMgrTest.kt + * LinksManagerTest.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/ViewTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/ViewTest.kt index e7c07f0..c28090d 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/ViewTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/ViewTest.kt @@ -1,8 +1,7 @@ /* * ViewTest.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt index 46090e5..4298a16 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt @@ -1,8 +1,7 @@ /* * SeenTest.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt index 2e4ef6e..f7239e0 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt @@ -1,8 +1,7 @@ /* * TellMessageTest.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt index a07eb68..cff11f2 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt @@ -1,8 +1,7 @@ /* * TellMessagesMgrTest.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt index 23ba01e..6eef16e 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt @@ -1,8 +1,7 @@ /* * EntriesUtilsTest.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt index 8c1a862..ab8c71c 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt @@ -1,8 +1,7 @@ /* * EntryLinkTest.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt index 68be3f7..cd2ebb8 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt @@ -1,8 +1,7 @@ /* * FeedMgrTest.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt index 0873e7b..fb0402e 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt @@ -1,8 +1,7 @@ /* * CalcTest.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt index 6c30297..5e0e1d2 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt @@ -1,8 +1,7 @@ /* * ChatGptTest.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt index 3bef92b..e3475f1 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt @@ -1,8 +1,7 @@ /* * CryptoPricesTest.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt index 66ae5c7..8c1d745 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt @@ -1,8 +1,7 @@ /* * CurrencyConverterTest.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/DiceTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/DiceTest.kt index e391f2a..cdc04f0 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/DiceTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/DiceTest.kt @@ -1,8 +1,7 @@ /* * DiceTest.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt index 9d052cf..c2bb833 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt @@ -1,8 +1,7 @@ /* * GoogleSearchTest.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/JokeTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/JokeTest.kt index 618cd36..fa063f4 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/JokeTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/JokeTest.kt @@ -1,8 +1,7 @@ /* * JokeTest.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt index 5ab97d7..9c21f7c 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt @@ -1,8 +1,7 @@ /* * LookupTest.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt index 74b5a9a..d464f03 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt @@ -1,8 +1,7 @@ /* * MastodonTest.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt index eef610a..c7dbfc0 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt @@ -1,8 +1,7 @@ /* * ModuleExceptionTest.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/PingTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/PingTest.kt index 50f7fda..e1e79f3 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/PingTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/PingTest.kt @@ -1,8 +1,7 @@ /* * PingTest.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt index 4bd8025..8dc90ba 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt @@ -1,8 +1,7 @@ /* * RockPaperScissorsTest.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt index 2721469..d35a3d3 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt @@ -1,8 +1,7 @@ /* * StockQuoteTest.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/TwitterTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/TwitterTest.kt index 126fb4c..9651ba0 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/TwitterTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/TwitterTest.kt @@ -1,8 +1,7 @@ /* * TwitterTest.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt index f1949d6..4c7f7e6 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt @@ -1,8 +1,7 @@ /* * Weather2Test.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt index 0d9ed9a..4aaf620 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt @@ -1,8 +1,7 @@ /* * WolframAlphaTest.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt index 049d315..f17ed1d 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt @@ -1,8 +1,7 @@ /* * WordTimeTest.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/msg/MessageTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/msg/MessageTest.kt index 7219a1b..e856112 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/msg/MessageTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/msg/MessageTest.kt @@ -1,8 +1,7 @@ /* - * TestMessage.kt + * MessageTest.kt * - * Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/resources/current.xml b/src/test/resources/current.xml index 8552a9a..535a400 100644 --- a/src/test/resources/current.xml +++ b/src/test/resources/current.xml @@ -1,4 +1,35 @@ + + #mobibot IRC Links diff --git a/version.properties b/version.properties index 8d6a471..fb36533 100644 --- a/version.properties +++ b/version.properties @@ -1,9 +1,9 @@ #Generated by the Semver Plugin for Gradle -#Thu Jan 12 23:03:48 PST 2023 -version.buildmeta=982 +#Sat Jan 28 23:17:39 PST 2023 +version.buildmeta=983 version.major=0 version.minor=8 version.patch=0 version.prerelease=rc version.project=mobibot -version.semver=0.8.0-rc+982 +version.semver=0.8.0-rc+983 From 6f3b84a7c0c4634b2b2a5f2abfb54268e0ff6c62 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Tue, 31 Jan 2023 22:03:33 -0800 Subject: [PATCH 704/844] Fixed potential resource leak --- src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt index 165647a..f61c56c 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt @@ -420,12 +420,12 @@ object Utils { val connection = this.openConnection() as HttpURLConnection connection.setRequestProperty( "User-Agent", - "Mozilla/5.0 (Linux x86_64; rv:104.0) Gecko/20100101 Firefox/104.0" + "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/109.0" ) return if (connection.responseCode.isHttpSuccess()) { - UrlReaderResponse(connection.responseCode, connection.inputStream.bufferedReader().readText()) + UrlReaderResponse(connection.responseCode, connection.inputStream.bufferedReader().use { it.readText() }) } else { - UrlReaderResponse(connection.responseCode, connection.errorStream.bufferedReader().readText()) + UrlReaderResponse(connection.responseCode, connection.errorStream.bufferedReader().use { it.readText() }) } } From a43d4e0b5dbd75c1e998810dbe6f46e8d27c112d Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Tue, 31 Jan 2023 23:24:34 -0800 Subject: [PATCH 705/844] Updated workflow --- .github/workflows/gradle.yml | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 94687dc..fa46754 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -15,12 +15,12 @@ jobs: java-version: [ 11, 18 ] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: fetch-depth: 0 - name: Set up JDK ${{ matrix.java-version }} - uses: actions/setup-java@v1 + uses: actions/setup-java@v3 with: java-version: ${{ matrix.java-version }} @@ -29,23 +29,14 @@ jobs: - name: Cache SonarCloud packages if: matrix.java-version == env.SONAR_JDK - uses: actions/cache@v1 + uses: actions/cache@v3 with: path: ~/.sonar/cache key: ${{ runner.os }}-sonar restore-keys: ${{ runner.os }}-sonar - - name: Cache Gradle packages - uses: actions/cache@v2 - with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-${{ matrix.java-version }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} - restore-keys: | - ${{ runner.os }}-gradle-${{ matrix.java-version }}- - - name: Test with Gradle + uses: gradle/gradle-build-action@v2 env: CI_NAME: "GitHub CI" ALPHAVANTAGE_API_KEY: ${{ secrets.ALPHAVANTAGE_API_KEY }} @@ -60,8 +51,8 @@ jobs: MASTODON_ACCESS_TOKEN: ${{ secrets.MASTODON_ACCESS_TOKEN }} MASTODON_HANDLE: ${{ secrets.MASTODON_HANDLE }} MASTODON_INSTANCE: ${{ secrets.MASTODON_INSTANCE }} - - run: ./gradlew build check --stacktrace + with: + arguments: build check --stacktrace - name: SonarCloud if: success() && matrix.java-version == env.SONAR_JDK @@ -69,8 +60,3 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} run: ./gradlew sonar - - - name: Cleanup Gradle Cache - run: | - rm -f ~/.gradle/caches/modules-2/modules-2.lock - rm -f ~/.gradle/caches/modules-2/gc.properties From 1b55736ee189ddd3f1663f38be4af6651372d6b2 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Tue, 31 Jan 2023 23:31:12 -0800 Subject: [PATCH 706/844] Added Java distribution --- .github/workflows/gradle.yml | 1 + build.gradle | 2 +- version.properties | 6 +++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index fa46754..2e4df52 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -22,6 +22,7 @@ jobs: - name: Set up JDK ${{ matrix.java-version }} uses: actions/setup-java@v3 with: + distribution: 'zulu' java-version: ${{ matrix.java-version }} - name: Grant execute permission for gradlew diff --git a/build.gradle b/build.gradle index 70e3d46..8b7827f 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { id 'application' - id 'com.github.ben-manes.versions' version '0.44.0' + id 'com.github.ben-manes.versions' version '0.45.0' id 'idea' id 'io.gitlab.arturbosch.detekt' version '1.22.0' id 'java' diff --git a/version.properties b/version.properties index fb36533..693db4f 100644 --- a/version.properties +++ b/version.properties @@ -1,9 +1,9 @@ #Generated by the Semver Plugin for Gradle -#Sat Jan 28 23:17:39 PST 2023 -version.buildmeta=983 +#Mon Jan 30 22:08:48 PST 2023 +version.buildmeta=986 version.major=0 version.minor=8 version.patch=0 version.prerelease=rc version.project=mobibot -version.semver=0.8.0-rc+983 +version.semver=0.8.0-rc+986 From f06ba4a6f55d769d1a5dd872ab394f86f047b6d9 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Wed, 1 Feb 2023 02:37:04 -0800 Subject: [PATCH 707/844] Added disabled modules and commands listing --- src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt | 10 ++++++++++ src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt | 6 +++++- .../net/thauvin/erik/mobibot/commands/Modules.kt | 8 ++++++-- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt index 020edf4..1127f02 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt @@ -74,7 +74,10 @@ class Addons(private val props: Properties) { if (logger.isDebugEnabled) { logger.debug("Module $name is disabled.") } + names.disabledModules.add(name) } + } else { + names.disabledModules.add(name) } } return enabled @@ -106,7 +109,10 @@ class Addons(private val props: Properties) { if (logger.isDebugEnabled) { logger.debug("Command $name is disabled.") } + names.disabledCommands.add(name) } + } else { + names.disabledCommands.add(name) } } return enabled @@ -168,12 +174,16 @@ class Addons(private val props: Properties) { */ object Names { val modules: MutableList = mutableListOf() + val disabledModules: MutableList = mutableListOf() val commands: MutableList = mutableListOf() + val disabledCommands: MutableList = mutableListOf() val ops: MutableList = mutableListOf() fun sort() { modules.sort() + disabledModules.sort() commands.sort() + disabledCommands.sort() ops.sort() } } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt index f811764..2dff959 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt @@ -148,6 +148,10 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro event.sendMessage("The commands are:") event.sendList(addons.names.commands, 8, isBold = true, isIndent = true) if (event.isChannelOp(channel)) { + if (addons.names.disabledCommands.isNotEmpty()) { + event.sendMessage("The disabled commands are:") + event.sendList(addons.names.disabledCommands, 8, isBold = false, isIndent = true) + } event.sendMessage("The op commands are:") event.sendList(addons.names.ops, 8, isBold = true, isIndent = true) } @@ -412,7 +416,7 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro addons.add(Ignore()) addons.add(LinksManager()) addons.add(Me()) - addons.add(Modules(addons.names.modules)) + addons.add(Modules(addons.names.modules, addons.names.disabledModules)) addons.add(Msg()) addons.add(Nick()) addons.add(Posting()) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Modules.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Modules.kt index f64178d..b2293b0 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Modules.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Modules.kt @@ -36,9 +36,9 @@ import net.thauvin.erik.mobibot.Utils.isChannelOp import net.thauvin.erik.mobibot.Utils.sendList import org.pircbotx.hooks.types.GenericMessageEvent -class Modules(private val modules: List) : AbstractCommand() { +class Modules(private val modules: List, private val disabledModules: List) : AbstractCommand() { override val name = "modules" - override val help = listOf("To view a list of enabled modules:", helpFormat("%c $name")) + override val help = listOf("To view a list of enabled/disabled modules:", helpFormat("%c $name")) override val isOpOnly = true override val isPublic = false override val isVisible = true @@ -51,6 +51,10 @@ class Modules(private val modules: List) : AbstractCommand() { event.respondPrivateMessage("The enabled modules are: ") event.sendList(modules, 7, isIndent = true) } + if (disabledModules.isNotEmpty()) { + event.respondPrivateMessage("The disabled modules are: ") + event.sendList(disabledModules, 7, isIndent = true) + } } else { helpResponse(channel, args, event) } From d9d5dd2e47f9d198a3cc55961247ba4e45958222 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Wed, 1 Feb 2023 02:37:39 -0800 Subject: [PATCH 708/844] Updated to latest workflow actions --- .github/workflows/gradle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 2e4df52..6ad0035 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -60,4 +60,4 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - run: ./gradlew sonar + run: ./gradlew sonar --info From 1d85a1c51683073aa1453be757716751064a0a61 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Fri, 3 Feb 2023 00:58:16 -0800 Subject: [PATCH 709/844] Disabled Twitter module by default --- .idea/kotlinc.xml | 2 +- README.md | 7 ++----- build.gradle | 9 +++++---- properties/mobibot.properties | 2 +- .../net/thauvin/erik/mobibot/modules/TwitterTest.kt | 2 +- website/index.html | 3 +-- 6 files changed, 11 insertions(+), 14 deletions(-) diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index 2b8a50f..0fc3113 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/README.md b/README.md index 4dee7b5..53bcfe4 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # mobibot [![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) -[![Kotlin](https://img.shields.io/badge/kotlin-1.8.0-blue)](https://kotlinlang.org/) +[![Kotlin](https://img.shields.io/badge/kotlin-1.8.10-blue)](https://kotlinlang.org/) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ethauvin_mobibot&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=ethauvin_mobibot) [![GitHub CI](https://github.com/ethauvin/mobibot/actions/workflows/gradle.yml/badge.svg)](https://github.com/ethauvin/mobibot/actions/workflows/gradle.yml) [![CircleCI](https://circleci.com/gh/ethauvin/mobibot/tree/master.svg?style=shield)](https://circleci.com/gh/ethauvin/mobibot/tree/master) @@ -24,10 +24,7 @@ Some very basic instructions: # help java -jar mobibot.jar -h - - # twitter oauth token request - java -cp mobibot.jar net.thauvin.erik.mobibot.TwitterOAuth - + # launch /usr/bin/nohup java -jar mobibot.jar & ``` diff --git a/build.gradle b/build.gradle index 8b7827f..f09cdb1 100644 --- a/build.gradle +++ b/build.gradle @@ -5,8 +5,8 @@ plugins { id 'io.gitlab.arturbosch.detekt' version '1.22.0' id 'java' id 'net.thauvin.erik.gradle.semver' version '1.0.4' - id 'org.jetbrains.kotlin.jvm' version '1.8.0' - id 'org.jetbrains.kotlin.kapt' version '1.8.0' + id 'org.jetbrains.kotlin.jvm' version '1.8.10' + id 'org.jetbrains.kotlin.kapt' version '1.8.10' id 'org.jetbrains.kotlinx.kover' version '0.6.1' id 'org.sonarqube' version '3.5.0.2730' id 'pmd' @@ -92,10 +92,11 @@ dependencies { test { useTestNG() { + excludeGroups.add('twitter') if (isCI) { - excludeGroups('no-ci') - println "Excluded test groups: ${excludeGroups}" + excludeGroups.add('no-ci') } + println "Excluded test groups: ${excludeGroups}" } } diff --git a/properties/mobibot.properties b/properties/mobibot.properties index e82910c..0f97f3c 100644 --- a/properties/mobibot.properties +++ b/properties/mobibot.properties @@ -25,7 +25,7 @@ tell-max-days=5 tell-max-size=50 #disabled-commands=die, ignore -#disabled-modules=dice, joke +disabled-modules=twitter # # API Token for: https://pinboard.in/settings/password diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/TwitterTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/TwitterTest.kt index 9651ba0..6e4ab27 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/TwitterTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/TwitterTest.kt @@ -41,7 +41,7 @@ import org.testng.annotations.Test * The `TwitterTest` class. */ class TwitterTest : LocalProperties() { - @Test(groups = ["modules"]) + @Test(groups = ["modules", "twitter"]) @Throws(ModuleException::class) fun testTweet() { val msg = "Testing Twitter API from ${getHostName()}" diff --git a/website/index.html b/website/index.html index ea78552..be6c33e 100644 --- a/website/index.html +++ b/website/index.html @@ -122,8 +122,7 @@
    mobibot: paper
    mobibot: rock
    -
  5. Posting to Twitter and Mastodon -
    mobibot: tweet hello twitter
    +
  6. Automatic and manual posting to Mastodon
    mobibot: toot hello mastodon
  7. From d67cf4ace765ca2cb842f0edc6afd9d7acd947ca Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Wed, 15 Feb 2023 22:15:50 -0800 Subject: [PATCH 710/844] Minor cleanup --- README.md | 3 +-- src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt | 5 +++-- website/index.html | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 53bcfe4..8105ed3 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,7 @@ # mobibot [![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) -[![Kotlin](https://img.shields.io/badge/kotlin-1.8.10-blue)](https://kotlinlang.org/) -[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ethauvin_mobibot&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=ethauvin_mobibot) +[![Kotlin](https://img.shields.io/badge/kotlin-1.8.10-7f52ff.svg)](https://kotlinlang.org)[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ethauvin_mobibot&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=ethauvin_mobibot) [![GitHub CI](https://github.com/ethauvin/mobibot/actions/workflows/gradle.yml/badge.svg)](https://github.com/ethauvin/mobibot/actions/workflows/gradle.yml) [![CircleCI](https://circleci.com/gh/ethauvin/mobibot/tree/master.svg?style=shield)](https://circleci.com/gh/ethauvin/mobibot/tree/master) diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt index 22e37cb..ef0eaaf 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt @@ -266,8 +266,9 @@ class UtilsTest { @Test @Throws(IOException::class) fun testUrlReader() { - assertThat(URL("https://postman-echo.com/status/200").reader().body, "urlReader()") - .isEqualTo("{\"status\":200}") + val reader = URL("https://postman-echo.com/status/200").reader() + assertThat(reader.body).isEqualTo("{\n \"status\": 200\n}") + assertThat(reader.responseCode).isEqualTo(200) } @Test diff --git a/website/index.html b/website/index.html index be6c33e..97e337d 100644 --- a/website/index.html +++ b/website/index.html @@ -69,7 +69,7 @@
    mobibot: view
  8. Performing calculations -
    mobibot: calc (floor(sqrt(3)) + 3.14) * 3^2
    +
    mobibot: calc (floor(sqrt(3)) + π) * 3^2
  9. Crypto currencies prices
    mobibot: cryto btc
    From db8469169144beb7a5b7f0758f62956a08ed6db9 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Wed, 15 Feb 2023 22:27:08 -0800 Subject: [PATCH 711/844] Upgraded to Gradle 8.0 --- build.gradle | 17 ++++++++++++++--- gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index f09cdb1..f7da86e 100644 --- a/build.gradle +++ b/build.gradle @@ -70,7 +70,7 @@ dependencies { implementation "org.apache.logging.log4j:log4j-core:$versions.log4j" implementation "org.apache.logging.log4j:log4j-slf4j2-impl:$versions.log4j" - implementation 'com.rometools:rome:1.18.0' + implementation 'com.rometools:rome:1.19.0' implementation 'com.squareup.okhttp3:okhttp:4.10.0' implementation 'net.aksingh:owm-japis:2.5.3.0' implementation 'net.objecthunter:exp4j:0.4.8' @@ -92,11 +92,13 @@ dependencies { test { useTestNG() { - excludeGroups.add('twitter') + // excludeGroups.add('twitter') if (isCI) { excludeGroups.add('no-ci') } - println "Excluded test groups: ${excludeGroups}" + if (!excludeGroups.isEmpty()) { + println "Excluded test groups: ${excludeGroups}" + } } } @@ -153,6 +155,15 @@ detekt { baseline = file("${projectDir}/config/detekt/baseline.xml") } +tasks.withType(io.gitlab.arturbosch.detekt.Detekt).configureEach { + jvmTarget = java.targetCompatibility.toString() +} + +tasks.withType(io.gitlab.arturbosch.detekt.DetektCreateBaselineTask).configureEach { + jvmTarget = java.targetCompatibility.toString() +} + + jar { manifest.attributes('Main-Class': mainClassName, 'Class-Path': '. ./lib/' + configurations.runtimeClasspath.collect { it.getName() }.join(' ./lib/')) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f398c33..42defcc 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From c2c5f8beaeb5ce48483209d29dcef9eee3f7da0a Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Fri, 17 Feb 2023 22:09:57 -0800 Subject: [PATCH 712/844] Upgraded sonar plugin --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index f7da86e..55c1a38 100644 --- a/build.gradle +++ b/build.gradle @@ -8,7 +8,7 @@ plugins { id 'org.jetbrains.kotlin.jvm' version '1.8.10' id 'org.jetbrains.kotlin.kapt' version '1.8.10' id 'org.jetbrains.kotlinx.kover' version '0.6.1' - id 'org.sonarqube' version '3.5.0.2730' + id 'org.sonarqube' version '4.0.0.2929' id 'pmd' } @@ -75,7 +75,7 @@ dependencies { implementation 'net.aksingh:owm-japis:2.5.3.0' implementation 'net.objecthunter:exp4j:0.4.8' implementation 'org.json:json:20220924' - implementation 'org.jsoup:jsoup:1.15.3' + implementation 'org.jsoup:jsoup:1.15.4' implementation 'org.twitter4j:twitter4j-core:4.1.2' // Thauvin From 207c1b7e022b5a7ebc4458d4e9c9aa12912a6049 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 21 May 2023 00:01:01 -0700 Subject: [PATCH 713/844] Removed twitter module --- .github/workflows/gradle.yml | 5 - .idea/codeStyles/Project.xml | 275 ++++++++++++++++++ .idea/codeStyles/codeStyleConfig.xml | 1 + .idea/kotlinc.xml | 2 +- build.gradle | 58 ++-- config/detekt/baseline.xml | 7 +- gradle/wrapper/gradle-wrapper.jar | Bin 61574 -> 62076 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 11 +- properties/mobibot.properties | 17 +- .../net/thauvin/erik/mobibot/Constants.kt | 6 + .../net/thauvin/erik/mobibot/FeedReader.kt | 2 +- .../net/thauvin/erik/mobibot/Mobibot.kt | 3 +- .../net/thauvin/erik/mobibot/TwitterOAuth.kt | 118 -------- .../thauvin/erik/mobibot/modules/ChatGpt.kt | 8 +- .../thauvin/erik/mobibot/modules/Twitter.kt | 133 --------- .../net/thauvin/erik/mobibot/AddonsTest.kt | 2 - .../thauvin/erik/mobibot/FeedReaderTest.kt | 17 +- .../thauvin/erik/mobibot/modules/CalcTest.kt | 3 +- .../erik/mobibot/modules/ChatGptTest.kt | 7 +- .../erik/mobibot/modules/GoogleSearchTest.kt | 8 +- .../erik/mobibot/modules/MastodonTest.kt | 5 +- .../erik/mobibot/modules/StockQuoteTest.kt | 3 +- .../erik/mobibot/modules/TwitterTest.kt | 60 ---- .../erik/mobibot/modules/Weather2Test.kt | 5 +- .../erik/mobibot/modules/WolframAlphaTest.kt | 8 +- .../erik/mobibot/modules/WordTimeTest.kt | 3 +- version.properties | 6 +- website/index.html | 1 - 29 files changed, 360 insertions(+), 416 deletions(-) delete mode 100644 src/main/kotlin/net/thauvin/erik/mobibot/TwitterOAuth.kt delete mode 100644 src/main/kotlin/net/thauvin/erik/mobibot/modules/Twitter.kt delete mode 100644 src/test/kotlin/net/thauvin/erik/mobibot/modules/TwitterTest.kt diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 6ad0035..0034945 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -44,11 +44,6 @@ jobs: CHATGPT_API_KEY: ${{ secrets.CHATGPT_API_KEY }} OWM_API_KEY: ${{ secrets.OWM_API_KEY }} PINBOARD_API_TOKEN: ${{ secrets.PINBOARD_API_TOKEN }} - TWITTER_CONSUMERKEY: ${{ secrets.TWITTER_CONSUMERKEY }} - TWITTER_CONSUMERSECRET: ${{ secrets.TWITTER_CONSUMERSECRET }} - TWITTER_HANDLE: ${{ secrets.TWITTER_HANDLE }} - TWITTER_TOKEN: ${{ secrets.TWITTER_TOKEN }} - TWITTER_TOKENSECRET: ${{ secrets.TWITTER_TOKENSECRET }} MASTODON_ACCESS_TOKEN: ${{ secrets.MASTODON_ACCESS_TOKEN }} MASTODON_HANDLE: ${{ secrets.MASTODON_HANDLE }} MASTODON_INSTANCE: ${{ secrets.MASTODON_INSTANCE }} diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 1bec35e..76b5425 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -3,6 +3,281 @@ + + diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml index a55e7a1..6e6eec1 100644 --- a/.idea/codeStyles/codeStyleConfig.xml +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -1,5 +1,6 @@ + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index 0fc3113..217e5c5 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/build.gradle b/build.gradle index 55c1a38..6a131ab 100644 --- a/build.gradle +++ b/build.gradle @@ -1,13 +1,16 @@ +import io.gitlab.arturbosch.detekt.Detekt +import io.gitlab.arturbosch.detekt.DetektCreateBaselineTask + plugins { id 'application' - id 'com.github.ben-manes.versions' version '0.45.0' + id 'com.github.ben-manes.versions' version '0.46.0' id 'idea' id 'io.gitlab.arturbosch.detekt' version '1.22.0' id 'java' id 'net.thauvin.erik.gradle.semver' version '1.0.4' - id 'org.jetbrains.kotlin.jvm' version '1.8.10' - id 'org.jetbrains.kotlin.kapt' version '1.8.10' - id 'org.jetbrains.kotlinx.kover' version '0.6.1' + id 'org.jetbrains.kotlin.jvm' version '1.8.21' + id 'org.jetbrains.kotlin.kapt' version '1.8.21' + id 'org.jetbrains.kotlinx.kover' version '0.7.0' id 'org.sonarqube' version '4.0.0.2929' id 'pmd' } @@ -29,8 +32,8 @@ def isNonStable = { String version -> mainClassName = packageName + '.Mobibot' ext.versions = [ - log4j: '2.19.0', - pmd : '6.54.0', + log4j: '2.20.0', + pmd : '6.55.0', ] repositories { @@ -61,22 +64,21 @@ dependencies { // Kotlin implementation platform('org.jetbrains.kotlin:kotlin-bom') implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1' implementation 'org.jetbrains.kotlinx:kotlinx-cli:0.3.5' // Logging - implementation 'org.slf4j:slf4j-api:2.0.6' + implementation 'org.slf4j:slf4j-api:2.0.7' implementation "org.apache.logging.log4j:log4j-api:$versions.log4j" implementation "org.apache.logging.log4j:log4j-core:$versions.log4j" implementation "org.apache.logging.log4j:log4j-slf4j2-impl:$versions.log4j" - implementation 'com.rometools:rome:1.19.0' - implementation 'com.squareup.okhttp3:okhttp:4.10.0' + implementation 'com.rometools:rome:2.1.0' + implementation 'com.squareup.okhttp3:okhttp:4.11.0' implementation 'net.aksingh:owm-japis:2.5.3.0' implementation 'net.objecthunter:exp4j:0.4.8' - implementation 'org.json:json:20220924' - implementation 'org.jsoup:jsoup:1.15.4' - implementation 'org.twitter4j:twitter4j-core:4.1.2' + implementation 'org.json:json:20230227' + implementation 'org.jsoup:jsoup:1.16.1' // Thauvin implementation 'net.thauvin.erik:cryptoprice:1.0.0' @@ -84,10 +86,10 @@ dependencies { implementation 'net.thauvin.erik:pinboard-poster:1.0.3' implementation 'net.thauvin.erik:urlencoder:1.3.0' - testImplementation 'com.willowtreeapps.assertk:assertk-jvm:0.25' + testImplementation 'com.willowtreeapps.assertk:assertk-jvm:0.26.1' // testImplementation 'org.mockito.kotlin:mockito-kotlin:4.0.0' // testImplementation "org.mockito:mockito-core:4.0.0" - testImplementation 'org.testng:testng:7.7.1' + testImplementation 'org.testng:testng:7.8.0' } test { @@ -114,6 +116,12 @@ java { targetCompatibility = JavaVersion.VERSION_11 } +kotlin { + jvmToolchain { + languageVersion.set(JavaLanguageVersion.of(11)) + } +} + kapt { includeCompileClasspath = false arguments { @@ -121,15 +129,10 @@ kapt { } } -tasks.withType(JavaCompile) { +tasks.withType(JavaCompile).configureEach { options.encoding = 'UTF-8' } -tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach { - kotlinOptions { - jvmTarget = java.targetCompatibility.toString() - } -} compileJava { dependsOn 'incrementBuildMeta' @@ -155,15 +158,14 @@ detekt { baseline = file("${projectDir}/config/detekt/baseline.xml") } -tasks.withType(io.gitlab.arturbosch.detekt.Detekt).configureEach { +tasks.withType(Detekt).configureEach { jvmTarget = java.targetCompatibility.toString() } -tasks.withType(io.gitlab.arturbosch.detekt.DetektCreateBaselineTask).configureEach { +tasks.withType(DetektCreateBaselineTask).configureEach { jvmTarget = java.targetCompatibility.toString() } - jar { manifest.attributes('Main-Class': mainClassName, 'Class-Path': '. ./lib/' + configurations.runtimeClasspath.collect { it.getName() }.join(' ./lib/')) @@ -204,19 +206,19 @@ tasks.sonar { dependsOn 'koverReport' } -task copyToDeploy(type: Copy) { +tasks.register('copyToDeploy', Copy) { from('properties', jar) into deployDir } -task copyToDeployLib(type: Copy) { +tasks.register('copyToDeployLib', Copy) { from(configurations.runtimeClasspath) { exclude 'annotations-*.jar' } into(deployDir + '/lib') } -task deploy { +tasks.register('deploy') { description = "Copies all needed files to the ${deployDir} directory." group = 'Publishing' dependsOn(assemble, jar) @@ -228,7 +230,7 @@ task deploy { mustRunAfter(clean) } -task release { +tasks.register('release') { group = 'Publishing' description = 'Releases new version.' dependsOn(clean, check, deploy) diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml index da082db..db7e772 100644 --- a/config/detekt/baseline.xml +++ b/config/detekt/baseline.xml @@ -10,7 +10,6 @@ LongMethod:Weather2.kt$Weather2.Companion$@JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message> LongParameterList:Comment.kt$Comment$( channel: String, cmd: String, entry: EntryLink, entryIndex: Int, commentIndex: Int, event: GenericMessageEvent ) LongParameterList:EntryLink.kt$EntryLink$( // Link's comments val comments: MutableList<EntryComment> = mutableListOf(), // Tags/categories val tags: MutableList<SyndCategory> = mutableListOf(), // Channel var channel: String, // Creation date var date: Date = Calendar.getInstance().time, // Link's URL var link: String, // Author's login var login: String = "", // Author's nickname var nick: String, // Link's title var title: String ) - LongParameterList:Twitter.kt$Twitter.Companion$( consumerKey: String?, consumerSecret: String?, token: String?, tokenSecret: String?, handle: String?, message: String, isDm: Boolean ) MagicNumber:ChatGpt.kt$ChatGpt$400 MagicNumber:ChatGpt.kt$ChatGpt.Companion$200 MagicNumber:ChatGpt.kt$ChatGpt.Companion$429 @@ -33,7 +32,6 @@ MagicNumber:StockQuote.kt$StockQuote.Companion$10 MagicNumber:Tell.kt$Tell$50 MagicNumber:Tell.kt$Tell$7 - MagicNumber:TwitterOAuth.kt$TwitterOAuth$401 MagicNumber:Users.kt$Users$8 MagicNumber:Utils.kt$Utils$200 MagicNumber:Utils.kt$Utils$399 @@ -47,7 +45,6 @@ MagicNumber:WorldTime.kt$WorldTime.Companion$3600 MagicNumber:WorldTime.kt$WorldTime.Companion$60 MagicNumber:WorldTime.kt$WorldTime.Companion$86.4 - MaxLineLength:TwitterOAuth.kt$TwitterOAuth$* NestedBlockDepth:Addons.kt$Addons$fun add(command: AbstractCommand): Boolean NestedBlockDepth:Addons.kt$Addons$fun add(module: AbstractModule): Boolean NestedBlockDepth:ChatGpt.kt$ChatGpt.Companion$@JvmStatic @Throws(ModuleException::class) fun chat(query: String, apiKey: String?, maxTokens: Int): String @@ -65,13 +62,10 @@ NestedBlockDepth:Seen.kt$Seen$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) NestedBlockDepth:StockQuote.kt$StockQuote.Companion$@JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List<Message> NestedBlockDepth:Tell.kt$Tell$fun send(event: GenericUserEvent) - NestedBlockDepth:TwitterOAuth.kt$TwitterOAuth$@JvmStatic fun main(args: Array<String>) NestedBlockDepth:Utils.kt$Utils$@JvmStatic fun loadSerialData(file: String, default: Any, logger: Logger, description: String): Any NestedBlockDepth:Utils.kt$Utils$@JvmStatic fun saveSerialData(file: String, data: Any, logger: Logger, description: String) NestedBlockDepth:Weather2.kt$Weather2$override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) NestedBlockDepth:Weather2.kt$Weather2.Companion$@JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message> - PrintStackTrace:TwitterOAuth.kt$TwitterOAuth$ioe - PrintStackTrace:TwitterOAuth.kt$TwitterOAuth$te ReturnCount:Addons.kt$Addons$fun exec(channel: String, cmd: String, args: String, event: GenericMessageEvent): Boolean ReturnCount:Addons.kt$Addons$fun help(channel: String, topic: String, event: GenericMessageEvent): Boolean ReturnCount:ExceptionSanitizer.kt$ExceptionSanitizer$fun ModuleException.sanitize(vararg sanitize: String): ModuleException @@ -91,5 +85,6 @@ TooManyFunctions:EntryLink.kt$EntryLink : Serializable TooManyFunctions:Mobibot.kt$Mobibot : ListenerAdapter TooManyFunctions:Tell.kt$Tell : AbstractCommand + WildcardImport:FeedReaderTest.kt$import assertk.assertions.* diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 943f0cbfa754578e88a3dae77fce6e3dea56edbf..c1962a79e29d3e0ab67b14947c167a862655af9b 100644 GIT binary patch delta 13895 zcmZ8|Wmp``)-~=Hdu)0n3Y-8OvyK$p9^s9MM|Aj$miotNhy-{udLczZyd9uWtD)X_{|!LhIEF9y8(e*Z zW>^w$u&x|i9OjL=#6Nl~*ERulzX>8C-}o;iSMRYdfCU5d`~U{V4>HCg0HG4Xg2uP;fn!>S9+>LbuWbc0bETMQfo9~h}yI*TSv;Oikl~t-+xqI-`P$Rj@yi{mr2zC~s1snMT3!OPBdJ%IDnPXq+pl*Z>=+?qo${lkCSKmwTlVjfb3thU6B8yFjr!tphOs*G6 zwL`RyVAUXj4p=9&@PpWK)m+REuvHaq838TEhY^7W+JAp$ zZ^y;8`Z*@VqJ{sFFj?<|7SKS@G`$Yi)gx%nOi@Lr zCv0IJlFz0bP(eDIW(uWNq?;8zEAb+uGgnkLk;y!4XhA6=Eoa<`+|;6mOq>z`%ir@z$4)Mkd3 zF=hFo zyd{*bRQ4YUe^bU*Y`__)Uhu5NIjVJ~a}{lHp-_7wI?#EB11XcqmdY>pk`JJ) zW9Rt!tK=N>fZ!UDomwMnb`0EOvTjcNl=yW@$c!OAg*=l()GjZwSyJ+o^;Zi#I5*uP z$6qeih8&g8E(pNSneK>93A(8*%gvwv!0V|SqGcj55Y7`=N*@pJx_ig3uVuf-G~LJbm`7nxNcZ>Jgqy(LTHu_C2e>STp^Pm{}f&^)XU}vzuU`UV&>e& zqsXNXSs;Wri|?NhCq0vXC5$>9Cag$adyWz^x@NCiy2${9Dc)Y;J8k1Z933W$3$H}g zCQFU1XwzGm_WUheXvnDisH_%BdzMgNwk2^mHcQu*x>U%iN*B^8U(eVz1~(%`kV1Vb z=9T0xmN?bQMyrrd?u}jer}zV&sCK6zSm!zV8A8dP6THF=4*V{_K*E*K<)I(Q^(eV!m!vu##-2g|G z{RB;{gJB_X-w{ANq?ft_n!@=O8_gj6FxW&zO$7L3@NjWt@R{NxMbpHLk6;=2$0P5P=kKc1_85inX z#s$&s0zhV1cz>nRb#|D#N8Z-=Tphm)sGH>9cz3K3I)6XpimJW0(6$GtLzN(YPu9%R zdFXG9|30AZME4r@joC0IdvBBe08mF@+5Dd97p$h=n|pi80Cn2n{ev!S$llPGLqHva zZ3*OmW%!Qj>C$F!Ffafl7#I_1(gz!aa)b{ebU*=yH%^kr=~N?|2&2Df2o9X=2B?U!#R#+Cj45=f@=EcQx+9J z=X3~A=zbX29Fqn23m3dm}0Voj^Q9BjI=MiG+NZ)YCYn@r^qv(xE3=)&i z=(ML301=rNTptvUt2tnsPb1~G*DWFWoZfv)wV|uNW%?!)jju`jN(K-0$JYi!ofNup z9K%_ucHwutbZsl~vDQ!Jtj8uI6WA6K--@?8+_=t>g|kgUeC=w`IP9m&*fuoO3#A;t z&3@=3;J0>yjM89?h5MG$S`wW+=vyYOWQGhIP`^vScM8^JL{mGan5uTJPvAg$0z}8; z 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 J*WbtZ{{Z#P!zlm& delta 13442 zcmY*=Wk4Lu)-CStgS)!~5AMM=xVr|o3>Mr6cNpB=LvVsyAXspBcgQ1o=R5aaest|x zYp|Ud;3g1aLn46!*8mAJI&Z-nf(`=#0paw?iVYg# zKUs^o|DOcGK$5&gPV0aMK}b!cw=e}1HdMgiC8Pg8*>1^32Z5FfsER!G3mZ%qKjJOpfesiQ2!1wa9roW6I&DK_t$shg|m=c2cE{QdM|NtSH0rXoXzvmNP+5U2LV{^QbB?sv0VKm95!eQeL4~+?=ho^^MZI zi4QY0fsKBbqrOh39Z!#mM!z2}i6F-BHKbV_Q&qzRsaF`l1Vjpm1sC-ZseEjRhHlco zfXoyCv0NC5K}!1s)zB(Gd8sKQIBYyB)bFK(2G2GM&K4S`>_HR&4tr1?iRab0FsEbp z*Jv*zm^-fRK+ctLcyDjn-afw<1S1jM(4q5ykfHQzL_}qIFL}{AIQ>4(4ufTO5LOPw z_jW{#M|)nyUycekv0yq3ALu*Gjx4MO>bHe*!#3>nE^vCCDgcN>sA^k$Zux742g7MRGS5YWh9J!2T zS<0JF@`%w;58G&U(_V6*RvcGc?)SP#I!b=^l;;8|2L56hb1X6;bd2imS_1e~0c%T; z1T8HGf8HR3ELFmM^n?Su6+Q7D+$t^=tIK-pWi`W;i!lHwI+jG7m{1RRjBU0~dzp zhN*kX9bAON4=>l-DWvYo*J$Q4Xp~|yYTaabShU@ns@lubZE3xU%6MYv&e|3AuK8?k zu?#J5JQ%%TJ7Bb$Gs;&*)*UAk%Oo-5q=+2(Jm zIuppiu)ZJ9p`Q{Ox6P5{rbDkZk#-Qv`%KHjq9XiNOUl8kb7aZj*E~>vv^dbHH4oOd zczWr1LJT!^o_(O*2>j}6lOtE3Z)Pht?L5pyzPpntJ|r!%j z5uggS6oZWkpVt^698p3fEKA&|+deWq)ldqZGKG?a|~=1V2xdW$8-mayFlC zJWmagu;BBJC#|ZHrUXfE&`4P20AGgWC5=H0HjYm~^E~OwgAnMps?;#CY=ahb7%?H$ ziejQ`%0Proz9+myGwpEQf^)-=KkUK?uyDVM9dcP_xwRPl?asXN_w$2*H zua=Dr(GFqiFLl870&u+1P>>n@QI(3gk(rj0%e8Ar$G7fdFyGel0{sZrPuEX12l`k< z5>lA+*xaiLY{Vo_72dq>E!s&D_ z0I)&YzOCXkxi;^DvcHbfU{x!;>3?+f!px_0&rPIW~iPmIG@n7rmiC;XiLC?f3vTJUz`Gg=p9 zK8)mv-V6dl|9;(R_$VaJ&lBtE0aw!=g-iJ(;|-J>nsF(42in0{Gp)Wy}WNr3llis^vYk0y2t{zC9G7SQW8GEvz>ZPi09E9wH*yE=+9`RdARy$??) z&b{^h_aIn=A*FNBQ7ATjvh&tjsQ~1FV3r;lW1~f8kh24Aagu#Jxb89ZAs>t(Qw(FD zS|S=1m#oMS;Dwi>0@KkG0*-OHaJb4?~;#3j^WrKgCx}3YozM}uF#0{&QFMled>Mo$+hUe%lY}nvK|5GwA1fTy@ z(^KJxKj6OT*`H=XLgP=vBF+Dn0wO;EGz7>+V7(zo`X~r*4Zb>n+<&CFW^ zx;O-Yo^0{nqPJTC5S<;>8>L{^1C9Ql@|#RETigaBa*_pJOL-@W8p+w%^}Gv*)l3j& zWma|3USri z5Z(cKy3rMvzZlR?nR7E6wO%( zDf&3(AqN7_lQ~96t?KD<`i5K_pH$aIxYeiWm}ICd!1&&$NJHxywzKXt0v0W~ZuFwG z5rq7KRa$-&A|tYU(+b&T6VxMx2Qmg$O$VM!XY^ciTE+)P^vMMLl^U-ySP1P83$*2u zNcQ@)+ok4pN7x{9Z?XBZPr*Vr7wr91_FvBH=xc%RZ4TH$W+0R#VWB0Ua`8O;-2Pnqo5QG!{#(=RmvtM({fuA>4ai&IW$2`P<|D!v-qs^RSsZ z2+y{qc6(Io-Ywwf<$c?(7ay7Q&wZ)JAdk<#iTYCy`PaXy(4aeKd-6d}u}-UT9jad< zPB+QbuZWqQGTG)@?W;;TDUqxD9Q+ao``pz(B`&cPTFR3|P6fz8&WRjU<4 zKLyJI>Cm{uI!saN=y6~Pp0Yiw`YLo6*z$^aOS8b)G@I&C3g&BsS$8cSG8QK(iy>kZ`195!*f-ndgPIM}p9?J=GYwFDqRYmdSymmgW9=>uiSN z{#DAsx#ke6UQ;6!o#~HR_BN1VnmUn=c$;LY0ajlu+#0J~E8a8UlvxiJ7^)K-FrJE% z<2gebNA1Z==jc$B(7~TXXM6&Q)3pToSPkWWSOl$HC)oA zgNe5(5xkR+BQco*Qiy6ns0vv|LP>(bx@_3vrzwIU;zwexl)cvpL>(yu=LHEOokp5L zRA9~H_ysBBuJrkjur_&)92IMj*o{ClU=^%$`6*Q~>ISJTt7*aljn)-ljW+BK3w>s| zLN#{_x{$hhj7jvX2)Uy)P$0MUVAnPRgU&7jijQ%_?AODC$j+(yrkEJnuiw`IZ7!R2 zPB4GAo_x+e`MWBlrj}-+i-p zjlo(;u36|+c@du3o(ChHTb!CNG1uvA!k!ACwEt{gFz)!#yl79^=yNgIS(ucgbSZVj zR+{Nqx!hUAVk>-}*j$=WTI$Wgh61lQum5C;c&WKWY;gwydc@?bv+*)FqXm13fAnj~ z7*E%gV-~u|mTx|mAw-ZO`Bi*+jS3ZWr4V0~ zh0jG$(j(1RVT&D>u$wVNqIc}P&MlcPYg z_5|^fraxyhG$cMGT+&0SEe)_*oGW>KQZ~0~Rq(Ly?T1~r;_P(>cUwlKd0k}|K>BjD zPqf(ox&pVUNt_0FAu<5Ry?hfTydm-bPTF3CYZH!1pu(4}QAR&!8!uXdc*_CBC>{%1 zA#ZnKhO=T2`m_g!lt@+#fsRc8DFky1Glal5Y`)UPr+ffyzIo=U{^j>S8)Iva%|F%A zGycyWb;bAUPc@wa68+gwA19vu!9Z~EZ_QRl-&-LDp`8Ih-Pu$4|EZ)baFvDzZ+qHA zEC>in&_*!{DEABjn62&YhoepMyX%-^)Evr&KA*^%h@n}5{G)gq78)|*fHeX)qcQ9U*FEo?pAZ2&Lq&Gb-n;6#E_Xu)r30J;4{Oxf#|W(TISTm37EaLAz)5( zb1#?ZZ;q%NG(z8!JPil?M!oqa`W!eDy}m>{b|!``@2#VCMt(D7+2Uyh$(<&;@EQ{J z9;IF1P;>@bd{rIHJhxo+R-ifU(Mvyf==AfYG4+z6+4Q1Ar=nOHUA`Ok!e3Kj@w~@yTV|fh zG~45!>b!@cwCpXeD#8WQ?o1;`s8Gotuz$`fbvPoAP1e|d71`QPX&ZV+oBm-u;`HE@ zym&N?*)l!sMsiRqUCH=ki3ME&qFxMUJEEzrkRkAmSMOkwUCrLg(Ig%_Sr!ztKfZ&I&V|;hkBz1&x)60kft|N;0kXv~YbhB+EPM4N&!QS#}gP3tLBgQpm6pCr<>GQPu|KzFkk@ zOl|mn?>(D2)rZDbhsv1rnmK?{HP{lsAt^U^B+7vBxyOSavbz-KuGLmVO-nU=o z6S)#sswKHb>egmHw;{EM^SRV1M`pAk%gw4o7vPVDDKws)dfEG=5Opk4ayvRjWd%MK zXYcoEj?$jD=(Zg5!X+}wY2~0gxnC&q#zc-9wV0VW_PZP2tztcR_L@_n9AKCBu2fRHnbjeyv<*yJx~og`}k@A0HvO@R|K|$hBMLQ=WrVx>{$Ar3jVpsHmuC z$t3qeB>3$4EYSl>!zj&+H1r&FyDogkkYpysdb~}}mQ$u9=gVLTQ=Ns$4fWH&Gy=E_ z%CR%}(Hu1zm@)A~It;A3Re$W4q#uP;pyBCK6ta|7RTit)0mWh==&(r2UnTNDxk6om zmC>MJQS((G-uhP&ZPN^6Ry(Rrvz$XAhg$K8((*`87J)?Ujsv1THp9U~zMz*LJ2W|s(*ZTJ+2yv_eH*%dgVNuT(K!EpdvA^glL-!ujzY3Y z`KD{RAk{+dBc8b1NkgVVuh7c{#ta>ikwf9R&>BXBG@;6@!IJ8s!{^!TOSnoiXhJKq z?$^tc4t>w-N4X8((semr5<}q8VoD}!Pl|ZIk^JZ=leGyf(d(I2BU2>tl34u@7+jql z4N!&y&O_{Zbr!2bT8oPEH#c3eTM8Y6ab=2t-SM_`QpwW~PL!U-RtbW$9TA_Y9`}KQ zIm#;}*G*)&@z!0tS3P?A^WhYQLr zSy4ZZ5rI9~P9E!9?O~2mtyH;!ESE4k4@kzyhIRzCqRn~`#JT5k1Y*8$8zo4k?H~CF z=kwf&U*-m^wM5Lnx-bI|b%lcR0g5_8HsTc`$CD9QTdkZjx~{mG+?Fmpm=>yMB=5rp z!d|Ru`@?G2Kpu)ttD7#&4(`giOjCpi@DuC0ftdE2HAgVQY!X#HSTvYwSZIlvIXwJQ z8|!>2H#uIGlyv;@QWAKhAIV;3HzHTWzLYdyz@Rn3$xF(}6y`f2O2*-W=5m1`Ts3JXDuiYr z6d`uOh7w_AtN~-(cK;qFotu@Cr2}!C4)Mmfbmo~F$bUPd9bZU7p8bTd6>_dmBH53< z4^|H}aUq*qgxnNnJ?$CS$bK(GbLfnWmY8&GM)SB4&z#XOi3IpYi84+{|@ngymx$~Rj(n;X6$p3B%0|6q}h`vw| z5P-LTue1EUBRM<61|}yNC}WG^gs$1N7_|QquUfm;ERxkj(nHF?7$A@fr^X(L0Yd+JlyIbivAQ_WnVN+;*y|^d-o0gj@Sj0@Ll9H0=1@hE$Hta zR2PzZH0j!kKBea;ePh?Jrz9Ko7nOq28iGI}i($3?7&Jc!m;GLB*io;%#<2JUVUyNS z!x!dd5#uN<(@nza%(Q+QY+5y16l%qlK@t)s6jyvV^GzU}5{h^k#n=pC00#k<0GqHun4N7jH*p5NKxwY-`-poyrq98zAIn(Pqelhp@wBZS z;VPUpIZzh2>BSRb$Z?b~p?EPDjb#@KnB}){l5^=Naz&X^lrUaq`pipVbPx&kM1xpN z6F(xQqnZQL23bVMsk6$`?ca%u_*|N#<8zPrmThWVf6KSa&6A2d5O?dgv*@;Cgjp*B zq9km)rsQ-BmlK{>#^X~h*KOtJG(cw&oGPG2kQwhrr;VYA)J|^_Tgrrk@v%jYPrQtt zNfNI58EA5j9B%W{vgy!n`D;ueZJM60hba*peuxnK?;^EQuvlBbfq($AfL4p?fFBY4 zH0I_+=o&hQ&ljK|L&sGS&1sHDVe%tu)bbFl9j zT><}db*{&yjtx=~fNtE&hISi_2$bbgHKcne3!$?U8jyO9f`8uLE93M`HT*Vz6ZRT1~`1F?D!-$WNc;<&((Ib08Ag&yg|t zgjctZts}}?Z4*NkMIsVgJ|ZmJJcPXWHXI8k&Q;t;h5YLKm8n%R?^nsGhnP=8*y={8CBq{b z{Z1z2l0k`Rey6&pI09&?tw5cO;>4>RN@eM;5S9L+n!_|Sv1%ql{6v*EAj?yZ53f0e zGuz;q!pFarb_lP-92?X@yK2iBQ;9w_7OK&>_`#l?oq;sGg&;vunv(hKK&)jBGjxwu z@Kdut>cI;O;%x00?ndE2=bbq|pIxuF6kh^vxsjCt#~RjYlIH>zABUiYp4!%AA4{6OoRsk@aiB5-scca{ zgAc*xCz9H^EL)%*w$84D!Nm3-fZNkzve)G0*kYJ`?d zIpjut2dLm)=AZ34RwGb!v*GfMJf3||p%&~r!JRCSvmq2}EZT|TU?LW<#WEpSedEKH z9rtUHv@iE7LQ_c-f8H1-Znqi5p#pMe90Z!{VAf*dI)stltyRxJvofFk(yti0 zx|9WUkxLZkVJ0Wam1udF5}C2ce5Qug{)O+Ie*AF8Rv1#EQjKet91DYB#y(b#(fqxD z=vSK6#ca?)n&qt?EibeHleq-0r6&V>JLM+Sw|sprhxy8nA5LOrEOzx@et+=rHfShJ zXBp4>%&;4QGXd`*jU>amD8M9P-G!n1X*1*#@TeB03U;X2eat>Nze&YfGYg@L?*?Yu(P`DMIR42wH#Yo+>sAW0hA$p6f!s92m}jI%+zHV@~WpCT;m8=%^DqO zW|QW@yFWsIEu5wBkt~^=L1}fQ&MWCTUWZ%^n+FxEYE&eo_{k&hvMGy1Ca`awgh#=pynJdeU{rREf6`K z((@f%xEN&nCFyJP#M;K$;j{2-z>T|#ZvC_xM`?+X1vDf{lyKwxeBPPRdLkF-l{ z&(J5~U}ZMBvu8z(iVsZBPqjeE3+mAUt{@d`Hbpx#TlcruF$Zq(v+_Gz*1q%Cg0J$b zMWqv)I_|9_JwTh7s6NVxU@S6fZ5rP*(b;?P6W#M|Q{E%HF!*3aq8ZM8My=ByJRL_H zIB|FJLP+-G0rGRa%}pH--cJA`MaG=)el2nma18yxjp$ePRo^pqHhNFtN}b#Yu-G|j zWV6RBb9UZ16LPOPM<0hNk_U1n)~-O>v$k)+5iV1a3$HQSx&#Nahs319%u@A(zX5fD zSVdp$R9X)pb`6ayC_94ho$fEO{b`m?`*5v73IQ%*^kBH6Af!-`iXg>&@Ti`J!j!CN zqZ=tqJ5I;-t+5^@=@Nk)boU~N=edVvmmizr$_7cy*AqEy`naa4JCM)h0g`Batz z0j|PMD9#>RO=h(8sRzt1$QxCWuK5yEEk0YzBLc*B8CA_|tF=SP-u)Du$}6+$f{C~* zYylAlW#yhgHyzX7HR9N!Egb}*7{*O&+yw|Xt1d<%7LsW`dD@@74_EH5Kn7D(jhyKR ztLMrI5&Z5r*J_k>D73H^;gT!1`&99L?U`qv0JX&t)xEWFsTEV@i260l6x2!x_s>cx ziZADsDqDN*uO#2{u1torx59SQ8WH8~Hp^ryB8iiR!+Snt6CWS5B?UWNNYc|k>`BD{ zYp%%pIdp~ixk4jVw^H3+fmGirFLK>JfB9W`WprPYwrcV-Rp8qQaQ1=cGYL(V8K7uZ z?>ThBDUxb!^P3g3P@%`n16g9n@3O0J_ZHc|Sx$3=765keIKkMTW?fE`?l(j>Q(D}8 zQeP{s1fLD^F80G9W}~+%!&E+771NZeI!*9j#63ozC6Cq{T4Y>PkO61fyoOnrTT}-v zSoG#e@#Eu}MUm9d2MyH=&hpcJ%DzrGwM2r8sOqYyKfE#eabL&ktLQo`!@2;cd(xWh zT21{``ca`~=^|5c0}5Ee+#QZCT2T+zi`WXMPq1hKjYA9vn+#WnXU(^~L0GU&@Ke$; zuTt~8$=y3*MW{$X4^_dI9c3Z@s!?)NF4{|P7ITA@HNmcI8oHsVU7EylK>KEm78ma) zzv=g=vvQ9L2@^f9$dhf5kDAN))XgGt=_S~1uW`j{fa{a>hB?roaklqoO^aeS$|15X zLS2;v%Q5}uW{+H!rYDB1Wv=w3f7W!H_)^wjm%UP9D}{n?@+r64IwvOlE1ZG(sx8 zxP0lDg_&q3k5(_$>3AH4sMfaF!*3Qd9t0-HH}GiCxS9Ovett?pgkD5~Jr9ZE_b~^# z@@px>rOE}(h6WKV{1nvaZ8{*FHdl4yLh$n<_Wajh@-}ws^C?X0{-QP*|;bR&Co=D@zEYi&qyMo2H@C8da2rC z<@+vZn_uzIsT&C$g9%}5R|&KL7ArBuumo$#kTltOM#2?LO==v=9-(-pJiebc&}?(k z9t6WY7a?z(Lk{pcnht7Ix`EcCdu?XDw`B0#G12gftNye$S~LKY0hNgAlLarMO=Ehx z`1I;djAMh-67)+g@uy&|bh}bWe0Q0?Z&vUVv>>J8Yz=WqQlzPp1Fn8I%+*V4eBAE? zusO)vcoH|M(>vwgf~qA&;OuG&DyBc9Ipspa@;(A>ioPZpEy=tV2bq8mrVVHArq5^U z{R@**&ZwMh2Hq3aX}jDDEk$fg2@(l1*)Wd>qPW^Hj)T>0-Wvp`t7X#q2X@I8=19_N zDN}0Z_+Yi^6TDyldcxyD$l_tj=Vm5u7>$nZ z^<)jSSGVaVI!{W~yjC+okMRu{T;rFWkeYJgpw||gr{RuJ0;^l6C%Pt&voP(cJ#rer zN0`58?^on)hG`iEC+jch$#)#US-(T{S(W8AnPcEicN_$zI`%m7daOnY-xs&sY;}FC)Yyrd6u9s{NWom+mGt2+hV(rC8#Pz zcYNK#5?|CF-@ia`@=hIGOQ^U6KdAxRLAODx1`Awqja1}EbJiu&TRiP=4n-ZXe~43c z857Upg}*5HqFOb64SYa2*QwA4-&&6!-w3^fVC^IMs^&E{tKt%1$$rk>oVValmdxEY zLUgBo@R_j#n``I0Hm_N^>3Px-#P}GMsK!)hE+bh_!N*{{;r?U6WR%UQgCtYjOyUR-fm)Fz1#Q`O$cqA*CQrT4pC-M84+$g04 z$Z<%t#eKQ1(`*GDHvBjAim5>_l;j6PjDe`&FV`43)CWJzn`-jIG)QszRz7u0{hPy{df+b|8lfD)Sq!8;aufj=wu-HojGV53sOYStR| zGb+>GH29hTC&2uply=Fl<31%9N5lD|+wU&~m|sS}yTg)=aW`r=gpT{*9mUnB(&AywS|~%d z(l3)6kI6A#-P*IiYE$@9UHv#IPWEqXFN>S7PP}_G)SXp8r7*v0s=X0dm|B*wdiTXI z%-Tw)^LTL`-G^?m#~g;q8=p<}t0%rr&}x*;zg#GJ zqU~g9JQLJctDdT0VDZ!>q!Jll75s@26bpqw@MqXZQkB~or|urqc7dE6bz>lXRA86} zI~Y#-(bq8WD@NIc=f~QgiIbi%e*OTmtrBVQ4&m3lXp zi(BY@`7@P!13s^Uy1twfSI%{+sfIyBlBT*yeZ*xxTff{{`@IEPz)uB7e%>0oxT9DF z{qRQoI=@wt;QEmY<7?hp-x%rXBZOvN6``+)be&QS=UoA-6L5NnTCWL)q29gC% zd%M(1&m*zE0vYWt86O)s+tNJw+Ez=TVqSaIS78%`9xBw@;k+=;J~Owq#|dm-qw}sa zizvtY1~d<2nvST4eRX z7Oz!)7EL6Pf&bdPq*f2rwwoWet_^TNJx{~JT5%O_>T33*I#laoFmX?+L~9sEtGS?Htoj->OE7d51ez z?s43UVib0q_tavOp?pr3+FrX6LM<_U{S62Ck2kQp;*Z-evTy5;o6m7T=FNEkGQ0pZ zOpe{Y`4d2$Z{gas%pZ>e-5li~=l&mqpV1n{TNJn^_D_FdjrgAkY5mRm_cupko#`!d zTGxI%CLjYq>+8IK832f5L-?PZkPW)GsB**b?TEZ-{dRQQ{1YqS0zk)`f3hm@03eAi zfw$;_7ywG$5_*ePNC2RdE#6J#qRuhOJS80 zkhqHkRlo__pr-<{?fw~q>Mj*j9uH_^mjRT!`)3dvd;sLP*9HFm6b2T7)^|nUP>MY& zs3yU`X-<3iZ@{TA0F<|f1XVBm7i4{p06&7VUY%a#`ck*E~Nf~Py5twAo&3m6qDQ=Knco|gZo$P_6ASrfhhFp|AoH4 zLCa=u5G6>({6AM9XaxWX9wI^gwgkx>iocx^-3Ea2pFz!9gK7@{Ox?vH6;ZM6|9@@6 z>XV7Ny#<@Qn~go&|Bd8rsxbinr-Q(NI1!t-1!W!)ft-&1yndlz2LQz#Awi;pGLG12 z|MR{7b$UX+Jq?0}fMEMq4gpaZIPD0^@56nw4B~(koe)6e$8i58`yXrJ|Hyti|05&( zcjQ6GR8V3bf8o^=1W=X-!oQS)=iA~rMuMXD{FerL(*8@Y_yRzBCrD6DzW>q~et>`J zDIfs!^^GnA{zK!ujr2GX075xMf*MHtS3?fM`&Y990)Xt^=qAu#I{K9MP1A5n1=X4H z7eLSa&xNC%Q9%V{|Al4GaQ|!g|KsZUpW)l){7wIwgUTg9ZNmCL9O;d!f1Zy^)lttY-EmuCD*Ls0=TtpgKnWo-FO+&mW7kxx<=g>fwml$x0zy4h1{{yI$%}4+M diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 42defcc..37aef8d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 65dcd68..aeb74cb 100755 --- a/gradlew +++ b/gradlew @@ -85,9 +85,6 @@ done APP_BASE_NAME=${0##*/} APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -144,7 +141,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -152,7 +149,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -197,6 +194,10 @@ if "$cygwin" || "$msys" ; then done fi + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + # Collect all arguments for the java command; # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # shell script including quotes and variable substitutions, so put them in diff --git a/properties/mobibot.properties b/properties/mobibot.properties index 0f97f3c..fa8ce50 100644 --- a/properties/mobibot.properties +++ b/properties/mobibot.properties @@ -25,28 +25,13 @@ tell-max-days=5 tell-max-size=50 #disabled-commands=die, ignore -disabled-modules=twitter +disabled-modules=mastodon # # API Token for: https://pinboard.in/settings/password # #pinboard-api-token=user\:TOKEN -# -# Configure app at: https://developer.twitter.com/ -# and then: java -cp mobibot.jar net.thauvin.erik.mobibot.TwitterOAuth -# -#twitter-consumerKey= -#twitter-consumerSecret= -#twitter-token= -#twitter-tokenSecret= - -# Twitter handle to receive channel join/leave notifications -#twitter-handle= - -# Automatically post links to Mastodon -#twitter-auto-post=true - # # Create a Mastodon application access token at: https//SERVER_INSTANCE/settings/applications # Make sure the 'write:statuses' scope is enabled. diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt index 6766f62..98ef74a 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt @@ -59,6 +59,12 @@ object Constants { */ const val CLI_CMD = "java -jar ${ReleaseInfo.PROJECT}.jar" + /** + * User-Agent + */ + const val USER_AGENT = + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36" + /** * The help command. */ diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt b/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt index f56af2e..d82f011 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt @@ -74,7 +74,7 @@ class FeedReader(private val url: String, val event: GenericMessageEvent) : Runn fun readFeed(url: String, maxItems: Int = 5): List { val messages = mutableListOf() val input = SyndFeedInput() - XmlReader(URL(url)).use { reader -> + XmlReader(URL(url).openStream()).use { reader -> val feed = input.build(reader) val items = feed.entries if (items.isEmpty()) { diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt index 2dff959..dabb7c8 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt @@ -78,7 +78,6 @@ import net.thauvin.erik.mobibot.modules.Mastodon import net.thauvin.erik.mobibot.modules.Ping import net.thauvin.erik.mobibot.modules.RockPaperScissors import net.thauvin.erik.mobibot.modules.StockQuote -import net.thauvin.erik.mobibot.modules.Twitter import net.thauvin.erik.mobibot.modules.War import net.thauvin.erik.mobibot.modules.Weather2 import net.thauvin.erik.mobibot.modules.WolframAlpha @@ -438,7 +437,7 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro addons.add(View()) // Load social modules - LinksManager.socialManager.add(addons, Twitter(), Mastodon()) + LinksManager.socialManager.add(addons, Mastodon()) // Load the modules addons.add(Calc()) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/TwitterOAuth.kt b/src/main/kotlin/net/thauvin/erik/mobibot/TwitterOAuth.kt deleted file mode 100644 index ab078db..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/TwitterOAuth.kt +++ /dev/null @@ -1,118 +0,0 @@ -/* - * TwitterOAuth.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot - -import twitter4j.AccessToken -import twitter4j.OAuthAuthorization -import twitter4j.TwitterException -import java.io.BufferedReader -import java.io.IOException -import java.io.InputStreamReader -import kotlin.system.exitProcess - - -/** - * The `TwitterOAuth` class. - * - * Go to [https://developer.twitter.com/en/apps](https://developer.twitter.com/en/apps) to register your bot. - * - * Then execute: - * - * `java -cp mobibot.jar net.thauvin.erik.mobibot.TwitterOAuth ` - * - * and follow the prompts/instructions. - * - * @author [Erik C. Thauvin](https://erik.thauvin.net) - * @author [Yusuke Yamamoto](https://github.com/Twitter4J/Twitter4J/blob/main/twitter4j-examples/src/main/java/examples/oauth/GetAccessToken.java) - */ -object TwitterOAuth { - /** - * Twitter OAuth Client Registration. - * - * @param args The consumerKey and consumerSecret should be passed as arguments. - */ - @JvmStatic - fun main(args: Array) { - if (args.size == 2) { - try { - val oAuthAuthorization = OAuthAuthorization.getInstance(args[0], args[1]) - val requestToken = oAuthAuthorization.oAuthRequestToken - var accessToken: AccessToken? = null - val br = BufferedReader(InputStreamReader(System.`in`)) - while (null == accessToken) { - print( - """ - Open the following URL and grant access to your account: - - ${requestToken.authorizationURL} - - Enter the PIN (if available) or just hit enter. [PIN]: """.trimIndent() - ) - val pin = br.readLine() - try { - accessToken = if (!pin.isNullOrEmpty()) { - oAuthAuthorization.getOAuthAccessToken(requestToken, pin) - } else { - oAuthAuthorization.getOAuthAccessToken(requestToken) - } - } catch (te: TwitterException) { - if (401 == te.statusCode) { - println("Unable to get the access token.") - } else { - te.printStackTrace() - } - } - } - println( - """ - Please add the following to the bot's property file: - - twitter-consumerKey=${args[0]} - twitter-consumerSecret=${args[1]} - twitter-token=${accessToken.token} - twitter-tokenSecret=${accessToken.tokenSecret} - """.trimIndent() - ) - } catch (te: TwitterException) { - te.printStackTrace() - println("Failed to get accessToken: " + te.message) - exitProcess(-1) - } catch (ioe: IOException) { - ioe.printStackTrace() - println("Failed to read the system input.") - exitProcess(-1) - } - } else { - println("Usage: ${TwitterOAuth::class.java.name} ") - } - exitProcess(0) - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt index 8847bef..3647b31 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt @@ -31,6 +31,7 @@ package net.thauvin.erik.mobibot.modules +import net.thauvin.erik.mobibot.Constants import net.thauvin.erik.mobibot.Utils import net.thauvin.erik.mobibot.Utils.sendMessage import org.apache.commons.text.WordUtils @@ -106,6 +107,7 @@ class ChatGpt : AbstractModule() { .uri(URI.create(API_URL)) .header("Content-Type", "application/json") .header("Authorization", "Bearer $apiKey") + .header("User-Agent", Constants.USER_AGENT) .POST( HttpRequest.BodyPublishers.ofString( """{ @@ -136,8 +138,10 @@ class ChatGpt : AbstractModule() { } } else { if (response.statusCode() == 429) { - throw ModuleException("$CHATGPT_CMD($query): Rate limit reached", - "Rate limit reached. Please try again later.") + throw ModuleException( + "$CHATGPT_CMD($query): Rate limit reached", + "Rate limit reached. Please try again later." + ) } else { throw IOException("HTTP Status Code: " + response.statusCode()) } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Twitter.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Twitter.kt deleted file mode 100644 index d4c02e1..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Twitter.kt +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Twitter.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.entries.EntryLink -import net.thauvin.erik.mobibot.social.SocialModule -import twitter4j.TwitterException - -/** - * The Twitter module. - */ -class Twitter : SocialModule() { - override val name = "Twitter" - - override val handle: String? - get() = properties[HANDLE_PROP] - - override val isAutoPost: Boolean - get() = isEnabled && properties[AUTO_POST_PROP].toBoolean() - - override val isValidProperties: Boolean - get() = !(properties[CONSUMER_KEY_PROP].isNullOrBlank() || properties[CONSUMER_SECRET_PROP].isNullOrBlank() - || properties[TOKEN_PROP].isNullOrBlank() || properties[TOKEN_SECRET_PROP].isNullOrBlank()) - - /** - * Formats the entry for posting. - */ - override fun formatEntry(entry: EntryLink): String { - return "${entry.title} ${entry.link} via ${entry.nick} on ${entry.channel}" - } - - /** - * Posts on Twitter. - */ - @Throws(ModuleException::class) - override fun post(message: String, isDm: Boolean): String { - return tweet( - consumerKey = properties[CONSUMER_KEY_PROP], - consumerSecret = properties[CONSUMER_SECRET_PROP], - token = properties[TOKEN_PROP], - tokenSecret = properties[TOKEN_SECRET_PROP], - handle = handle, - message = message, - isDm = isDm - ) - } - - companion object { - // Property keys - const val AUTO_POST_PROP = "twitter-auto-post" - const val CONSUMER_KEY_PROP = "twitter-consumerKey" - const val CONSUMER_SECRET_PROP = "twitter-consumerSecret" - const val HANDLE_PROP = "twitter-handle" - const val TOKEN_PROP = "twitter-token" - const val TOKEN_SECRET_PROP = "twitter-tokenSecret" - - // Twitter commands - private const val TWITTER_CMD = "twitter" - private const val TWEET_CMD = "tweet" - - /** - * Post on Twitter. - */ - @JvmStatic - @Throws(ModuleException::class) - fun tweet( - consumerKey: String?, - consumerSecret: String?, - token: String?, - tokenSecret: String?, - handle: String?, - message: String, - isDm: Boolean - ): String { - return try { - val twitter = twitter4j.Twitter.newBuilder() - .prettyDebugEnabled(true) - .oAuthConsumer(consumerKey, consumerSecret) - .oAuthAccessToken(token, tokenSecret) - .build() - if (!isDm) { - val status = twitter.v1().tweets().updateStatus(message) - "Your message was posted to https://twitter.com/${ - twitter.v1().users().accountSettings.screenName - }/statuses/${status.id}" - } else { - val dm = twitter.v1().directMessages().sendDirectMessage(handle, message) - dm.text - } - } catch (e: TwitterException) { - throw ModuleException("tweet($message)", "An error has occurred: ${e.message}", e) - } - } - } - - init { - commands.add(TWITTER_CMD) - commands.add(TWEET_CMD) - help.add("To $TWEET_CMD on $name:") - help.add(helpFormat("%c $TWEET_CMD ")) - properties[AUTO_POST_PROP] = "false" - initProperties(CONSUMER_KEY_PROP, CONSUMER_SECRET_PROP, HANDLE_PROP, TOKEN_PROP, TOKEN_SECRET_PROP) - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt index 8662392..ebc2aa0 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt @@ -45,7 +45,6 @@ import net.thauvin.erik.mobibot.modules.Dice import net.thauvin.erik.mobibot.modules.Joke import net.thauvin.erik.mobibot.modules.Lookup import net.thauvin.erik.mobibot.modules.RockPaperScissors -import net.thauvin.erik.mobibot.modules.Twitter import net.thauvin.erik.mobibot.modules.War import org.testng.annotations.Test import java.util.Properties @@ -62,7 +61,6 @@ class AddonsTest { // Modules addons.add(Joke()) addons.add(RockPaperScissors()) - addons.add(Twitter()) // no properties, disabled. addons.add(War()) addons.add(Dice()) addons.add(Lookup()) diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt index 0d66a0d..d30977e 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt @@ -31,14 +31,9 @@ package net.thauvin.erik.mobibot import assertk.all +import assertk.assertFailure import assertk.assertThat -import assertk.assertions.contains -import assertk.assertions.index -import assertk.assertions.isEqualTo -import assertk.assertions.isFailure -import assertk.assertions.isInstanceOf -import assertk.assertions.prop -import assertk.assertions.size +import assertk.assertions.* import com.rometools.rome.io.FeedException import net.thauvin.erik.mobibot.FeedReader.Companion.readFeed import net.thauvin.erik.mobibot.msg.Message @@ -66,13 +61,13 @@ class FeedReaderTest { assertThat(messages, "messages").size().isEqualTo(84) assertThat(messages.last(), "messages.last").prop(Message::msg).contains("techdigest.tv") - assertThat { readFeed("blah") }.isFailure().isInstanceOf(MalformedURLException::class.java) + assertFailure { readFeed("blah") }.isInstanceOf(MalformedURLException::class.java) - assertThat { readFeed("https://www.example.com") }.isFailure().isInstanceOf(FeedException::class.java) + assertFailure { readFeed("https://www.example.com") }.isInstanceOf(FeedException::class.java) - assertThat { readFeed("https://www.thauvin.net/foo") }.isFailure().isInstanceOf(IOException::class.java) + assertFailure { readFeed("https://www.thauvin.net/foo") }.isInstanceOf(IOException::class.java) - assertThat { readFeed("https://www.examplesfoo.com/") }.isFailure() + assertFailure { readFeed("https://www.examplesfoo.com/") } .isInstanceOf(UnknownHostException::class.java) } } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt index fb0402e..b3bd248 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt @@ -30,6 +30,7 @@ */ package net.thauvin.erik.mobibot.modules +import assertk.assertFailure import assertk.assertThat import assertk.assertions.isEqualTo import assertk.assertions.isFailure @@ -48,6 +49,6 @@ class CalcTest { assertThat(calculate("1 + 1"), "calculate(1+1)").isEqualTo("1+1 = ${2.bold()}") assertThat(calculate("1 -3"), "calculate(1-3)").isEqualTo("1-3 = ${(-2).bold()}") assertThat(calculate("pi+π+e+φ"), "calculate(pi+π+e+φ)").isEqualTo("pi+π+e+φ = ${"10.62".bold()}") - assertThat { calculate("one + one") }.isFailure().isInstanceOf(UnknownFunctionOrVariableException::class.java) + assertFailure { calculate("one + one") }.isInstanceOf(UnknownFunctionOrVariableException::class.java) } } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt index 5e0e1d2..e4638b9 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt @@ -30,6 +30,7 @@ */ package net.thauvin.erik.mobibot.modules +import assertk.assertFailure import assertk.assertThat import assertk.assertions.contains import assertk.assertions.hasNoCause @@ -41,8 +42,7 @@ import org.testng.annotations.Test class ChatGptTest : LocalProperties() { @Test(groups = ["modules"]) fun testApiKey() { - assertThat { ChatGpt.chat("1 gallon to liter", "", 0) } - .isFailure() + assertFailure { ChatGpt.chat("1 gallon to liter", "", 0) } .isInstanceOf(ModuleException::class.java) .hasNoCause() } @@ -57,8 +57,7 @@ class ChatGptTest : LocalProperties() { ChatGpt.chat("how do I encode a URL in java?", apiKey, 60) ).contains("URLEncoder") - assertThat { ChatGpt.chat("1 liter to gallon", apiKey, 0) } - .isFailure() + assertFailure { ChatGpt.chat("1 liter to gallon", apiKey, 0) } .isInstanceOf(ModuleException::class.java) } } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt index c2bb833..175af47 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt @@ -31,6 +31,7 @@ package net.thauvin.erik.mobibot.modules import assertk.all +import assertk.assertFailure import assertk.assertThat import assertk.assertions.contains import assertk.assertions.hasMessage @@ -59,14 +60,13 @@ class GoogleSearchTest : LocalProperties() { "searchGoogle(empty)" ).isInstanceOf(ErrorMessage::class.java) - assertThat { searchGoogle("test", "", "apiKey") }.isFailure() + assertFailure { searchGoogle("test", "", "apiKey") } .isInstanceOf(ModuleException::class.java).hasNoCause() - assertThat { searchGoogle("test", "apiKey", "") }.isFailure() + assertFailure { searchGoogle("test", "apiKey", "") } .isInstanceOf(ModuleException::class.java).hasNoCause() - assertThat { searchGoogle("test", "apiKey", "cssKey") } - .isFailure() + assertFailure { searchGoogle("test", "apiKey", "cssKey") } .isInstanceOf(ModuleException::class.java) .hasMessage("API key not valid. Please pass a valid API key.") } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt index d464f03..34f778a 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt @@ -32,7 +32,6 @@ package net.thauvin.erik.mobibot.modules import assertk.assertThat import assertk.assertions.contains -import assertk.assertions.isSuccess import net.thauvin.erik.mobibot.LocalProperties import net.thauvin.erik.mobibot.modules.Mastodon.Companion.toot import org.testng.annotations.Test @@ -42,7 +41,7 @@ class MastodonTest : LocalProperties() { @Throws(ModuleException::class) fun testToot() { val msg = "Testing Mastodon API from ${getHostName()}" - assertThat { + assertThat( toot( getProperty(Mastodon.ACCESS_TOKEN_PROP), getProperty(Mastodon.INSTANCE_PROP), @@ -50,6 +49,6 @@ class MastodonTest : LocalProperties() { msg, true ) - }.isSuccess().contains(msg) + ).contains(msg) } } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt index d35a3d3..b4a277e 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt @@ -31,6 +31,7 @@ package net.thauvin.erik.mobibot.modules import assertk.all +import assertk.assertFailure import assertk.assertThat import assertk.assertions.hasNoCause import assertk.assertions.index @@ -78,7 +79,7 @@ class StockQuoteTest : LocalProperties() { isInstanceOf(ErrorMessage::class.java) prop(Message::msg).isEqualTo(StockQuote.INVALID_SYMBOL) } - assertThat { getQuote("test", "") }.isFailure().isInstanceOf(ModuleException::class.java).hasNoCause() + assertFailure { getQuote("test", "") }.isInstanceOf(ModuleException::class.java).hasNoCause() } catch (e: ModuleException) { // Avoid displaying api keys in CI logs if ("true" == System.getenv("CI")) { diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/TwitterTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/TwitterTest.kt deleted file mode 100644 index 6e4ab27..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/TwitterTest.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * TwitterTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import assertk.assertThat -import assertk.assertions.isEqualTo -import assertk.assertions.isSuccess -import net.thauvin.erik.mobibot.LocalProperties -import net.thauvin.erik.mobibot.modules.Twitter.Companion.tweet -import org.testng.annotations.Test - -/** - * The `TwitterTest` class. - */ -class TwitterTest : LocalProperties() { - @Test(groups = ["modules", "twitter"]) - @Throws(ModuleException::class) - fun testTweet() { - val msg = "Testing Twitter API from ${getHostName()}" - assertThat { - tweet( - getProperty(Twitter.CONSUMER_KEY_PROP), - getProperty(Twitter.CONSUMER_SECRET_PROP), - getProperty(Twitter.TOKEN_PROP), - getProperty(Twitter.TOKEN_SECRET_PROP), - getProperty(Twitter.HANDLE_PROP), - msg, - true - ) - }.isSuccess().isEqualTo(msg) - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt index 4c7f7e6..ca650bb 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt @@ -31,6 +31,7 @@ package net.thauvin.erik.mobibot.modules import assertk.all +import assertk.assertFailure import assertk.assertThat import assertk.assertions.contains import assertk.assertions.endsWith @@ -116,8 +117,8 @@ class Weather2Test : LocalProperties() { } query = "test" - assertThat { getWeather(query, "") }.isFailure().isInstanceOf(ModuleException::class.java).hasNoCause() - assertThat { getWeather(query, null) }.isFailure().isInstanceOf(ModuleException::class.java).hasNoCause() + assertFailure { getWeather(query, "") }.isInstanceOf(ModuleException::class.java).hasNoCause() + assertFailure { getWeather(query, null) }.isInstanceOf(ModuleException::class.java).hasNoCause() messages = getWeather("", "apikey") assertThat(messages, "getWeather(empty)").index(0).prop(Message::isError).isTrue() diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt index 4aaf620..ae1722d 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt @@ -31,10 +31,10 @@ package net.thauvin.erik.mobibot.modules +import assertk.assertFailure import assertk.assertThat import assertk.assertions.contains import assertk.assertions.hasMessage -import assertk.assertions.isFailure import assertk.assertions.isInstanceOf import net.thauvin.erik.mobibot.ExceptionSanitizer.sanitize import net.thauvin.erik.mobibot.LocalProperties @@ -44,13 +44,11 @@ import org.testng.annotations.Test class WolframAlphaTest : LocalProperties() { @Test(groups = ["modules"]) fun testAppId() { - assertThat { queryWolfram("1 gallon to liter", appId = "DEMO") } - .isFailure() + assertFailure { queryWolfram("1 gallon to liter", appId = "DEMO") } .isInstanceOf(ModuleException::class.java) .hasMessage("Error 1: Invalid appid") - assertThat { queryWolfram("1 gallon to liter", appId = "") } - .isFailure() + assertFailure { queryWolfram("1 gallon to liter", appId = "") } .isInstanceOf(ModuleException::class.java) } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt index f17ed1d..46888e3 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt @@ -30,6 +30,7 @@ */ package net.thauvin.erik.mobibot.modules +import assertk.assertFailure import assertk.assertThat import assertk.assertions.endsWith import assertk.assertions.isSuccess @@ -65,7 +66,7 @@ class WordTimeTest { @Test(groups = ["modules"]) fun testZones() { COUNTRIES_MAP.filter { it.value != BEATS_KEYWORD }.forEach { - assertThat { ZoneId.of(it.value) }.isSuccess() + assertThat(ZoneId.of(it.value)) } } } diff --git a/version.properties b/version.properties index 693db4f..27ca594 100644 --- a/version.properties +++ b/version.properties @@ -1,9 +1,9 @@ #Generated by the Semver Plugin for Gradle -#Mon Jan 30 22:08:48 PST 2023 -version.buildmeta=986 +#Sat May 20 23:54:50 PDT 2023 +version.buildmeta=1077 version.major=0 version.minor=8 version.patch=0 version.prerelease=rc version.project=mobibot -version.semver=0.8.0-rc+986 +version.semver=0.8.0-rc+1077 diff --git a/website/index.html b/website/index.html index 97e337d..1ffaad2 100644 --- a/website/index.html +++ b/website/index.html @@ -46,7 +46,6 @@
  10. Pinboard Poster
  11. PircBotX
  12. Rome
  13. -
  14. Twitter4J
  15. UrlEncoder
  16. mobibot was written by From e57f80f9d9152d49853b754adb4b3f4b87e394a6 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 21 May 2023 00:16:46 -0700 Subject: [PATCH 714/844] Moved to JDK 17 --- .circleci/config.yml | 12 ++++++------ .github/workflows/gradle.yml | 4 ++-- .idea/compiler.xml | 2 +- .idea/misc.xml | 2 +- README.md | 3 ++- build.gradle | 6 +++--- version.properties | 6 +++--- 7 files changed, 18 insertions(+), 17 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index b76d7e8..67e6618 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -31,19 +31,19 @@ defaults_gradle: &defaults_gradle path: build/reports/ jobs: - build_gradle_jdk18: + build_gradle_jdk17: <<: *defaults docker: - - image: cimg/openjdk:18.0 + - image: cimg/openjdk:17.0 <<: *defaults_gradle - build_gradle_jdk11: + build_gradle_jdk20: <<: *defaults docker: - - image: cimg/openjdk:11.0 + - image: cimg/openjdk:20.0 <<: *defaults_gradle @@ -51,5 +51,5 @@ workflows: version: 2 gradle: jobs: - - build_gradle_jdk11 - - build_gradle_jdk18 + - build_gradle_jdk17 + - build_gradle_jdk20 diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 0034945..c917819 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -8,11 +8,11 @@ jobs: env: GRADLE_OPTS: "-Dorg.gradle.jvmargs=-XX:MaxMetaspaceSize=512m" - SONAR_JDK: "11" + SONAR_JDK: "17" strategy: matrix: - java-version: [ 11, 18 ] + java-version: [ 17, 20 ] steps: - uses: actions/checkout@v3 diff --git a/.idea/compiler.xml b/.idea/compiler.xml index fb7f4a8..b589d56 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 323152a..1bcb8e7 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -7,5 +7,5 @@ - + \ No newline at end of file diff --git a/README.md b/README.md index 8105ed3..1c4de30 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ # mobibot [![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) -[![Kotlin](https://img.shields.io/badge/kotlin-1.8.10-7f52ff.svg)](https://kotlinlang.org)[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ethauvin_mobibot&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=ethauvin_mobibot) +[![Kotlin](https://img.shields.io/badge/kotlin-1.8.21-7f52ff.svg)](https://kotlinlang.org) +[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ethauvin_mobibot&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=ethauvin_mobibot) [![GitHub CI](https://github.com/ethauvin/mobibot/actions/workflows/gradle.yml/badge.svg)](https://github.com/ethauvin/mobibot/actions/workflows/gradle.yml) [![CircleCI](https://circleci.com/gh/ethauvin/mobibot/tree/master.svg?style=shield)](https://circleci.com/gh/ethauvin/mobibot/tree/master) diff --git a/build.gradle b/build.gradle index 6a131ab..e3d5453 100644 --- a/build.gradle +++ b/build.gradle @@ -112,13 +112,13 @@ tasks.withType(Test).configureEach { } java { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } kotlin { jvmToolchain { - languageVersion.set(JavaLanguageVersion.of(11)) + languageVersion.set(JavaLanguageVersion.of(17)) } } diff --git a/version.properties b/version.properties index 27ca594..b4770f6 100644 --- a/version.properties +++ b/version.properties @@ -1,9 +1,9 @@ #Generated by the Semver Plugin for Gradle -#Sat May 20 23:54:50 PDT 2023 -version.buildmeta=1077 +#Sun May 21 00:12:53 PDT 2023 +version.buildmeta=1078 version.major=0 version.minor=8 version.patch=0 version.prerelease=rc version.project=mobibot -version.semver=0.8.0-rc+1077 +version.semver=0.8.0-rc+1078 From 37b4eb4343bcb3f6d97842df499544191c882856 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 21 May 2023 00:56:47 -0700 Subject: [PATCH 715/844] Added default max token for ChatGPT --- .circleci/config.yml | 6 +++--- build.gradle | 17 ++++++++++++----- .../net/thauvin/erik/mobibot/modules/ChatGpt.kt | 3 ++- version.properties | 6 +++--- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 67e6618..140179a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -39,11 +39,11 @@ jobs: <<: *defaults_gradle - build_gradle_jdk20: + build_gradle_jdk19: <<: *defaults docker: - - image: cimg/openjdk:20.0 + - image: cimg/openjdk:19.0 <<: *defaults_gradle @@ -52,4 +52,4 @@ workflows: gradle: jobs: - build_gradle_jdk17 - - build_gradle_jdk20 + - build_gradle_jdk19 diff --git a/build.gradle b/build.gradle index e3d5453..31ec925 100644 --- a/build.gradle +++ b/build.gradle @@ -193,19 +193,26 @@ incrementBuildMeta { } } +koverReport { + defaults { + xml { + onCheck = true + } + html { + onCheck = true + } + } +} + sonarqube { properties { property('sonar.organization', 'ethauvin-github') property('sonar.projectKey', 'ethauvin_mobibot') property('sonar.host.url', 'https://sonarcloud.io') - property('sonar.coverage.jacoco.xmlReportPaths', "${project.buildDir}/reports/kover/xml/report.xml") + property('sonar.coverage.jacoco.xmlReportPaths', "${project.buildDir}/reports/kover/report.xml") } } -tasks.sonar { - dependsOn 'koverReport' -} - tasks.register('copyToDeploy', Copy) { from('properties', jar) into deployDir diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt index 3647b31..c1f660e 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt @@ -55,7 +55,8 @@ class ChatGpt : AbstractModule() { override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { if (args.isNotBlank()) { try { - val answer = chat(args.trim(), properties[API_KEY_PROP], properties[MAX_TOKENS_PROP]!!.toInt()) + val answer = chat(args.trim(), properties[API_KEY_PROP], + properties.getOrDefault(MAX_TOKENS_PROP, "1024").toInt()) if (answer.isNotBlank()) { event.sendMessage(WordUtils.wrap(answer, 400)) } else { diff --git a/version.properties b/version.properties index b4770f6..654c604 100644 --- a/version.properties +++ b/version.properties @@ -1,9 +1,9 @@ #Generated by the Semver Plugin for Gradle -#Sun May 21 00:12:53 PDT 2023 -version.buildmeta=1078 +#Sun May 21 00:52:16 PDT 2023 +version.buildmeta=1085 version.major=0 version.minor=8 version.patch=0 version.prerelease=rc version.project=mobibot -version.semver=0.8.0-rc+1078 +version.semver=0.8.0-rc+1085 From e94b1aa97d74a60a8448ab7d5aa5764af9795ccf Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 21 May 2023 01:08:05 -0700 Subject: [PATCH 716/844] Potential fix for CircleCI --- build.gradle | 8 -------- 1 file changed, 8 deletions(-) diff --git a/build.gradle b/build.gradle index 31ec925..e6ae710 100644 --- a/build.gradle +++ b/build.gradle @@ -158,14 +158,6 @@ detekt { baseline = file("${projectDir}/config/detekt/baseline.xml") } -tasks.withType(Detekt).configureEach { - jvmTarget = java.targetCompatibility.toString() -} - -tasks.withType(DetektCreateBaselineTask).configureEach { - jvmTarget = java.targetCompatibility.toString() -} - jar { manifest.attributes('Main-Class': mainClassName, 'Class-Path': '. ./lib/' + configurations.runtimeClasspath.collect { it.getName() }.join(' ./lib/')) From 1825b13a23851639fe006cfc71c43d555099bb94 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 21 May 2023 01:13:17 -0700 Subject: [PATCH 717/844] Disabled JDK 19 from CircleCI --- .circleci/config.yml | 1 - build.gradle | 8 ++++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 140179a..1868b37 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -52,4 +52,3 @@ workflows: gradle: jobs: - build_gradle_jdk17 - - build_gradle_jdk19 diff --git a/build.gradle b/build.gradle index e6ae710..31ec925 100644 --- a/build.gradle +++ b/build.gradle @@ -158,6 +158,14 @@ detekt { baseline = file("${projectDir}/config/detekt/baseline.xml") } +tasks.withType(Detekt).configureEach { + jvmTarget = java.targetCompatibility.toString() +} + +tasks.withType(DetektCreateBaselineTask).configureEach { + jvmTarget = java.targetCompatibility.toString() +} + jar { manifest.attributes('Main-Class': mainClassName, 'Class-Path': '. ./lib/' + configurations.runtimeClasspath.collect { it.getName() }.join(' ./lib/')) From 945c763768dc1251e1d1d0ba7944e6e88264b706 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 21 May 2023 02:03:31 -0700 Subject: [PATCH 718/844] Moved to JDK 17 for GitLab and BitBucket --- .gitlab-ci.yml | 2 +- bitbucket-pipelines.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 490f7b8..48a3396 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,4 +1,4 @@ -image: gradle:7-jdk18 +image: gradle:8-jdk17 variables: GRADLE_OPTS: "-Dorg.gradle.daemon=false" diff --git a/bitbucket-pipelines.yml b/bitbucket-pipelines.yml index a9514a0..623b3c3 100644 --- a/bitbucket-pipelines.yml +++ b/bitbucket-pipelines.yml @@ -1,4 +1,4 @@ -image: maven:3-openjdk-18 +image: maven:3-eclipse-temurin-17 pipelines: default: From 66b8adb743e361eb5e848b63aaded63fab30211e Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Tue, 23 May 2023 08:31:51 -0700 Subject: [PATCH 719/844] Upgraded to PircBotX 2.3.1 --- build.gradle | 2 +- version.properties | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index 31ec925..d35a393 100644 --- a/build.gradle +++ b/build.gradle @@ -48,7 +48,7 @@ dependencies { compileOnly(semverProcessor) // PircBotX - implementation 'com.github.pircbotx:pircbotx:master-SNAPSHOT' + implementation 'com.github.pircbotx:pircbotx:2.3.1' // implementation fileTree(dir: 'lib', include: '*.jar') // Commons (mostly for PircBotX) diff --git a/version.properties b/version.properties index 654c604..4ce7fe9 100644 --- a/version.properties +++ b/version.properties @@ -1,9 +1,9 @@ #Generated by the Semver Plugin for Gradle -#Sun May 21 00:52:16 PDT 2023 -version.buildmeta=1085 +#Tue May 23 08:26:47 PDT 2023 +version.buildmeta=1087 version.major=0 version.minor=8 version.patch=0 version.prerelease=rc version.project=mobibot -version.semver=0.8.0-rc+1085 +version.semver=0.8.0-rc+1087 From d8291e21562c6010937adab5991dff219bd6a299 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sat, 17 Jun 2023 21:30:55 -0700 Subject: [PATCH 720/844] Added all keyword to seen command --- .idea/kotlinc.xml | 2 +- build.gradle | 16 ++++++------ config/detekt/baseline.xml | 2 ++ .../erik/mobibot/commands/seen/Seen.kt | 26 ++++++++++++++++++- .../erik/mobibot/entries/EntryComment.kt | 2 +- .../thauvin/erik/mobibot/entries/EntryLink.kt | 2 +- version.properties | 6 ++--- 7 files changed, 41 insertions(+), 15 deletions(-) diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index 217e5c5..9a55c2d 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/build.gradle b/build.gradle index d35a393..ff50536 100644 --- a/build.gradle +++ b/build.gradle @@ -3,15 +3,15 @@ import io.gitlab.arturbosch.detekt.DetektCreateBaselineTask plugins { id 'application' - id 'com.github.ben-manes.versions' version '0.46.0' + id 'com.github.ben-manes.versions' version '0.47.0' id 'idea' - id 'io.gitlab.arturbosch.detekt' version '1.22.0' + id 'io.gitlab.arturbosch.detekt' version '1.23.0' id 'java' id 'net.thauvin.erik.gradle.semver' version '1.0.4' - id 'org.jetbrains.kotlin.jvm' version '1.8.21' - id 'org.jetbrains.kotlin.kapt' version '1.8.21' - id 'org.jetbrains.kotlinx.kover' version '0.7.0' - id 'org.sonarqube' version '4.0.0.2929' + id 'org.jetbrains.kotlin.jvm' version '1.8.22' + id 'org.jetbrains.kotlin.kapt' version '1.8.22' + id 'org.jetbrains.kotlinx.kover' version '0.7.1' + id 'org.sonarqube' version '4.2.1.3168' id 'pmd' } @@ -59,11 +59,11 @@ dependencies { // Google implementation 'com.google.code.gson:gson:2.10.1' - implementation 'com.google.guava:guava:31.1-jre' + implementation 'com.google.guava:guava:32.0.1-jre' // Kotlin implementation platform('org.jetbrains.kotlin:kotlin-bom') - implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8' + implementation 'org.jetbrains.kotlin:kotlin-stdlib' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1' implementation 'org.jetbrains.kotlinx:kotlinx-cli:0.3.5' diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml index db7e772..356067c 100644 --- a/config/detekt/baseline.xml +++ b/config/detekt/baseline.xml @@ -27,6 +27,7 @@ MagicNumber:Mastodon.kt$Mastodon.Companion$200 MagicNumber:Mobibot.kt$Mobibot$8 MagicNumber:Modules.kt$Modules$7 + MagicNumber:Seen.kt$Seen$8 MagicNumber:SocialManager.kt$SocialManager$1000L MagicNumber:SocialManager.kt$SocialManager$60L MagicNumber:StockQuote.kt$StockQuote.Companion$10 @@ -69,6 +70,7 @@ ReturnCount:Addons.kt$Addons$fun exec(channel: String, cmd: String, args: String, event: GenericMessageEvent): Boolean ReturnCount:Addons.kt$Addons$fun help(channel: String, topic: String, event: GenericMessageEvent): Boolean ReturnCount:ExceptionSanitizer.kt$ExceptionSanitizer$fun ModuleException.sanitize(vararg sanitize: String): ModuleException + ReturnCount:Seen.kt$Seen$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) SwallowedException:GoogleSearchTest.kt$GoogleSearchTest$e: ModuleException SwallowedException:StockQuoteTest.kt$StockQuoteTest$e: ModuleException SwallowedException:WolframAlphaTest.kt$WolframAlphaTest$e: ModuleException diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt index 4a45598..fca143a 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt @@ -32,10 +32,14 @@ package net.thauvin.erik.mobibot.commands.seen import com.google.common.collect.ImmutableSortedSet +import net.thauvin.erik.mobibot.Utils +import net.thauvin.erik.mobibot.Utils.bold import net.thauvin.erik.mobibot.Utils.bot import net.thauvin.erik.mobibot.Utils.helpFormat +import net.thauvin.erik.mobibot.Utils.isChannelOp import net.thauvin.erik.mobibot.Utils.loadSerialData import net.thauvin.erik.mobibot.Utils.saveSerialData +import net.thauvin.erik.mobibot.Utils.sendList import net.thauvin.erik.mobibot.Utils.sendMessage import net.thauvin.erik.mobibot.commands.AbstractCommand import net.thauvin.erik.mobibot.commands.Info.Companion.toUptime @@ -43,15 +47,19 @@ import org.pircbotx.User import org.pircbotx.hooks.types.GenericMessageEvent import org.slf4j.Logger import org.slf4j.LoggerFactory -import java.util.TreeMap +import java.util.* class Seen(private val serialObject: String) : AbstractCommand() { private val logger: Logger = LoggerFactory.getLogger(Seen::class.java) + private val allKeyword = "all" val seenNicks = TreeMap(NickComparator()) override val name = "seen" override val help = listOf("To view when a nickname was last seen:", helpFormat("%c $name ")) + private val helpOp = help.plus( + arrayOf("To view all ${"seen".bold()} nicks:", helpFormat("%c $name $allKeyword")) + ) override val isOpOnly = false override val isPublic = true override val isVisible = true @@ -61,6 +69,11 @@ class Seen(private val serialObject: String) : AbstractCommand() { if (isEnabled()) { if (args.isNotBlank() && !args.contains(' ')) { val ch = event.bot().userChannelDao.getChannel(channel) + if (args.equals(allKeyword) && ch.isOp(event.user) && seenNicks.isNotEmpty()) { + event.sendMessage("The ${"seen".bold()} nicks are:") + event.sendList(seenNicks.keys.toList(), 8, separator = ", ", isIndent = true) + return + } ch.users.forEach { if (args.equals(it.nick, true)) { event.sendMessage("${it.nick} is on ${channel}.") @@ -102,6 +115,17 @@ class Seen(private val serialObject: String) : AbstractCommand() { fun count(): Int = seenNicks.size + override fun helpResponse(channel: String, topic: String, event: GenericMessageEvent): Boolean { + return if (event.isChannelOp(channel)) { + for (h in helpOp) { + event.sendMessage(Utils.helpCmdSyntax(h, event.bot().nick, true)) + } + true + } else { + super.helpResponse(channel, topic, event) + } + } + fun load() { if (isEnabled()) { @Suppress("UNCHECKED_CAST") diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryComment.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryComment.kt index bc64191..8de54e4 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryComment.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryComment.kt @@ -46,6 +46,6 @@ data class EntryComment(var comment: String, var nick: String) : Serializable { companion object { // Serial version UID - const val serialVersionUID = 1L + private const val serialVersionUID: Long = 1L } } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt index 7bf003d..fc61d18 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt @@ -208,6 +208,6 @@ class EntryLink( companion object { // Serial version UID - const val serialVersionUID = 1L + private const val serialVersionUID: Long = 1L } } diff --git a/version.properties b/version.properties index 4ce7fe9..9cd983c 100644 --- a/version.properties +++ b/version.properties @@ -1,9 +1,9 @@ #Generated by the Semver Plugin for Gradle -#Tue May 23 08:26:47 PDT 2023 -version.buildmeta=1087 +#Sat Jun 17 21:28:53 PDT 2023 +version.buildmeta=1098 version.major=0 version.minor=8 version.patch=0 version.prerelease=rc version.project=mobibot -version.semver=0.8.0-rc+1087 +version.semver=0.8.0-rc+1098 From 5834a23b7e9a7856c3c7c113a109fcc4357c0e22 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 2 Jul 2023 02:23:09 -0700 Subject: [PATCH 721/844] Updated dependencies --- .idea/misc.xml | 5 +++++ README.md | 2 +- build.gradle | 14 ++++++++------ config/detekt/baseline.xml | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 62076 -> 63375 bytes gradle/wrapper/gradle-wrapper.properties | 3 ++- gradlew | 5 ++++- .../erik/mobibot/commands/seen/Seen.kt | 4 ++-- version.properties | 6 +++--- 9 files changed, 26 insertions(+), 15 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index 1bcb8e7..f648a66 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -5,6 +5,11 @@ + diff --git a/README.md b/README.md index 1c4de30..6739889 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # mobibot [![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) -[![Kotlin](https://img.shields.io/badge/kotlin-1.8.21-7f52ff.svg)](https://kotlinlang.org) +[![Kotlin](https://img.shields.io/badge/kotlin-1.8.22-7f52ff.svg)](https://kotlinlang.org) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ethauvin_mobibot&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=ethauvin_mobibot) [![GitHub CI](https://github.com/ethauvin/mobibot/actions/workflows/gradle.yml/badge.svg)](https://github.com/ethauvin/mobibot/actions/workflows/gradle.yml) [![CircleCI](https://circleci.com/gh/ethauvin/mobibot/tree/master.svg?style=shield)](https://circleci.com/gh/ethauvin/mobibot/tree/master) diff --git a/build.gradle b/build.gradle index ff50536..a3677ef 100644 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,5 @@ +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter import io.gitlab.arturbosch.detekt.Detekt import io.gitlab.arturbosch.detekt.DetektCreateBaselineTask @@ -10,7 +12,7 @@ plugins { id 'net.thauvin.erik.gradle.semver' version '1.0.4' id 'org.jetbrains.kotlin.jvm' version '1.8.22' id 'org.jetbrains.kotlin.kapt' version '1.8.22' - id 'org.jetbrains.kotlinx.kover' version '0.7.1' + id 'org.jetbrains.kotlinx.kover' version '0.7.2' id 'org.sonarqube' version '4.2.1.3168' id 'pmd' } @@ -54,17 +56,17 @@ dependencies { // Commons (mostly for PircBotX) implementation 'org.apache.commons:commons-lang3:3.12.0' implementation 'org.apache.commons:commons-text:1.10.0' - implementation 'commons-codec:commons-codec:1.15' + implementation 'commons-codec:commons-codec:1.16.0' implementation 'commons-net:commons-net:3.9.0' // Google implementation 'com.google.code.gson:gson:2.10.1' - implementation 'com.google.guava:guava:32.0.1-jre' + implementation 'com.google.guava:guava:32.1.1-jre' // Kotlin implementation platform('org.jetbrains.kotlin:kotlin-bom') implementation 'org.jetbrains.kotlin:kotlin-stdlib' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.2' implementation 'org.jetbrains.kotlinx:kotlinx-cli:0.3.5' // Logging @@ -77,7 +79,7 @@ dependencies { implementation 'com.squareup.okhttp3:okhttp:4.11.0' implementation 'net.aksingh:owm-japis:2.5.3.0' implementation 'net.objecthunter:exp4j:0.4.8' - implementation 'org.json:json:20230227' + implementation 'org.json:json:20230618' implementation 'org.jsoup:jsoup:1.16.1' // Thauvin @@ -188,7 +190,7 @@ incrementBuildMeta { if (isCI) { println 'No increment with CI.' } else { - buildMeta = sprintf("%03d", (buildMeta as Integer) + 1) + buildMeta = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now()) } } } diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml index 356067c..0aa592e 100644 --- a/config/detekt/baseline.xml +++ b/config/detekt/baseline.xml @@ -27,7 +27,7 @@ MagicNumber:Mastodon.kt$Mastodon.Companion$200 MagicNumber:Mobibot.kt$Mobibot$8 MagicNumber:Modules.kt$Modules$7 - MagicNumber:Seen.kt$Seen$8 + MagicNumber:Seen.kt$Seen$7 MagicNumber:SocialManager.kt$SocialManager$1000L MagicNumber:SocialManager.kt$SocialManager$60L MagicNumber:StockQuote.kt$StockQuote.Companion$10 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index c1962a79e29d3e0ab67b14947c167a862655af9b..033e24c4cdf41af1ab109bc7f253b2b887023340 100644 GIT binary patch delta 16170 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 delta 14892 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 37aef8d..62f495d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index aeb74cb..fcb6fca 100755 --- a/gradlew +++ b/gradlew @@ -130,10 +130,13 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt index fca143a..c9ee0f3 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt @@ -69,9 +69,9 @@ class Seen(private val serialObject: String) : AbstractCommand() { if (isEnabled()) { if (args.isNotBlank() && !args.contains(' ')) { val ch = event.bot().userChannelDao.getChannel(channel) - if (args.equals(allKeyword) && ch.isOp(event.user) && seenNicks.isNotEmpty()) { + if (args == allKeyword && ch.isOp(event.user) && seenNicks.isNotEmpty()) { event.sendMessage("The ${"seen".bold()} nicks are:") - event.sendList(seenNicks.keys.toList(), 8, separator = ", ", isIndent = true) + event.sendList(seenNicks.keys.toList(), 7, separator = ", ", isIndent = true) return } ch.users.forEach { diff --git a/version.properties b/version.properties index 9cd983c..b464c4e 100644 --- a/version.properties +++ b/version.properties @@ -1,9 +1,9 @@ #Generated by the Semver Plugin for Gradle -#Sat Jun 17 21:28:53 PDT 2023 -version.buildmeta=1098 +#Sun Jul 02 02:19:45 PDT 2023 +version.buildmeta=20230702021945 version.major=0 version.minor=8 version.patch=0 version.prerelease=rc version.project=mobibot -version.semver=0.8.0-rc+1098 +version.semver=0.8.0-rc+20230702021945 From 2313d36584fdb363b8eeb93331cf05a60e63f12a Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Thu, 6 Jul 2023 10:23:04 -0700 Subject: [PATCH 722/844] Upgraded to Koltin 1.9.0 --- .idea/codeStyles/codeStyleConfig.xml | 3 +- .idea/kotlinc.xml | 2 +- README.md | 2 +- build.gradle | 4 +- config/detekt/baseline.xml | 26 ++++ .../net/thauvin/erik/mobibot/modules/War.java | 12 +- .../kotlin/net/thauvin/erik/mobibot/Addons.kt | 2 +- .../net/thauvin/erik/mobibot/Constants.kt | 2 +- .../net/thauvin/erik/mobibot/Mobibot.kt | 115 ++++++------------ .../net/thauvin/erik/mobibot/Pinboard.kt | 4 +- .../kotlin/net/thauvin/erik/mobibot/Utils.kt | 35 +++--- .../thauvin/erik/mobibot/commands/Ignore.kt | 14 +-- .../net/thauvin/erik/mobibot/commands/Info.kt | 10 +- .../net/thauvin/erik/mobibot/commands/Msg.kt | 4 +- .../thauvin/erik/mobibot/commands/Recap.kt | 8 +- .../thauvin/erik/mobibot/commands/Versions.kt | 8 +- .../erik/mobibot/commands/links/Comment.kt | 46 +++---- .../mobibot/commands/links/LinksManager.kt | 6 +- .../erik/mobibot/commands/links/Posting.kt | 20 +-- .../erik/mobibot/commands/links/Tags.kt | 4 +- .../erik/mobibot/commands/links/View.kt | 10 +- .../erik/mobibot/commands/seen/Seen.kt | 14 +-- .../erik/mobibot/commands/tell/Tell.kt | 44 +++---- .../erik/mobibot/commands/tell/TellMessage.kt | 24 ++-- .../thauvin/erik/mobibot/entries/Entries.kt | 8 +- .../erik/mobibot/entries/EntriesUtils.kt | 6 +- .../thauvin/erik/mobibot/entries/EntryLink.kt | 59 +++++---- .../erik/mobibot/entries/FeedsManager.kt | 48 ++++---- .../thauvin/erik/mobibot/modules/ChatGpt.kt | 40 +++--- .../erik/mobibot/modules/CryptoPrices.kt | 6 +- .../erik/mobibot/modules/CurrencyConverter.kt | 22 ++-- .../erik/mobibot/modules/GoogleSearch.kt | 30 ++--- .../thauvin/erik/mobibot/modules/Lookup.kt | 6 +- .../thauvin/erik/mobibot/modules/Mastodon.kt | 40 +++--- .../erik/mobibot/modules/ModuleException.kt | 6 +- .../net/thauvin/erik/mobibot/modules/Ping.kt | 24 ++-- .../erik/mobibot/modules/RockPaperScissors.kt | 10 +- .../erik/mobibot/modules/StockQuote.kt | 66 +++++----- .../thauvin/erik/mobibot/modules/Weather2.kt | 36 +++--- .../erik/mobibot/modules/WolframAlpha.kt | 28 ++--- .../thauvin/erik/mobibot/modules/WorldTime.kt | 4 +- .../thauvin/erik/mobibot/msg/ErrorMessage.kt | 2 +- .../net/thauvin/erik/mobibot/msg/Message.kt | 10 +- .../thauvin/erik/mobibot/msg/NoticeMessage.kt | 2 +- .../erik/mobibot/msg/PrivateMessage.kt | 3 +- .../erik/mobibot/social/SocialManager.kt | 2 +- .../erik/mobibot/social/SocialModule.kt | 4 +- .../erik/mobibot/social/SocialTimer.kt | 2 +- .../net/thauvin/erik/mobibot/AddonsTest.kt | 18 ++- .../erik/mobibot/ExceptionSanitizer.kt | 6 +- .../thauvin/erik/mobibot/FeedReaderTest.kt | 2 +- .../thauvin/erik/mobibot/LocalProperties.kt | 2 +- .../net/thauvin/erik/mobibot/PinboardTest.kt | 2 +- .../net/thauvin/erik/mobibot/UtilsTest.kt | 35 +++--- .../thauvin/erik/mobibot/commands/InfoTest.kt | 8 +- .../erik/mobibot/commands/RecapTest.kt | 6 +- .../commands/links/LinksManagerTest.kt | 4 +- .../erik/mobibot/commands/links/ViewTest.kt | 16 +-- .../erik/mobibot/commands/seen/SeenTest.kt | 9 +- .../commands/tell/TellMessagesMgrTest.kt | 8 +- .../erik/mobibot/entries/EntriesUtilsTest.kt | 20 +-- .../erik/mobibot/entries/EntryLinkTest.kt | 20 ++- .../erik/mobibot/entries/FeedMgrTest.kt | 10 +- .../thauvin/erik/mobibot/modules/CalcTest.kt | 1 - .../erik/mobibot/modules/ChatGptTest.kt | 11 +- .../mobibot/modules/CurrencyConverterTest.kt | 12 +- .../thauvin/erik/mobibot/modules/DiceTest.kt | 8 +- .../erik/mobibot/modules/GoogleSearchTest.kt | 22 ++-- .../thauvin/erik/mobibot/modules/JokeTest.kt | 7 +- .../erik/mobibot/modules/MastodonTest.kt | 14 +-- .../mobibot/modules/ModuleExceptionTest.kt | 22 ++-- .../erik/mobibot/modules/StockQuoteTest.kt | 11 +- .../erik/mobibot/modules/Weather2Test.kt | 13 +- .../erik/mobibot/modules/WolframAlphaTest.kt | 10 +- .../erik/mobibot/modules/WordTimeTest.kt | 8 +- version.properties | 6 +- 76 files changed, 549 insertions(+), 645 deletions(-) diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml index 6e6eec1..d91f848 100644 --- a/.idea/codeStyles/codeStyleConfig.xml +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -1,6 +1,5 @@ - \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index 9a55c2d..fdf8d99 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/README.md b/README.md index 6739889..df026ab 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # mobibot [![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) -[![Kotlin](https://img.shields.io/badge/kotlin-1.8.22-7f52ff.svg)](https://kotlinlang.org) +[![Kotlin](https://img.shields.io/badge/kotlin-1.9.0-7f52ff.svg)](https://kotlinlang.org) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ethauvin_mobibot&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=ethauvin_mobibot) [![GitHub CI](https://github.com/ethauvin/mobibot/actions/workflows/gradle.yml/badge.svg)](https://github.com/ethauvin/mobibot/actions/workflows/gradle.yml) [![CircleCI](https://circleci.com/gh/ethauvin/mobibot/tree/master.svg?style=shield)](https://circleci.com/gh/ethauvin/mobibot/tree/master) diff --git a/build.gradle b/build.gradle index a3677ef..fa00b54 100644 --- a/build.gradle +++ b/build.gradle @@ -10,8 +10,8 @@ plugins { id 'io.gitlab.arturbosch.detekt' version '1.23.0' id 'java' id 'net.thauvin.erik.gradle.semver' version '1.0.4' - id 'org.jetbrains.kotlin.jvm' version '1.8.22' - id 'org.jetbrains.kotlin.kapt' version '1.8.22' + id 'org.jetbrains.kotlin.jvm' version '1.9.0' + id 'org.jetbrains.kotlin.kapt' version '1.9.0' id 'org.jetbrains.kotlinx.kover' version '0.7.2' id 'org.sonarqube' version '4.2.1.3168' id 'pmd' diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml index 0aa592e..f7cc151 100644 --- a/config/detekt/baseline.xml +++ b/config/detekt/baseline.xml @@ -46,6 +46,15 @@ MagicNumber:WorldTime.kt$WorldTime.Companion$3600 MagicNumber:WorldTime.kt$WorldTime.Companion$60 MagicNumber:WorldTime.kt$WorldTime.Companion$86.4 + MaxLineLength:DiceTest.kt$DiceTest$. + MaxLineLength:Lookup.kt$Lookup$("(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)") + MaxLineLength:Mastodon.kt$Mastodon.Companion$mapOf("status" to "${handle?.prefixIfMissing('@')} $message", "visibility" to "direct") + MaxLineLength:Mobibot.kt$Mobibot$helpCmdSyntax("%c ${Constants.HELP_CMD} <command>", event.bot().nick, event is PrivateMessageEvent) + MaxLineLength:PinboardTest.kt$PinboardTest$URL("https://api.pinboard.in/v1/posts/get?auth_token=${apiToken}&tag=test&" + url.encodeUrl()).reader().body + MaxLineLength:StockQuote.kt$StockQuote.Companion$+ + MaxLineLength:Utils.kt$Utils$list.subList(i, list.size.coerceAtMost(i + maxPerLine)).joinToString(separator, truncated = "") + MaxLineLength:View.kt$View$helpCmdSyntax("%c $name ${index + 1} $query", event.bot().nick, event is PrivateMessageEvent) + MaxLineLength:Weather2.kt$Weather2.Companion$country.name.replace('_', ' ').capitalizeWords() NestedBlockDepth:Addons.kt$Addons$fun add(command: AbstractCommand): Boolean NestedBlockDepth:Addons.kt$Addons$fun add(module: AbstractModule): Boolean NestedBlockDepth:ChatGpt.kt$ChatGpt.Companion$@JvmStatic @Throws(ModuleException::class) fun chat(query: String, apiKey: String?, maxTokens: Int): String @@ -87,6 +96,23 @@ TooManyFunctions:EntryLink.kt$EntryLink : Serializable TooManyFunctions:Mobibot.kt$Mobibot : ListenerAdapter TooManyFunctions:Tell.kt$Tell : AbstractCommand + WildcardImport:AddonsTest.kt$import net.thauvin.erik.mobibot.modules.* + WildcardImport:EntryLinkTest.kt$import assertk.assertions.* + WildcardImport:FeedMgrTest.kt$import assertk.assertions.* WildcardImport:FeedReaderTest.kt$import assertk.assertions.* + WildcardImport:FeedsManager.kt$import com.rometools.rome.feed.synd.* + WildcardImport:GoogleSearchTest.kt$import assertk.assertions.* + WildcardImport:JokeTest.kt$import assertk.assertions.* + WildcardImport:Mobibot.kt$import java.io.* + WildcardImport:Mobibot.kt$import net.thauvin.erik.mobibot.commands.* + WildcardImport:Mobibot.kt$import net.thauvin.erik.mobibot.commands.links.* + WildcardImport:Mobibot.kt$import net.thauvin.erik.mobibot.modules.* + WildcardImport:Mobibot.kt$import org.pircbotx.hooks.events.* + WildcardImport:ModuleExceptionTest.kt$import assertk.assertions.* + WildcardImport:SeenTest.kt$import assertk.assertions.* + WildcardImport:StockQuoteTest.kt$import assertk.assertions.* + WildcardImport:TellMessagesMgrTest.kt$import assertk.assertions.* + WildcardImport:Utils.kt$import java.io.* + WildcardImport:Weather2Test.kt$import assertk.assertions.* diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/War.java b/src/main/java/net/thauvin/erik/mobibot/modules/War.java index d1d7882..4bbbd9b 100644 --- a/src/main/java/net/thauvin/erik/mobibot/modules/War.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/War.java @@ -72,6 +72,12 @@ public final class War extends AbstractModule { help.add(Utils.helpFormat("%c " + WAR_CMD)); } + @NotNull + @Override + public String getName() { + return "War"; + } + /** * {@inheritDoc} */ @@ -99,10 +105,4 @@ public final class War extends AbstractModule { } while (i == y); } - - @NotNull - @Override - public String getName() { - return "War"; - } } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt index 1127f02..2c5f05d 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt @@ -38,7 +38,7 @@ import org.pircbotx.hooks.events.PrivateMessageEvent import org.pircbotx.hooks.types.GenericMessageEvent import org.slf4j.Logger import org.slf4j.LoggerFactory -import java.util.Properties +import java.util.* /** * Modules and Commands addons. diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt index 98ef74a..7cf6719 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt @@ -63,7 +63,7 @@ object Constants { * User-Agent */ const val USER_AGENT = - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36" + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36" /** * The help command. diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt index dabb7c8..3342077 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt @@ -45,67 +45,24 @@ import net.thauvin.erik.mobibot.Utils.lastOrEmpty import net.thauvin.erik.mobibot.Utils.sendList import net.thauvin.erik.mobibot.Utils.sendMessage import net.thauvin.erik.mobibot.Utils.toIsoLocalDate -import net.thauvin.erik.mobibot.commands.ChannelFeed -import net.thauvin.erik.mobibot.commands.Cycle -import net.thauvin.erik.mobibot.commands.Die -import net.thauvin.erik.mobibot.commands.Ignore -import net.thauvin.erik.mobibot.commands.Info -import net.thauvin.erik.mobibot.commands.Me -import net.thauvin.erik.mobibot.commands.Modules -import net.thauvin.erik.mobibot.commands.Msg -import net.thauvin.erik.mobibot.commands.Nick -import net.thauvin.erik.mobibot.commands.Recap +import net.thauvin.erik.mobibot.commands.* import net.thauvin.erik.mobibot.commands.Recap.Companion.storeRecap -import net.thauvin.erik.mobibot.commands.Say -import net.thauvin.erik.mobibot.commands.Users -import net.thauvin.erik.mobibot.commands.Versions -import net.thauvin.erik.mobibot.commands.links.Comment -import net.thauvin.erik.mobibot.commands.links.LinksManager -import net.thauvin.erik.mobibot.commands.links.Posting -import net.thauvin.erik.mobibot.commands.links.Tags -import net.thauvin.erik.mobibot.commands.links.View +import net.thauvin.erik.mobibot.commands.links.* import net.thauvin.erik.mobibot.commands.seen.Seen import net.thauvin.erik.mobibot.commands.tell.Tell -import net.thauvin.erik.mobibot.modules.Calc -import net.thauvin.erik.mobibot.modules.ChatGpt -import net.thauvin.erik.mobibot.modules.CryptoPrices -import net.thauvin.erik.mobibot.modules.CurrencyConverter -import net.thauvin.erik.mobibot.modules.Dice -import net.thauvin.erik.mobibot.modules.GoogleSearch -import net.thauvin.erik.mobibot.modules.Joke -import net.thauvin.erik.mobibot.modules.Lookup -import net.thauvin.erik.mobibot.modules.Mastodon -import net.thauvin.erik.mobibot.modules.Ping -import net.thauvin.erik.mobibot.modules.RockPaperScissors -import net.thauvin.erik.mobibot.modules.StockQuote -import net.thauvin.erik.mobibot.modules.War -import net.thauvin.erik.mobibot.modules.Weather2 -import net.thauvin.erik.mobibot.modules.WolframAlpha -import net.thauvin.erik.mobibot.modules.WorldTime +import net.thauvin.erik.mobibot.modules.* import net.thauvin.erik.semver.Version import org.pircbotx.Configuration import org.pircbotx.PircBotX import org.pircbotx.hooks.ListenerAdapter -import org.pircbotx.hooks.events.ActionEvent -import org.pircbotx.hooks.events.DisconnectEvent -import org.pircbotx.hooks.events.JoinEvent -import org.pircbotx.hooks.events.MessageEvent -import org.pircbotx.hooks.events.NickChangeEvent -import org.pircbotx.hooks.events.PartEvent -import org.pircbotx.hooks.events.PrivateMessageEvent -import org.pircbotx.hooks.events.QuitEvent +import org.pircbotx.hooks.events.* import org.pircbotx.hooks.types.GenericMessageEvent import org.slf4j.Logger import org.slf4j.LoggerFactory -import java.io.BufferedOutputStream -import java.io.File -import java.io.FileNotFoundException -import java.io.FileOutputStream -import java.io.IOException -import java.io.PrintStream +import java.io.* import java.nio.file.Files import java.nio.file.Paths -import java.util.Properties +import java.util.* import java.util.regex.Pattern import kotlin.system.exitProcess @@ -140,9 +97,9 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro event.sendMessage("Type a URL on $channel to post it.") event.sendMessage("For more information on a specific command, type:") event.sendMessage( - helpFormat( - helpCmdSyntax("%c ${Constants.HELP_CMD} ", event.bot().nick, event is PrivateMessageEvent) - ) + helpFormat( + helpCmdSyntax("%c ${Constants.HELP_CMD} ", event.bot().nick, event is PrivateMessageEvent) + ) ) event.sendMessage("The commands are:") event.sendList(addons.names.commands, 8, isBold = true, isIndent = true) @@ -204,7 +161,7 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro with(event.getBot()) { if (user.nick == nick) { LinksManager.socialManager.notification( - "$nick has joined ${event.channel.name} on $serverHostname" + "$nick has joined ${event.channel.name} on $serverHostname" ) seen.add(userChannelDao.getChannel(channel).users) } else { @@ -252,7 +209,7 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro with(event.getBot()) { if (user.nick == nick) { LinksManager.socialManager.notification( - "$nick has left ${event.channel.name} on $serverHostname" + "$nick has left ${event.channel.name} on $serverHostname" ) seen.add(userChannelDao.getChannel(channel).users) } else { @@ -275,22 +232,22 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro // Set up the command line options val parser = ArgParser(Constants.CLI_CMD) val debug by parser.option( - ArgType.Boolean, - Constants.DEBUG_ARG, - Constants.DEBUG_ARG.substring(0, 1), - "Print debug & logging data directly to the console" + ArgType.Boolean, + Constants.DEBUG_ARG, + Constants.DEBUG_ARG.substring(0, 1), + "Print debug & logging data directly to the console" ).default(false) val property by parser.option( - ArgType.String, - Constants.PROPS_ARG, - Constants.PROPS_ARG.substring(0, 1), - "Use alternate properties file" + ArgType.String, + Constants.PROPS_ARG, + Constants.PROPS_ARG.substring(0, 1), + "Use alternate properties file" ).default("./${ReleaseInfo.PROJECT}.properties") val version by parser.option( - ArgType.Boolean, - Constants.VERSION_ARG, - Constants.VERSION_ARG.substring(0, 1), - "Print version info" + ArgType.Boolean, + Constants.VERSION_ARG, + Constants.VERSION_ARG.substring(0, 1), + "Print version info" ).default(false) // Parse the command line @@ -299,8 +256,8 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro if (version) { // Output the version println( - "${ReleaseInfo.PROJECT.capitalise()} ${ReleaseInfo.VERSION}" + - " (${ReleaseInfo.BUILDDATE.toIsoLocalDate()})" + "${ReleaseInfo.PROJECT.capitalise()} ${ReleaseInfo.VERSION}" + + " (${ReleaseInfo.BUILDDATE.toIsoLocalDate()})" ) println(ReleaseInfo.WEBSITE) } else { @@ -308,7 +265,7 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro val p = Properties() try { Files.newInputStream( - Paths.get(property) + Paths.get(property) ).use { fis -> p.load(fis) } @@ -327,11 +284,11 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro if (!debug) { try { val stdout = PrintStream( - BufferedOutputStream( - FileOutputStream( - logsDir + channel.substring(1) + '.' + Utils.today() + ".log", true - ) - ), true + BufferedOutputStream( + FileOutputStream( + logsDir + channel.substring(1) + '.' + Utils.today() + ".log", true + ) + ), true ) System.setOut(stdout) } catch (ignore: IOException) { @@ -340,9 +297,9 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro } try { val stderr = PrintStream( - BufferedOutputStream( - FileOutputStream("$logsDir$nickname.err", true) - ), true + BufferedOutputStream( + FileOutputStream("$logsDir$nickname.err", true) + ), true ) System.setErr(stderr) } catch (ignore: IOException) { @@ -367,8 +324,8 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro login = p.getProperty("login", nickname) realName = p.getProperty("realname", nickname) addServer( - ircServer, - p.getIntProperty("port", Constants.DEFAULT_PORT) + ircServer, + p.getIntProperty("port", Constants.DEFAULT_PORT) ) addAutoJoinChannel(channel) addListener(this@Mobibot) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt index b829bab..1a4260d 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt @@ -37,7 +37,7 @@ import java.time.ZoneId import java.time.ZonedDateTime import java.time.format.DateTimeFormatter import java.time.temporal.ChronoUnit -import java.util.Date +import java.util.* /** * Handles posts to pinboard.in. @@ -92,7 +92,7 @@ class Pinboard { */ private fun Date.toTimestamp(): String { return ZonedDateTime.ofInstant( - toInstant().truncatedTo(ChronoUnit.SECONDS), ZoneId.systemDefault() + toInstant().truncatedTo(ChronoUnit.SECONDS), ZoneId.systemDefault() ).format(DateTimeFormatter.ISO_INSTANT) } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt index f61c56c..0595220 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt @@ -39,11 +39,7 @@ import org.pircbotx.PircBotX import org.pircbotx.hooks.events.PrivateMessageEvent import org.pircbotx.hooks.types.GenericMessageEvent import org.slf4j.Logger -import java.io.BufferedInputStream -import java.io.BufferedOutputStream -import java.io.IOException -import java.io.ObjectInputStream -import java.io.ObjectOutputStream +import java.io.* import java.net.HttpURLConnection import java.net.URL import java.nio.file.Files @@ -51,8 +47,7 @@ import java.nio.file.Paths import java.time.LocalDateTime import java.time.ZoneId import java.time.format.DateTimeFormatter -import java.util.Date -import java.util.Properties +import java.util.* import kotlin.io.path.exists import kotlin.io.path.fileSize @@ -220,7 +215,7 @@ object Utils { if (serialFile.exists() && serialFile.fileSize() > 0) { try { ObjectInputStream( - BufferedInputStream(Files.newInputStream(serialFile)) + BufferedInputStream(Files.newInputStream(serialFile)) ).use { input -> if (logger.isDebugEnabled) logger.debug("Loading the ${description}.") return input.readObject() @@ -307,20 +302,20 @@ object Utils { @JvmStatic @JvmOverloads fun GenericMessageEvent.sendList( - list: List, - maxPerLine: Int, - separator: String = " ", - isBold: Boolean = false, - isIndent: Boolean = false + list: List, + maxPerLine: Int, + separator: String = " ", + isBold: Boolean = false, + isIndent: Boolean = false ) { var i = 0 while (i < list.size) { sendMessage( - helpFormat( - list.subList(i, list.size.coerceAtMost(i + maxPerLine)).joinToString(separator, truncated = ""), - isBold, - isIndent - ), + helpFormat( + list.subList(i, list.size.coerceAtMost(i + maxPerLine)).joinToString(separator, truncated = ""), + isBold, + isIndent + ), ) i += maxPerLine } @@ -419,8 +414,8 @@ object Utils { fun URL.reader(): UrlReaderResponse { val connection = this.openConnection() as HttpURLConnection connection.setRequestProperty( - "User-Agent", - "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/109.0" + "User-Agent", + "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/109.0" ) return if (connection.responseCode.isHttpSuccess()) { UrlReaderResponse(connection.responseCode, connection.inputStream.bufferedReader().use { it.readText() }) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt index a696fa8..88109e8 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt @@ -50,15 +50,15 @@ class Ignore : AbstractCommand() { override val name = IGNORE_CMD override val help = listOf( - "To ignore a link posted to the channel:", - helpFormat("https://www.foo.bar %n"), - "To check your ignore status:", - helpFormat("%c $name"), - "To toggle your ignore status:", - helpFormat("%c $name $me") + "To ignore a link posted to the channel:", + helpFormat("https://www.foo.bar %n"), + "To check your ignore status:", + helpFormat("%c $name"), + "To toggle your ignore status:", + helpFormat("%c $name $me") ) private val helpOp = help.plus( - arrayOf("To add/remove nicks from the ignored list:", helpFormat("%c $name [ ...]")) + arrayOf("To add/remove nicks from the ignored list:", helpFormat("%c $name [ ...]")) ) override val isOpOnly = false diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Info.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Info.kt index ed0b6ef..7eb3bdb 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Info.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Info.kt @@ -48,8 +48,8 @@ import kotlin.time.toDuration class Info(private val tell: Tell, private val seen: Seen) : AbstractCommand() { private val allVersions = listOf( - "${ReleaseInfo.PROJECT.capitalise()} ${ReleaseInfo.VERSION} (${ReleaseInfo.WEBSITE.green()})", - "Written by ${ReleaseInfo.AUTHOR} (${ReleaseInfo.AUTHOR_URL.green()})" + "${ReleaseInfo.PROJECT.capitalise()} ${ReleaseInfo.VERSION} (${ReleaseInfo.WEBSITE.green()})", + "Written by ${ReleaseInfo.AUTHOR} (${ReleaseInfo.AUTHOR_URL.green()})" ) override val name = "info" override val help = listOf("To view information about the bot:", helpFormat("%c $name")) @@ -104,9 +104,9 @@ class Info(private val tell: Tell, private val seen: Seen) : AbstractCommand() { event.sendList(allVersions, 1) val info = StringBuilder() info.append("Uptime: ") - .append(ManagementFactory.getRuntimeMXBean().uptime.toUptime()) - .append(" [Entries: ") - .append(LinksManager.entries.links.size) + .append(ManagementFactory.getRuntimeMXBean().uptime.toUptime()) + .append(" [Entries: ") + .append(LinksManager.entries.links.size) if (seen.isEnabled()) { info.append(", Seen: ").append(seen.count()) } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Msg.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Msg.kt index 20a6635..48ff38f 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Msg.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Msg.kt @@ -39,8 +39,8 @@ import org.pircbotx.hooks.types.GenericMessageEvent class Msg : AbstractCommand() { override val name = "msg" override val help = listOf( - "To have the bot send a private message to someone:", - helpFormat("%c $name ") + "To have the bot send a private message to someone:", + helpFormat("%c $name ") ) override val isOpOnly = true override val isPublic = false diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Recap.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Recap.kt index 77154c7..66e721e 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Recap.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Recap.kt @@ -41,8 +41,8 @@ import java.time.LocalDateTime class Recap : AbstractCommand() { override val name = "recap" override val help = listOf( - "To list the last 10 public channel messages:", - helpFormat("%c $name") + "To list the last 10 public channel messages:", + helpFormat("%c $name") ) override val isOpOnly = false override val isPublic = true @@ -60,8 +60,8 @@ class Recap : AbstractCommand() { @JvmStatic fun storeRecap(sender: String, message: String, isAction: Boolean) { recaps.add( - LocalDateTime.now(Clock.systemUTC()).toUtcDateTime() - + " - $sender" + (if (isAction) " " else ": ") + message + LocalDateTime.now(Clock.systemUTC()).toUtcDateTime() + + " - $sender" + (if (isAction) " " else ": ") + message ) if (recaps.size > MAX_RECAPS) { recaps.removeFirst() diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Versions.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Versions.kt index 896c569..f920891 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Versions.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Versions.kt @@ -40,10 +40,10 @@ import org.pircbotx.hooks.types.GenericMessageEvent class Versions : AbstractCommand() { private val allVersions = listOf( - "Version: ${ReleaseInfo.VERSION} (${ReleaseInfo.BUILDDATE.toIsoLocalDate()})", - "${System.getProperty("os.name")} ${System.getProperty("os.version")} (${System.getProperty("os.arch")})" + - ", JVM ${System.getProperty("java.runtime.version")}", - "Kotlin ${KotlinVersion.CURRENT}, PircBotX ${PircBotX.VERSION}" + "Version: ${ReleaseInfo.VERSION} (${ReleaseInfo.BUILDDATE.toIsoLocalDate()})", + "${System.getProperty("os.name")} ${System.getProperty("os.version")} (${System.getProperty("os.arch")})" + + ", JVM ${System.getProperty("java.runtime.version")}", + "Kotlin ${KotlinVersion.CURRENT}, PircBotX ${PircBotX.VERSION}" ) override val name = "versions" override val help = listOf("To view the versions data (bot, platform, java, etc.):", helpFormat("%c $name")) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Comment.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Comment.kt index 1443d44..9fe250d 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Comment.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Comment.kt @@ -45,13 +45,13 @@ import org.pircbotx.hooks.types.GenericMessageEvent class Comment : AbstractCommand() { override val name = COMMAND override val help = listOf( - "To add a comment:", - helpFormat("${Constants.LINK_CMD}1:This is a comment"), - "I will reply with a label, for example: ${Constants.LINK_CMD.bold()}1.1", - "To edit a comment, use its label: ", - helpFormat("${Constants.LINK_CMD}1.1:This is an edited comment"), - "To delete a comment, use its label and a minus sign: ", - helpFormat("${Constants.LINK_CMD}1.1:-") + "To add a comment:", + helpFormat("${Constants.LINK_CMD}1:This is a comment"), + "I will reply with a label, for example: ${Constants.LINK_CMD.bold()}1.1", + "To edit a comment, use its label: ", + helpFormat("${Constants.LINK_CMD}1.1:This is an edited comment"), + "To delete a comment, use its label and a minus sign: ", + helpFormat("${Constants.LINK_CMD}1.1:-") ) override val isOpOnly = false override val isPublic = true @@ -100,12 +100,12 @@ class Comment : AbstractCommand() { } private fun changeAuthor( - channel: String, - cmd: String, - entry: EntryLink, - entryIndex: Int, - commentIndex: Int, - event: GenericMessageEvent + channel: String, + cmd: String, + entry: EntryLink, + entryIndex: Int, + commentIndex: Int, + event: GenericMessageEvent ) { if (event.isChannelOp(channel) && cmd.length > 1) { val comment = entry.getComment(commentIndex) @@ -118,11 +118,11 @@ class Comment : AbstractCommand() { } private fun deleteComment( - channel: String, - entry: EntryLink, - entryIndex: Int, - commentIndex: Int, - event: GenericMessageEvent + channel: String, + entry: EntryLink, + entryIndex: Int, + commentIndex: Int, + event: GenericMessageEvent ) { if (event.isChannelOp(channel) || event.user.nick == entry.getComment(commentIndex).nick) { entry.deleteComment(commentIndex) @@ -134,11 +134,11 @@ class Comment : AbstractCommand() { } private fun setComment( - cmd: String, - entry: EntryLink, - entryIndex: Int, - commentIndex: Int, - event: GenericMessageEvent + cmd: String, + entry: EntryLink, + entryIndex: Int, + commentIndex: Int, + event: GenericMessageEvent ) { entry.setComment(commentIndex, cmd, event.user.nick) event.sendMessage(printComment(entryIndex, commentIndex, entry.getComment(commentIndex))) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManager.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManager.kt index fba6b99..fb1a634 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManager.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManager.kt @@ -161,8 +161,8 @@ class LinksManager : AbstractCommand() { internal fun fetchTitle(link: String): String { try { val html = Jsoup.connect(link) - .userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0") - .get() + .userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0") + .get() val title = html.title() if (title.isNotBlank()) { return title @@ -178,7 +178,7 @@ class LinksManager : AbstractCommand() { return try { val match = entries.links.single { it.link == link } event.sendMessage( - "Duplicate".bold() + " >> " + printLink(entries.links.indexOf(match), match) + "Duplicate".bold() + " >> " + printLink(entries.links.indexOf(match), match) ) true } catch (ignore: NoSuchElementException) { diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Posting.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Posting.kt index ff4278d..e04cd15 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Posting.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Posting.kt @@ -47,16 +47,16 @@ import org.pircbotx.hooks.types.GenericMessageEvent class Posting : AbstractCommand() { override val name = "posting" override val help = listOf( - "Post a URL, by saying it on a line on its own:", - helpFormat(" [] ${Tags.COMMAND}: <+tag> [...]]"), - "I will reply with a label, for example: ${Constants.LINK_CMD.bold()}1", - "To add a title, use its label and a pipe:", - helpFormat("${Constants.LINK_CMD}1:|This is the title"), - "To add a comment:", - helpFormat("${Constants.LINK_CMD}1:This is a comment"), - "I will reply with a label, for example: ${Constants.LINK_CMD.bold()}1.1", - "To edit a comment, see: ", - helpFormat("%c ${Constants.HELP_CMD} ${Comment.COMMAND}") + "Post a URL, by saying it on a line on its own:", + helpFormat("<url> [<title>] ${Tags.COMMAND}: <+tag> [...]]"), + "I will reply with a label, for example: ${Constants.LINK_CMD.bold()}1", + "To add a title, use its label and a pipe:", + helpFormat("${Constants.LINK_CMD}1:|This is the title"), + "To add a comment:", + helpFormat("${Constants.LINK_CMD}1:This is a comment"), + "I will reply with a label, for example: ${Constants.LINK_CMD.bold()}1.1", + "To edit a comment, see: ", + helpFormat("%c ${Constants.HELP_CMD} ${Comment.COMMAND}") ) override val isOpOnly = false override val isPublic = true diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Tags.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Tags.kt index 1662857..9071059 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Tags.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Tags.kt @@ -44,8 +44,8 @@ import org.pircbotx.hooks.types.GenericMessageEvent class Tags : AbstractCommand() { override val name = COMMAND override val help = listOf( - "To categorize or tag a URL, use its label and a ${Constants.TAG_CMD}:", - helpFormat("${Constants.LINK_CMD}1${Constants.TAG_CMD}:<+tag|-tag> [...]") + "To categorize or tag a URL, use its label and a ${Constants.TAG_CMD}:", + helpFormat("${Constants.LINK_CMD}1${Constants.TAG_CMD}:<+tag|-tag> [...]") ) override val isOpOnly = false override val isPublic = true diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/View.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/View.kt index 825e374..ea1ebf8 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/View.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/View.kt @@ -46,8 +46,8 @@ import org.pircbotx.hooks.types.GenericMessageEvent class View : AbstractCommand() { override val name = VIEW_CMD override val help = listOf( - "To list or search the current URL posts:", - helpFormat("%c $name [<start>] [<query>]") + "To list or search the current URL posts:", + helpFormat("%c $name [<start>] [<query>]") ) override val isOpOnly = false override val isPublic = true @@ -107,9 +107,9 @@ class View : AbstractCommand() { if (sent == MAX_ENTRIES && index < entries.links.size) { event.sendMessage("To view more, try: ") event.sendMessage( - helpFormat( - helpCmdSyntax("%c $name ${index + 1} $query", event.bot().nick, event is PrivateMessageEvent) - ) + helpFormat( + helpCmdSyntax("%c $name ${index + 1} $query", event.bot().nick, event is PrivateMessageEvent) + ) ) } } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt index c9ee0f3..05ad330 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt @@ -58,7 +58,7 @@ class Seen(private val serialObject: String) : AbstractCommand() { override val name = "seen" override val help = listOf("To view when a nickname was last seen:", helpFormat("%c $name <nick>")) private val helpOp = help.plus( - arrayOf("To view all ${"seen".bold()} nicks:", helpFormat("%c $name $allKeyword")) + arrayOf("To view all ${"seen".bold()} nicks:", helpFormat("%c $name $allKeyword")) ) override val isOpOnly = false override val isPublic = true @@ -130,12 +130,12 @@ class Seen(private val serialObject: String) : AbstractCommand() { if (isEnabled()) { @Suppress("UNCHECKED_CAST") seenNicks.putAll( - loadSerialData( - serialObject, - TreeMap<String, SeenNick>(), - logger, - "seen nicknames" - ) as TreeMap<String, SeenNick> + loadSerialData( + serialObject, + TreeMap<String, SeenNick>(), + logger, + "seen nicknames" + ) as TreeMap<String, SeenNick> ) } } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt index e073184..96800bb 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt @@ -66,11 +66,11 @@ class Tell(private val serialObject: String) : AbstractCommand() { override val name = "tell" override val help = listOf( - "To send a message to someone when they join the channel:", - helpFormat("%c $name <nick> <message>"), - "To view queued and sent messages:", - helpFormat("%c $name ${View.VIEW_CMD}"), - "Messages are kept for ${maxDays.bold()}" + " day".plural(maxDays.toLong()) + '.' + "To send a message to someone when they join the channel:", + helpFormat("%c $name <nick> <message>"), + "To view queued and sent messages:", + helpFormat("%c $name ${View.VIEW_CMD}"), + "Messages are kept for ${maxDays.bold()}" + " day".plural(maxDays.toLong()) + '.' ) override val isOpOnly: Boolean = false override val isPublic: Boolean = isEnabled() @@ -118,9 +118,9 @@ class Tell(private val serialObject: String) : AbstractCommand() { } } else { if (messages.removeIf { - it.id == id && - (it.sender.equals(event.user.nick, true) || event.isChannelOp(channel)) - }) { + it.id == id && + (it.sender.equals(event.user.nick, true) || event.isChannelOp(channel)) + }) { save() event.sendMessage("The message was deleted from the queue.") } else { @@ -180,7 +180,7 @@ class Tell(private val serialObject: String) : AbstractCommand() { if (message.sender == nickname) { if (event !is MessageEvent) { event.user.send().message( - "${"You".bold()} wanted me to remind you: ${message.message.reverseColor()}" + "${"You".bold()} wanted me to remind you: ${message.message.reverseColor()}" ) message.isReceived = true message.isNotified = true @@ -188,17 +188,17 @@ class Tell(private val serialObject: String) : AbstractCommand() { } } else { event.user.send().message( - "${message.sender} wanted me to tell you: ${message.message.reverseColor()}" + "${message.sender} wanted me to tell you: ${message.message.reverseColor()}" ) message.isReceived = true save() } } else if (message.sender.equals(nickname, ignoreCase = true) && message.isReceived - && !message.isNotified + && !message.isNotified ) { event.user.send().message( - "Your message ${"[ID ${message.id}]".reverseColor()} was sent to " - + "${message.recipient.bold()} on ${message.receptionDate}" + "Your message ${"[ID ${message.id}]".reverseColor()} was sent to " + + "${message.recipient.bold()} on ${message.receptionDate}" ) message.isNotified = true save() @@ -219,8 +219,8 @@ class Tell(private val serialObject: String) : AbstractCommand() { if (messages.isNotEmpty()) { for (message in messages) { event.sendMessage( - "${message.sender.bold()}$ARROW${message.recipient.bold()} [ID: ${message.id}, " + - (if (message.isReceived) "DELIVERED]" else "QUEUED]") + "${message.sender.bold()}$ARROW${message.recipient.bold()} [ID: ${message.id}, " + + (if (message.isReceived) "DELIVERED]" else "QUEUED]") ) } } else { @@ -238,13 +238,13 @@ class Tell(private val serialObject: String) : AbstractCommand() { } if (message.isReceived) { event.sendMessage( - message.sender.bold() + ARROW + message.recipient.bold() + - " [${message.receptionDate.toUtcDateTime()}, ID: ${message.id.bold()}, DELIVERED]" + message.sender.bold() + ARROW + message.recipient.bold() + + " [${message.receptionDate.toUtcDateTime()}, ID: ${message.id.bold()}, DELIVERED]" ) } else { event.sendMessage( - message.sender.bold() + ARROW + message.recipient.bold() + - " [${message.queued.toUtcDateTime()}, ID: ${message.id.bold()}, QUEUED]" + message.sender.bold() + ARROW + message.recipient.bold() + + " [${message.queued.toUtcDateTime()}, ID: ${message.id.bold()}, QUEUED]" ) } event.sendMessage(helpFormat(message.message)) @@ -254,9 +254,9 @@ class Tell(private val serialObject: String) : AbstractCommand() { } else { event.sendMessage("To delete one or all delivered messages:") event.sendMessage( - helpFormat( - helpCmdSyntax("%c $name $TELL_DEL_KEYWORD <id|$TELL_ALL_KEYWORD>", event.bot().nick, true) - ) + helpFormat( + helpCmdSyntax("%c $name $TELL_DEL_KEYWORD <id|$TELL_ALL_KEYWORD>", event.bot().nick, true) + ) ) event.sendMessage(help.last()) } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt index 6d2f313..33bc1e9 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt @@ -39,20 +39,20 @@ import java.time.format.DateTimeFormatter * Tell Message. */ class TellMessage( - /** - * Returns the message's sender. - */ - val sender: String, + /** + * Returns the message's sender. + */ + val sender: String, - /** - * Returns the message's recipient. - */ - val recipient: String, + /** + * Returns the message's recipient. + */ + val recipient: String, - /** - * Returns the message text. - */ - val message: String + /** + * Returns the message text. + */ + val message: String ) : Serializable { /** * Returns the queued date/time. diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/Entries.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/Entries.kt index e8676ec..ba22746 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/Entries.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/Entries.kt @@ -34,10 +34,10 @@ package net.thauvin.erik.mobibot.entries import net.thauvin.erik.mobibot.Utils.today class Entries( - var channel: String = "", - var ircServer: String = "", - var logsDir: String = "", - var backlogs: String = "" + var channel: String = "", + var ircServer: String = "", + var logsDir: String = "", + var backlogs: String = "" ) { val links = mutableListOf<EntryLink>() diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt index 9c09626..ff1e423 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt @@ -43,7 +43,7 @@ object EntriesUtils { */ @JvmStatic fun printComment(entryIndex: Int, commentIndex: Int, comment: EntryComment): String = - ("${entryIndex.toLinkLabel()}.${commentIndex + 1}: [${comment.nick}] ${comment.comment}") + ("${entryIndex.toLinkLabel()}.${commentIndex + 1}: [${comment.nick}] ${comment.comment}") /** * Prints an entry's link for display on the channel. @@ -52,7 +52,7 @@ object EntriesUtils { @JvmOverloads fun printLink(entryIndex: Int, entry: EntryLink, isView: Boolean = false): String { val buff = StringBuilder().append(entryIndex.toLinkLabel()).append(": ") - .append('[').append(entry.nick).append(']') + .append('[').append(entry.nick).append(']') if (isView && entry.comments.isNotEmpty()) { buff.append("[+").append(entry.comments.size).append(']') } @@ -73,7 +73,7 @@ object EntriesUtils { */ @JvmStatic fun printTags(entryIndex: Int, entry: EntryLink): String = - entryIndex.toLinkLabel() + "${Constants.TAG_CMD}: " + entry.formatTags(", ") + entryIndex.toLinkLabel() + "${Constants.TAG_CMD}: " + entry.formatTags(", ") /** * Builds link label based on its index. e.g: L1 diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt index fc61d18..80ca536 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt @@ -34,47 +34,46 @@ import com.rometools.rome.feed.synd.SyndCategory import com.rometools.rome.feed.synd.SyndCategoryImpl import net.thauvin.erik.mobibot.commands.links.LinksManager import java.io.Serializable -import java.util.Calendar -import java.util.Date +import java.util.* /** * The class used to store link entries. */ class EntryLink( - // Link's comments - val comments: MutableList<EntryComment> = mutableListOf(), + // Link's comments + val comments: MutableList<EntryComment> = mutableListOf(), - // Tags/categories - val tags: MutableList<SyndCategory> = mutableListOf(), + // Tags/categories + val tags: MutableList<SyndCategory> = mutableListOf(), - // Channel - var channel: String, + // Channel + var channel: String, - // Creation date - var date: Date = Calendar.getInstance().time, + // Creation date + var date: Date = Calendar.getInstance().time, - // Link's URL - var link: String, + // Link's URL + var link: String, - // Author's login - var login: String = "", + // Author's login + var login: String = "", - // Author's nickname - var nick: String, + // Author's nickname + var nick: String, - // Link's title - var title: String + // Link's title + var title: String ) : Serializable { /** * Creates a new entry. */ constructor( - link: String, - title: String, - nick: String, - login: String, - channel: String, - tags: List<String?> + link: String, + title: String, + nick: String, + login: String, + channel: String, + tags: List<String?> ) : this(link = link, title = title, nick = nick, login = login, channel = channel) { setTags(tags) } @@ -83,12 +82,12 @@ class EntryLink( * Creates a new entry. */ constructor( - link: String, - title: String, - nick: String, - channel: String, - date: Date, - tags: List<SyndCategory> + link: String, + title: String, + nick: String, + channel: String, + date: Date, + tags: List<SyndCategory> ) : this(link = link, title = title, nick = nick, channel = channel, date = Date(date.time)) { this.tags.addAll(tags) } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt index bb3838a..a30ba24 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt @@ -30,11 +30,7 @@ */ package net.thauvin.erik.mobibot.entries -import com.rometools.rome.feed.synd.SyndContentImpl -import com.rometools.rome.feed.synd.SyndEntry -import com.rometools.rome.feed.synd.SyndEntryImpl -import com.rometools.rome.feed.synd.SyndFeed -import com.rometools.rome.feed.synd.SyndFeedImpl +import com.rometools.rome.feed.synd.* import com.rometools.rome.io.FeedException import com.rometools.rome.io.SyndFeedInput import com.rometools.rome.io.SyndFeedOutput @@ -48,7 +44,7 @@ import java.io.OutputStreamWriter import java.nio.charset.StandardCharsets import java.nio.file.Files import java.nio.file.Paths -import java.util.Calendar +import java.util.* import kotlin.io.path.exists /** @@ -76,7 +72,7 @@ class FeedsManager private constructor() { if (xml.exists()) { val input = SyndFeedInput() InputStreamReader( - Files.newInputStream(xml), StandardCharsets.UTF_8 + Files.newInputStream(xml), StandardCharsets.UTF_8 ).use { reader -> val feed = input.build(reader) pubDate = feed.publishedDate.toIsoLocalDate() @@ -85,12 +81,12 @@ class FeedsManager private constructor() { for (i in items.indices.reversed()) { with(items[i]) { entry = EntryLink( - link, - title, - author.substring(author.lastIndexOf('(') + 1, author.length - 1), - entries.channel, - publishedDate, - categories + link, + title, + author.substring(author.lastIndexOf('(') + 1, author.length - 1), + entries.channel, + publishedDate, + categories ) var split: List<String> for (comment in description.value.split("<br/>")) { @@ -123,7 +119,7 @@ class FeedsManager private constructor() { val items: MutableList<SyndEntry> = mutableListOf() var item: SyndEntry OutputStreamWriter( - Files.newOutputStream(Paths.get("${entries.logsDir}${currentFile}")), StandardCharsets.UTF_8 + Files.newOutputStream(Paths.get("${entries.logsDir}${currentFile}")), StandardCharsets.UTF_8 ).use { fw -> with(rss) { feedType = "rss_2.0" @@ -138,13 +134,13 @@ class FeedsManager private constructor() { with(entries.links[i]) { buff.setLength(0) buff.append("Posted by <b>") - .append(nick) - .append("</b> on <a href=\"irc://") - .append(entries.ircServer).append('/') - .append(channel) - .append("\"><b>") - .append(channel) - .append("</b></a>") + .append(nick) + .append("</b> on <a href=\"irc://") + .append(entries.ircServer).append('/') + .append(channel) + .append("\"><b>") + .append(channel) + .append("</b></a>") if (comments.size > 0) { buff.append(" <br/><br/>") for (j in comments.indices) { @@ -169,11 +165,11 @@ class FeedsManager private constructor() { output.output(rss, fw) } OutputStreamWriter( - Files.newOutputStream( - Paths.get( - entries.logsDir + today() + dotXml - ) - ), StandardCharsets.UTF_8 + Files.newOutputStream( + Paths.get( + entries.logsDir + today() + dotXml + ) + ), StandardCharsets.UTF_8 ).use { fw -> output.output(rss, fw) } } catch (e: FeedException) { if (logger.isWarnEnabled) logger.warn("Unable to generate the entries feed.", e) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt index c1f660e..e1e86df 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt @@ -55,8 +55,10 @@ class ChatGpt : AbstractModule() { override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { if (args.isNotBlank()) { try { - val answer = chat(args.trim(), properties[API_KEY_PROP], - properties.getOrDefault(MAX_TOKENS_PROP, "1024").toInt()) + val answer = chat( + args.trim(), properties[API_KEY_PROP], + properties.getOrDefault(MAX_TOKENS_PROP, "1024").toInt() + ) if (answer.isNotBlank()) { event.sendMessage(WordUtils.wrap(answer, 400)) } else { @@ -105,13 +107,13 @@ class ChatGpt : AbstractModule() { if (!apiKey.isNullOrEmpty()) { val prompt = JSONWriter.valueToString("Q:$query\nA:") val request = HttpRequest.newBuilder() - .uri(URI.create(API_URL)) - .header("Content-Type", "application/json") - .header("Authorization", "Bearer $apiKey") - .header("User-Agent", Constants.USER_AGENT) - .POST( - HttpRequest.BodyPublishers.ofString( - """{ + .uri(URI.create(API_URL)) + .header("Content-Type", "application/json") + .header("Authorization", "Bearer $apiKey") + .header("User-Agent", Constants.USER_AGENT) + .POST( + HttpRequest.BodyPublishers.ofString( + """{ "model": "text-davinci-003", "prompt": $prompt, "temperature": 0, @@ -120,9 +122,9 @@ class ChatGpt : AbstractModule() { "frequency_penalty": 0, "presence_penalty": 0 }""".trimIndent() + ) ) - ) - .build() + .build() try { val response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString()) if (response.statusCode() == 200) { @@ -132,16 +134,16 @@ class ChatGpt : AbstractModule() { return choices.getJSONObject(0).getString("text").trim() } catch (e: JSONException) { throw ModuleException( - "$CHATGPT_CMD($query): JSON", - "A JSON error has occurred while conversing with $CHATGPT_NAME.", - e + "$CHATGPT_CMD($query): JSON", + "A JSON error has occurred while conversing with $CHATGPT_NAME.", + e ) } } else { if (response.statusCode() == 429) { throw ModuleException( - "$CHATGPT_CMD($query): Rate limit reached", - "Rate limit reached. Please try again later." + "$CHATGPT_CMD($query): Rate limit reached", + "Rate limit reached. Please try again later." ) } else { throw IOException("HTTP Status Code: " + response.statusCode()) @@ -149,9 +151,9 @@ class ChatGpt : AbstractModule() { } } catch (e: IOException) { throw ModuleException( - "$CHATGPT_CMD($query): IO", - "An IO error has occurred while conversing with $CHATGPT_NAME.", - e + "$CHATGPT_CMD($query): IO", + "An IO error has occurred while conversing with $CHATGPT_NAME.", + e ) } } else { diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt index d14056e..5136504 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt @@ -134,9 +134,9 @@ class CryptoPrices : AbstractModule() { } } catch (e: CryptoException) { throw ModuleException( - "loadCurrencies(): CE", - "An error has occurred while retrieving the currencies table.", - e + "loadCurrencies(): CE", + "An error has occurred while retrieving the currencies table.", + e ) } } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt index d41e7a1..0bf9d7a 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt @@ -45,7 +45,7 @@ import org.slf4j.Logger import org.slf4j.LoggerFactory import java.io.IOException import java.net.URL -import java.util.TreeMap +import java.util.* /** @@ -99,15 +99,15 @@ class CurrencyConverter : AbstractModule() { event.sendMessage("To convert from one currency to another:") event.sendMessage(helpFormat(helpCmdSyntax("%c $CURRENCY_CMD 100 USD to EUR", nick, isPrivateMsgEnabled))) event.sendMessage( - helpFormat( - helpCmdSyntax("%c $CURRENCY_CMD 50,000 GBP to BTC", nick, isPrivateMsgEnabled) - ) + helpFormat( + helpCmdSyntax("%c $CURRENCY_CMD 50,000 GBP to BTC", nick, isPrivateMsgEnabled) + ) ) event.sendMessage("To list the supported currency codes:") event.sendMessage( - helpFormat( - helpCmdSyntax("%c $CURRENCY_CMD $CODES_KEYWORD", nick, isPrivateMsgEnabled) - ) + helpFormat( + helpCmdSyntax("%c $CURRENCY_CMD $CODES_KEYWORD", nick, isPrivateMsgEnabled) + ) ) } return true @@ -146,7 +146,7 @@ class CurrencyConverter : AbstractModule() { if (json.getBoolean("success")) { PublicMessage( - "${cmds[0]} ${SYMBOLS[to]} = ${json.get("result")} ${SYMBOLS[from]}" + "${cmds[0]} ${SYMBOLS[to]} = ${json.get("result")} ${SYMBOLS[from]}" ) } else { ErrorMessage("Sorry, an error occurred while converting the currencies.") @@ -178,9 +178,9 @@ class CurrencyConverter : AbstractModule() { } } catch (e: IOException) { throw ModuleException( - "loadCodes(): IOE", - "An IO error has occurred while retrieving the currencies.", - e + "loadCodes(): IOE", + "An IO error has occurred while retrieving the currencies.", + e ) } } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt index f426d1e..b0e911c 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt @@ -65,10 +65,10 @@ class GoogleSearch : AbstractModule() { if (args.isNotBlank()) { try { val results = searchGoogle( - args, - properties[API_KEY_PROP], - properties[CSE_KEY_PROP], - event.user.nick + args, + properties[API_KEY_PROP], + properties[CSE_KEY_PROP], + event.user.nick ) for (msg in results) { if (msg.isError) { @@ -104,23 +104,23 @@ class GoogleSearch : AbstractModule() { @JvmStatic @Throws(ModuleException::class) fun searchGoogle( - query: String, - apiKey: String?, - cseKey: String?, - quotaUser: String = ReleaseInfo.PROJECT + query: String, + apiKey: String?, + cseKey: String?, + quotaUser: String = ReleaseInfo.PROJECT ): List<Message> { if (apiKey.isNullOrBlank() || cseKey.isNullOrBlank()) { throw ModuleException( - "${GoogleSearch::class.java.name} is disabled.", - "${GOOGLE_CMD.capitalise()} is disabled. The API keys are missing." + "${GoogleSearch::class.java.name} is disabled.", + "${GOOGLE_CMD.capitalise()} is disabled. The API keys are missing." ) } val results = mutableListOf<Message>() if (query.isNotBlank()) { try { val url = URL( - "https://www.googleapis.com/customsearch/v1?key=$apiKey&cx=$cseKey" + - ""aUser=${quotaUser}&q=${query.encodeUrl()}&filter=1&num=5&alt=json" + "https://www.googleapis.com/customsearch/v1?key=$apiKey&cx=$cseKey" + + ""aUser=${quotaUser}&q=${query.encodeUrl()}&filter=1&num=5&alt=json" ) val json = JSONObject(url.reader().body) if (json.has("items")) { @@ -141,9 +141,9 @@ class GoogleSearch : AbstractModule() { throw ModuleException("searchGoogle($query): IOE", "An IO error has occurred searching Google.", e) } catch (e: JSONException) { throw ModuleException( - "searchGoogle($query): JSON", - "A JSON error has occurred searching Google.", - e + "searchGoogle($query): JSON", + "A JSON error has occurred searching Google.", + e ) } } else { diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Lookup.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Lookup.kt index 9ab2ead..fc85226 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Lookup.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Lookup.kt @@ -55,9 +55,9 @@ class Lookup : AbstractModule() { event.respondWith(nslookup(args).prependIndent()) } catch (ignore: UnknownHostException) { if (args.matches( - ("(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)") - .toRegex() - ) + ("(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)") + .toRegex() + ) ) { try { val lines = whois(args) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Mastodon.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Mastodon.kt index 3be3a5f..4cf2fe9 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Mastodon.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Mastodon.kt @@ -65,7 +65,7 @@ class Mastodon : SocialModule() { private fun formatTags(entry: EntryLink): String { return entry.tags.filter { !it.name.equals(entry.channel.removePrefix("#"), true) } - .joinToString(separator = " ", prefix = "\n\n") { "#${it.name}" } + .joinToString(separator = " ", prefix = "\n\n") { "#${it.name}" } } /** @@ -74,11 +74,11 @@ class Mastodon : SocialModule() { @Throws(ModuleException::class) override fun post(message: String, isDm: Boolean): String { return toot( - apiKey = properties[ACCESS_TOKEN_PROP], - instance = properties[INSTANCE_PROP], - handle = handle, - message = message, - isDm = isDm + apiKey = properties[ACCESS_TOKEN_PROP], + instance = properties[INSTANCE_PROP], + handle = handle, + message = message, + isDm = isDm ) } @@ -99,21 +99,21 @@ class Mastodon : SocialModule() { @Throws(ModuleException::class) fun toot(apiKey: String?, instance: String?, handle: String?, message: String, isDm: Boolean): String { val request = HttpRequest.newBuilder() - .uri(URI.create("https://$instance/api/v1/statuses")) - .header("Content-Type", "application/json") - .header("Authorization", "Bearer $apiKey") - .POST( - HttpRequest.BodyPublishers.ofString( - JSONWriter.valueToString( - if (isDm) { - mapOf("status" to "${handle?.prefixIfMissing('@')} $message", "visibility" to "direct") - } else { - mapOf("status" to message) - } - ) + .uri(URI.create("https://$instance/api/v1/statuses")) + .header("Content-Type", "application/json") + .header("Authorization", "Bearer $apiKey") + .POST( + HttpRequest.BodyPublishers.ofString( + JSONWriter.valueToString( + if (isDm) { + mapOf("status" to "${handle?.prefixIfMissing('@')} $message", "visibility" to "direct") + } else { + mapOf("status" to message) + } + ) + ) ) - ) - .build() + .build() try { val response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString()) if (response.statusCode() == 200) { diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ModuleException.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ModuleException.kt index a569d21..017efd4 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ModuleException.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ModuleException.kt @@ -34,9 +34,9 @@ package net.thauvin.erik.mobibot.modules * The `ModuleException` class. */ class ModuleException @JvmOverloads constructor( - val debugMessage: String, - message: String? = null, - cause: Throwable? = null + val debugMessage: String, + message: String? = null, + cause: Throwable? = null ) : Exception(message, cause) { companion object { private const val serialVersionUID = 1L diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Ping.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Ping.kt index 944dbc1..de5c1e8 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Ping.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Ping.kt @@ -50,18 +50,18 @@ class Ping : AbstractModule() { */ @JvmField val PINGS = listOf( - "is barely alive.", - "is trying to stay awake.", - "has gone fishing.", - "is somewhere over the rainbow.", - "has fallen and can't get up.", - "is running. You better go chase it.", - "has just spontaneously combusted.", - "is talking to itself... don't interrupt. That's rude.", - "is bartending at an AA meeting.", - "is hibernating.", - "is saving energy: apathetic mode activated.", - "is busy. Go away!" + "is barely alive.", + "is trying to stay awake.", + "has gone fishing.", + "is somewhere over the rainbow.", + "has fallen and can't get up.", + "is running. You better go chase it.", + "has just spontaneously combusted.", + "is talking to itself... don't interrupt. That's rude.", + "is bartending at an AA meeting.", + "is hibernating.", + "is saving energy: apathetic mode activated.", + "is busy. Go away!" ) @JvmStatic diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt index d698888..359956a 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt @@ -52,10 +52,10 @@ class RockPaperScissors : AbstractModule() { with(help) { add("To play Rock Paper Scissors:") add( - helpFormat( - "%c ${Hands.ROCK.name.lowercase()} | ${Hands.PAPER.name.lowercase()}" - + " | ${Hands.SCISSORS.name.lowercase()}" - ) + helpFormat( + "%c ${Hands.ROCK.name.lowercase()} | ${Hands.PAPER.name.lowercase()}" + + " | ${Hands.SCISSORS.name.lowercase()}" + ) ) } } @@ -96,7 +96,7 @@ class RockPaperScissors : AbstractModule() { override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { val hand = Hands.valueOf(cmd.uppercase()) - val botHand = Hands.values()[(0..Hands.values().size).random()] + val botHand = Hands.entries[(0..Hands.entries.size).random()] when { hand == botHand -> { event.respond("${hand.name} vs. ${botHand.name} » You ${"tie".bold()}.") diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt index dcae5e7..661a4e8 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt @@ -132,8 +132,8 @@ class StockQuote : AbstractModule() { fun getQuote(symbol: String, apiKey: String?): List<Message> { if (apiKey.isNullOrBlank()) { throw ModuleException( - "${StockQuote::class.java.name} is disabled.", - "${STOCK_CMD.capitalise()} is disabled. The API key is missing." + "${StockQuote::class.java.name} is disabled.", + "${STOCK_CMD.capitalise()} is disabled. The API key is missing." ) } val messages = mutableListOf<Message>() @@ -144,8 +144,8 @@ class StockQuote : AbstractModule() { with(messages) { // Search for symbol/keywords response = URL( - "${API_URL}SYMBOL_SEARCH&keywords=" + symbol.encodeUrl() + "&apikey=" - + apiKey.encodeUrl() + "${API_URL}SYMBOL_SEARCH&keywords=" + symbol.encodeUrl() + "&apikey=" + + apiKey.encodeUrl() ).reader().body var json = getJsonResponse(response, debugMessage) val symbols = json.getJSONArray("bestMatches") @@ -156,9 +156,9 @@ class StockQuote : AbstractModule() { // Get quote for symbol response = URL( - "${API_URL}GLOBAL_QUOTE&symbol=" - + symbolInfo.getString("1. symbol").encodeUrl() + "&apikey=" - + apiKey.encodeUrl() + "${API_URL}GLOBAL_QUOTE&symbol=" + + symbolInfo.getString("1. symbol").encodeUrl() + "&apikey=" + + apiKey.encodeUrl() ).reader().body json = getJsonResponse(response, debugMessage) val quote = json.getJSONObject("Global Quote") @@ -167,50 +167,50 @@ class StockQuote : AbstractModule() { } else { add( - PublicMessage( - "Symbol: " + quote.getString("01. symbol").unescapeXml() - + " [" + symbolInfo.getString("2. name").unescapeXml() + ']' - ) + PublicMessage( + "Symbol: " + quote.getString("01. symbol").unescapeXml() + + " [" + symbolInfo.getString("2. name").unescapeXml() + ']' + ) ) val pad = 10 add( - PublicMessage( - "Price:".padEnd(pad).prependIndent() - + quote.getString("05. price").unescapeXml() - ) + PublicMessage( + "Price:".padEnd(pad).prependIndent() + + quote.getString("05. price").unescapeXml() + ) ) add( - PublicMessage( - "Previous:".padEnd(pad).prependIndent() - + quote.getString("08. previous close").unescapeXml() - ) + PublicMessage( + "Previous:".padEnd(pad).prependIndent() + + quote.getString("08. previous close").unescapeXml() + ) ) val data = arrayOf( - "Open" to "02. open", - "High" to "03. high", - "Low" to "04. low", - "Volume" to "06. volume", - "Latest" to "07. latest trading day" + "Open" to "02. open", + "High" to "03. high", + "Low" to "04. low", + "Volume" to "06. volume", + "Latest" to "07. latest trading day" ) data.forEach { add( - NoticeMessage( - "${it.first}:".padEnd(pad).prependIndent() - + quote.getString(it.second).unescapeXml() - ) + NoticeMessage( + "${it.first}:".padEnd(pad).prependIndent() + + quote.getString(it.second).unescapeXml() + ) ) } add( - NoticeMessage( - "Change:".padEnd(pad).prependIndent() - + quote.getString("09. change").unescapeXml() - + " [" + quote.getString("10. change percent").unescapeXml() + ']' - ) + NoticeMessage( + "Change:".padEnd(pad).prependIndent() + + quote.getString("09. change").unescapeXml() + + " [" + quote.getString("10. change percent").unescapeXml() + ']' + ) ) } } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt index 567728e..533cce6 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt @@ -104,7 +104,7 @@ class Weather2 : AbstractModule() { * Returns a country based on its country code. Defaults to [Country.UNITED_STATES] if not found. */ fun getCountry(countryCode: String): Country { - for (c in Country.values()) { + for (c in Country.entries) { if (c.value.equals(countryCode, ignoreCase = true)) { return c } @@ -120,8 +120,8 @@ class Weather2 : AbstractModule() { fun getWeather(query: String, apiKey: String?): List<Message> { if (apiKey.isNullOrBlank()) { throw ModuleException( - "${Weather2::class.java.name} is disabled.", - "${WEATHER_CMD.capitalise()} is disabled. The API key is missing." + "${Weather2::class.java.name} is disabled.", + "${WEATHER_CMD.capitalise()} is disabled. The API key is missing." ) } val owm = OWM(apiKey) @@ -145,10 +145,10 @@ class Weather2 : AbstractModule() { } if (cwd.hasCityName()) { messages.add( - PublicMessage( - "City: ${cwd.cityName}, " + - country.name.replace('_', ' ').capitalizeWords() + " [${country.value}]" - ) + PublicMessage( + "City: ${cwd.cityName}, " + + country.name.replace('_', ' ').capitalizeWords() + " [${country.value}]" + ) ) cwd.mainData?.let { with(it) { @@ -181,8 +181,8 @@ class Weather2 : AbstractModule() { for (w in it) { w?.let { condition.append(' ') - .append(w.getDescription().capitalise()) - .append('.') + .append(w.getDescription().capitalise()) + .append('.') } } messages.add(NoticeMessage(condition.toString())) @@ -192,15 +192,15 @@ class Weather2 : AbstractModule() { cwd.cityId?.let { if (it > 0) { messages.add( - NoticeMessage("https://openweathermap.org/city/$it", Colors.GREEN) + NoticeMessage("https://openweathermap.org/city/$it", Colors.GREEN) ) } else { messages.add( - NoticeMessage( - "https://openweathermap.org/find?q=" - + "$city,${code.uppercase()}".encodeUrl(), - Colors.GREEN - ) + NoticeMessage( + "https://openweathermap.org/find?q=" + + "$city,${code.uppercase()}".encodeUrl(), + Colors.GREEN + ) ) } } @@ -209,9 +209,9 @@ class Weather2 : AbstractModule() { } catch (e: APIException) { if (e.code == 404) { throw ModuleException( - "getWeather($query): API ${e.code}", - "The requested city was not found.", - e + "getWeather($query): API ${e.code}", + "The requested city was not found.", + e ) } else { throw ModuleException("getWeather($query): API ${e.code}", e.message, e) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt index a72efab..049807a 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt @@ -60,15 +60,15 @@ class WolframAlpha : AbstractModule() { try { val query = args.trim().split("units=", limit = 2, ignoreCase = true) event.sendMessage( - queryWolfram( - query[0].trim(), - units = if (query.size == 2) { - getUnits(query[1].trim()) - } else { - getUnits(properties[UNITS_PROP]) - }, - appId = properties[APPID_KEY_PROP] - ) + queryWolfram( + query[0].trim(), + units = if (query.size == 2) { + getUnits(query[1].trim()) + } else { + getUnits(properties[UNITS_PROP]) + }, + appId = properties[APPID_KEY_PROP] + ) ) } catch (e: ModuleException) { if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) @@ -111,15 +111,15 @@ class WolframAlpha : AbstractModule() { return urlReader.body } else { throw ModuleException( - "wolfram($query): ${urlReader.responseCode} : ${urlReader.body} ", - urlReader.body.ifEmpty { - "Looks like Wolfram Alpha isn't able to answer that. (${urlReader.responseCode})" - } + "wolfram($query): ${urlReader.responseCode} : ${urlReader.body} ", + urlReader.body.ifEmpty { + "Looks like Wolfram Alpha isn't able to answer that. (${urlReader.responseCode})" + } ) } } catch (ioe: IOException) { throw ModuleException( - "wolfram($query): IOE", "An IO Error occurred while querying Wolfram Alpha.", ioe + "wolfram($query): IOE", "An IO Error occurred while querying Wolfram Alpha.", ioe ) } } else { diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WorldTime.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WorldTime.kt index 18072bc..debbe98 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WorldTime.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WorldTime.kt @@ -322,7 +322,7 @@ class WorldTime : AbstractModule() { put("ZULU", "Zulu") put("ZW", "Africa/Harare") ZoneId.getAvailableZoneIds().filter { it.length <= 3 && !containsKey(it) } - .forEach { tz -> put(tz, tz) } + .forEach { tz -> put(tz, tz) } } // The Time command @@ -336,7 +336,7 @@ class WorldTime : AbstractModule() { // Date/Time Format private var dtf = - DateTimeFormatter.ofPattern("'The time is ${"'HH:mm'".bold()} on ${"'EEEE, d MMMM yyyy'".bold()} in '") + DateTimeFormatter.ofPattern("'The time is ${"'HH:mm'".bold()} on ${"'EEEE, d MMMM yyyy'".bold()} in '") /** * Returns the current Internet (beat) Time. diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/ErrorMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/ErrorMessage.kt index 0607936..2695a3b 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/ErrorMessage.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/msg/ErrorMessage.kt @@ -34,4 +34,4 @@ package net.thauvin.erik.mobibot.msg * The `ErrorMessage` class. */ class ErrorMessage @JvmOverloads constructor(msg: String, color: String = DEFAULT_COLOR) : - Message(msg, color, isError = true) + Message(msg, color, isError = true) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/Message.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/Message.kt index 23a33b9..3b4be49 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/Message.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/msg/Message.kt @@ -36,11 +36,11 @@ import net.thauvin.erik.semver.Constants * The `Message` class. */ open class Message @JvmOverloads constructor( - var msg: String, - var color: String = DEFAULT_COLOR, - var isNotice: Boolean = false, - isError: Boolean = false, - var isPrivate: Boolean = false + var msg: String, + var color: String = DEFAULT_COLOR, + var isNotice: Boolean = false, + isError: Boolean = false, + var isPrivate: Boolean = false ) { companion object { var DEFAULT_COLOR = Constants.EMPTY diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/NoticeMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/NoticeMessage.kt index 037d504..cd6721c 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/NoticeMessage.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/msg/NoticeMessage.kt @@ -34,5 +34,5 @@ package net.thauvin.erik.mobibot.msg * The `NoticeMessage` class. */ class NoticeMessage @JvmOverloads constructor(msg: String, color: String = DEFAULT_COLOR) : - Message(msg, color, isNotice = true) + Message(msg, color, isNotice = true) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/PrivateMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/PrivateMessage.kt index 842fee5..3033d1a 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/PrivateMessage.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/msg/PrivateMessage.kt @@ -33,6 +33,5 @@ package net.thauvin.erik.mobibot.msg /** * The `PrivateMessage` class. */ -@Suppress("unused") class PrivateMessage @JvmOverloads constructor(msg: String, color: String = DEFAULT_COLOR) : - Message(msg, color, isPrivate = true) + Message(msg, color, isPrivate = true) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialManager.kt b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialManager.kt index cbc1936..91f2dd9 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialManager.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialManager.kt @@ -36,7 +36,7 @@ import net.thauvin.erik.mobibot.Constants import net.thauvin.erik.mobibot.entries.EntriesUtils.toLinkLabel import org.slf4j.Logger import org.slf4j.LoggerFactory -import java.util.Timer +import java.util.* /** * Social Manager. diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialModule.kt b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialModule.kt index b594670..32e670a 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialModule.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialModule.kt @@ -76,8 +76,8 @@ abstract class SocialModule : AbstractModule() { post(message = formatEntry(LinksManager.entries.links[index]), isDm = false) } catch (e: ModuleException) { if (logger.isWarnEnabled) logger.warn( - "Failed to post entry ${index.toLinkLabel()} on $name.", - e + "Failed to post entry ${index.toLinkLabel()} on $name.", + e ) } } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialTimer.kt b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialTimer.kt index 267a59d..3fd315e 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialTimer.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialTimer.kt @@ -31,7 +31,7 @@ package net.thauvin.erik.mobibot.social -import java.util.TimerTask +import java.util.* class SocialTimer(private var socialManager: SocialManager, private var index: Int) : TimerTask() { override fun run() { diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt index ebc2aa0..5a8a638 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt @@ -41,13 +41,9 @@ import net.thauvin.erik.mobibot.commands.Die import net.thauvin.erik.mobibot.commands.Ignore import net.thauvin.erik.mobibot.commands.links.Comment import net.thauvin.erik.mobibot.commands.links.View -import net.thauvin.erik.mobibot.modules.Dice -import net.thauvin.erik.mobibot.modules.Joke -import net.thauvin.erik.mobibot.modules.Lookup -import net.thauvin.erik.mobibot.modules.RockPaperScissors -import net.thauvin.erik.mobibot.modules.War +import net.thauvin.erik.mobibot.modules.* import org.testng.annotations.Test -import java.util.Properties +import java.util.* class AddonsTest { private val p = Properties().apply { @@ -80,11 +76,11 @@ class AddonsTest { assertThat(addons.names.ops, "names.ops").containsExactly("cycle") assertThat(addons.names.commands, "names.command").containsExactly( - "joke", - "rock", - "paper", - "scissors", - "ignore" + "joke", + "rock", + "paper", + "scissors", + "ignore" ) } } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/ExceptionSanitizer.kt b/src/test/kotlin/net/thauvin/erik/mobibot/ExceptionSanitizer.kt index a3994ec..be2deb3 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/ExceptionSanitizer.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/ExceptionSanitizer.kt @@ -46,9 +46,9 @@ object ExceptionSanitizer { with(this) { if (!cause?.message.isNullOrBlank()) { return ModuleException( - debugMessage, - cause?.javaClass?.name + ": " + cause?.message?.replaceEach(search, obfuscate), - this + debugMessage, + cause?.javaClass?.name + ": " + cause?.message?.replaceEach(search, obfuscate), + this ) } else if (!message.isNullOrBlank()) { return ModuleException(debugMessage, message?.replaceEach(search, obfuscate), this) diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt index d30977e..7611ae3 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt @@ -68,6 +68,6 @@ class FeedReaderTest { assertFailure { readFeed("https://www.thauvin.net/foo") }.isInstanceOf(IOException::class.java) assertFailure { readFeed("https://www.examplesfoo.com/") } - .isInstanceOf(UnknownHostException::class.java) + .isInstanceOf(UnknownHostException::class.java) } } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/LocalProperties.kt b/src/test/kotlin/net/thauvin/erik/mobibot/LocalProperties.kt index e4af75a..1384a72 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/LocalProperties.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/LocalProperties.kt @@ -36,7 +36,7 @@ import java.net.InetAddress import java.net.UnknownHostException import java.nio.file.Files import java.nio.file.Paths -import java.util.Properties +import java.util.* /** * Access to `local.properties`. diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/PinboardTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/PinboardTest.kt index 87617e8..4ebb53c 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/PinboardTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/PinboardTest.kt @@ -68,7 +68,7 @@ class PinboardTest : LocalProperties() { private fun validatePin(apiToken: String, url: String, vararg matches: String): Boolean { val response = - URL("https://api.pinboard.in/v1/posts/get?auth_token=${apiToken}&tag=test&" + url.encodeUrl()).reader().body + URL("https://api.pinboard.in/v1/posts/get?auth_token=${apiToken}&tag=test&" + url.encodeUrl()).reader().body matches.forEach { if (!response.contains(it)) { diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt index ef0eaaf..8ddb013 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt @@ -66,15 +66,14 @@ import java.io.File import java.io.IOException import java.net.URL import java.time.LocalDateTime -import java.util.Calendar -import java.util.Properties +import java.util.* /** * The `Utils Test` class. */ class UtilsTest { private val ascii = - " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" + " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" private val cal = Calendar.getInstance() private val localDateTime = LocalDateTime.of(1952, 2, 17, 12, 30, 0) private val test = "This is a test." @@ -90,7 +89,7 @@ class UtilsTest { val sep = '/' val url = "https://erik.thauvin.net" assertThat(dir.appendIfMissing(File.separatorChar), "appendIfMissing(dir)") - .isEqualTo(dir + File.separatorChar) + .isEqualTo(dir + File.separatorChar) assertThat(url.appendIfMissing(sep), "appendIfMissing(url)").isEqualTo("$url$sep") assertThat("$url$sep".appendIfMissing(sep), "appendIfMissing($url$sep)").isEqualTo("$url$sep") } @@ -116,24 +115,24 @@ class UtilsTest { fun textCapitaliseWords() { assertThat(test.capitalizeWords(), "captiatlizeWords(test)").isEqualTo("This Is A Test.") assertThat("Already Capitalized".capitalizeWords(), "already capitalized") - .isEqualTo("Already Capitalized") + .isEqualTo("Already Capitalized") assertThat(" a test ".capitalizeWords(), "with spaces").isEqualTo(" A Test ") } @Test fun testColorize() { assertThat(ascii.colorize(Colors.REVERSE), "reverse.colorize()").isEqualTo( - Colors.REVERSE + ascii + Colors.REVERSE + Colors.REVERSE + ascii + Colors.REVERSE ) assertThat(ascii.colorize(Colors.RED), "red.colorize()") - .isEqualTo(Colors.RED + ascii + Colors.NORMAL) + .isEqualTo(Colors.RED + ascii + Colors.NORMAL) assertThat(ascii.colorize(Colors.BOLD), "colorized(bold)") - .isEqualTo(Colors.BOLD + ascii + Colors.BOLD) + .isEqualTo(Colors.BOLD + ascii + Colors.BOLD) assertThat(null.colorize(Colors.RED), "null.colorize()").isEqualTo("") assertThat("".colorize(Colors.RED), "colorize()").isEqualTo("") assertThat(ascii.colorize(DEFAULT_COLOR), "ascii.colorize()").isEqualTo(ascii) assertThat(" ".colorize(Colors.NORMAL), "blank.colorize()") - .isEqualTo(Colors.NORMAL + " " + Colors.NORMAL) + .isEqualTo(Colors.NORMAL + " " + Colors.NORMAL) } @Test @@ -165,19 +164,19 @@ class UtilsTest { fun testHelpCmdSyntax() { val bot = "mobibot" assertThat(helpCmdSyntax("%c $test %n $test", bot, false), "helpCmdSyntax(private)") - .isEqualTo("$bot: $test $bot $test") + .isEqualTo("$bot: $test $bot $test") assertThat(helpCmdSyntax("%c %n $test %c $test %n", bot, true), "helpCmdSyntax(public)") - .isEqualTo("/msg $bot $bot $test /msg $bot $test $bot") + .isEqualTo("/msg $bot $bot $test /msg $bot $test $bot") } @Test fun testHelpFormat() { assertThat(helpFormat(test, isBold = true, isIndent = false), "helpFormat(bold)") - .isEqualTo("${Colors.BOLD}$test${Colors.BOLD}") + .isEqualTo("${Colors.BOLD}$test${Colors.BOLD}") assertThat(helpFormat(test, isBold = false, isIndent = true), "helpFormat(indent)") - .isEqualTo(test.prependIndent()) + .isEqualTo(test.prependIndent()) assertThat(helpFormat(test, isBold = true, isIndent = true), "helpFormat(bold,indent)") - .isEqualTo(test.colorize(Colors.BOLD).prependIndent()) + .isEqualTo(test.colorize(Colors.BOLD).prependIndent()) } @@ -219,15 +218,15 @@ class UtilsTest { val search = arrayOf("one", "two", "three") val replace = arrayOf("1", "2", "3") assertThat(search.joinToString(",").replaceEach(search, replace), "replaceEach(1,2,3") - .isEqualTo(replace.joinToString(",")) + .isEqualTo(replace.joinToString(",")) assertThat(test.replaceEach(search, replace), "replaceEach(nothing)").isEqualTo(test) assertThat(test.replaceEach(arrayOf("t", "e"), arrayOf("", "E")), "replaceEach($test)") - .isEqualTo(test.replace("t", "").replace("e", "E")) + .isEqualTo(test.replace("t", "").replace("e", "E")) assertThat(test.replaceEach(search, emptyArray()), "replaceEach(search, empty)") - .isEqualTo(test) + .isEqualTo(test) } @Test @@ -259,7 +258,7 @@ class UtilsTest { @Test fun testUnescapeXml() { assertThat("<a name="test & ''">".unescapeXml()).isEqualTo( - "<a name=\"test & ''\">" + "<a name=\"test & ''\">" ) } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/InfoTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/InfoTest.kt index 265009b..1f28049 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/InfoTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/InfoTest.kt @@ -40,14 +40,14 @@ class InfoTest { @Test(groups = ["commands"]) fun testToUptime() { assertThat( - 547800300076L.toUptime(), - "upTime(full)" + 547800300076L.toUptime(), + "upTime(full)" ).isEqualTo("17 years 4 months 2 weeks 1 day 6 hours 45 minutes") assertThat(24300000L.toUptime(), "upTime(hours minutes)").isEqualTo("6 hours 45 minutes") assertThat(110700000L.toUptime(), "upTime(days hours minutes)").isEqualTo("1 day 6 hours 45 minutes") assertThat( - 1320300000L.toUptime(), - "upTime(weeks days hours minutes)" + 1320300000L.toUptime(), + "upTime(weeks days hours minutes)" ).isEqualTo("2 weeks 1 day 6 hours 45 minutes") assertThat(2700000L.toUptime(), "upTime(45 minutes)").isEqualTo("45 minutes") assertThat(60000L.toUptime(), "upTime(1 minute)").isEqualTo("1 minute") diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/RecapTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/RecapTest.kt index f1fbe11..5f1a690 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/RecapTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/RecapTest.kt @@ -48,13 +48,13 @@ class RecapTest { assertThat(Recap.recaps, "Recap.recaps").all { size().isEqualTo(Recap.MAX_RECAPS) prop(MutableList<String>::first) - .matches("[1-2]\\d{3}-[01]\\d-[0-3]\\d [0-2]\\d:[0-6]\\d - sender11: test 11".toRegex()) + .matches("[1-2]\\d{3}-[01]\\d-[0-3]\\d [0-2]\\d:[0-6]\\d - sender11: test 11".toRegex()) prop(MutableList<String>::last) - .matches("[1-2]\\d{3}-[01]\\d-[0-3]\\d [0-2]\\d:[0-6]\\d - sender20: test 20".toRegex()) + .matches("[1-2]\\d{3}-[01]\\d-[0-3]\\d [0-2]\\d:[0-6]\\d - sender20: test 20".toRegex()) } Recap.storeRecap("sender", "test action", true) assertThat(Recap.recaps.last()) - .matches("[1-2]\\d{3}-[01]\\d-[0-3]\\d [0-2]\\d:[0-6]\\d - sender test action".toRegex()) + .matches("[1-2]\\d{3}-[01]\\d-[0-3]\\d [0-2]\\d:[0-6]\\d - sender test action".toRegex()) } } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt index 8e49b5e..8fcbd8b 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt @@ -47,8 +47,8 @@ class LinksManagerTest { fun fetchTitle() { assertThat(linksManager.fetchTitle("https://erik.thauvin.net/"), "fetchTitle(Erik)").contains("Erik's Weblog") assertThat( - linksManager.fetchTitle("https://www.google.com/foo"), - "fetchTitle(Foo)" + linksManager.fetchTitle("https://www.google.com/foo"), + "fetchTitle(Foo)" ).isEqualTo(Constants.NO_TITLE) } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/ViewTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/ViewTest.kt index c28090d..0853a9d 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/ViewTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/ViewTest.kt @@ -45,14 +45,14 @@ class ViewTest { for (i in 1..10) { LinksManager.entries.links.add( - EntryLink( - "https://www.example.com/$i", - "Example $i", - "nick$i", - "login$i", - "#channel", - emptyList() - ) + EntryLink( + "https://www.example.com/$i", + "Example $i", + "nick$i", + "login$i", + "#channel", + emptyList() + ) ) } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt index 4298a16..52a21cc 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt @@ -33,14 +33,7 @@ package net.thauvin.erik.mobibot.commands.seen import assertk.all import assertk.assertThat -import assertk.assertions.isEmpty -import assertk.assertions.isEqualTo -import assertk.assertions.isGreaterThan -import assertk.assertions.isNotEqualTo -import assertk.assertions.isNotNull -import assertk.assertions.key -import assertk.assertions.prop -import assertk.assertions.size +import assertk.assertions.* import org.testng.annotations.AfterClass import org.testng.annotations.BeforeClass import org.testng.annotations.Test diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt index cff11f2..115e9fb 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt @@ -33,13 +33,7 @@ package net.thauvin.erik.mobibot.commands.tell import assertk.all import assertk.assertThat -import assertk.assertions.index -import assertk.assertions.isEqualTo -import assertk.assertions.isFalse -import assertk.assertions.isGreaterThan -import assertk.assertions.isTrue -import assertk.assertions.prop -import assertk.assertions.size +import assertk.assertions.* import org.testng.annotations.AfterClass import org.testng.annotations.BeforeClass import org.testng.annotations.Test diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt index 6eef16e..a09ebb9 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt @@ -46,14 +46,14 @@ class EntriesUtilsTest { private val links = buildList { for (i in 0..5) { add( - EntryLink( - "https://www.mobitopia.org/$i", - "Mobitopia$i", - "Skynx$i", - "JimH$i", - "#mobitopia$i", - listOf("tag1", "tag2", "tag3", "TAG4", "Tag5") - ) + EntryLink( + "https://www.mobitopia.org/$i", + "Mobitopia$i", + "Skynx$i", + "JimH$i", + "#mobitopia$i", + listOf("tag1", "tag2", "tag3", "TAG4", "Tag5") + ) ) } } @@ -67,7 +67,7 @@ class EntriesUtilsTest { fun printLinkTest() { for (i in links.indices) { assertThat( - printLink(i - 1, links[i]), "link $i" + printLink(i - 1, links[i]), "link $i" ).isEqualTo("L$i: [Skynx$i] \u0002Mobitopia$i\u0002 ( \u000303https://www.mobitopia.org/$i\u000F )") } @@ -79,7 +79,7 @@ class EntriesUtilsTest { fun printTagsTest() { for (i in links.indices) { assertThat( - printTags(i - 1, links[i]), "tag $i" + printTags(i - 1, links[i]), "tag $i" ).isEqualTo("L${i}T: tag1, tag2, tag3, tag4, tag5") } } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt index ab8c71c..4c20525 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt @@ -32,18 +32,12 @@ package net.thauvin.erik.mobibot.entries import assertk.all import assertk.assertThat -import assertk.assertions.index -import assertk.assertions.isEmpty -import assertk.assertions.isEqualTo -import assertk.assertions.isFalse -import assertk.assertions.isTrue -import assertk.assertions.prop -import assertk.assertions.size +import assertk.assertions.* import com.rometools.rome.feed.synd.SyndCategory import com.rometools.rome.feed.synd.SyndCategoryImpl import org.testng.annotations.Test import java.security.SecureRandom -import java.util.Date +import java.util.* /** * The `EntryUtilsTest` class. @@ -54,8 +48,8 @@ import java.util.Date */ class EntryLinkTest { private val entryLink = EntryLink( - "https://www.mobitopia.org/", "Mobitopia", "Skynx", "JimH", "#mobitopia", - listOf("tag1", "tag2", "tag3", "TAG4", "Tag5") + "https://www.mobitopia.org/", "Mobitopia", "Skynx", "JimH", "#mobitopia", + listOf("tag1", "tag2", "tag3", "TAG4", "Tag5") ) @Test(groups = ["entries"]) @@ -123,12 +117,12 @@ class EntryLinkTest { entryLink.setTags("+mobitopia") entryLink.setTags("-mobitopia") assertThat( - entryLink.formatTags(","), - "formatTags(',')" + entryLink.formatTags(","), + "formatTags(',')" ).isEqualTo("tag1,tag2,tag3,tag4,mobitopia") entryLink.setTags("-tag4 tag5") assertThat( - entryLink.formatTags(" ", ","), "formatTag(' ',',')" + entryLink.formatTags(" ", ","), "formatTag(' ',',')" ).isEqualTo(",tag1 tag2 tag3 mobitopia tag5") val size = entryLink.tags.size entryLink.setTags("") diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt index cd2ebb8..4223d9d 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt @@ -33,18 +33,12 @@ package net.thauvin.erik.mobibot.entries import assertk.all import assertk.assertThat -import assertk.assertions.endsWith -import assertk.assertions.exists -import assertk.assertions.index -import assertk.assertions.isEqualTo -import assertk.assertions.isTrue -import assertk.assertions.prop -import assertk.assertions.size +import assertk.assertions.* import net.thauvin.erik.mobibot.Utils.today import org.testng.annotations.BeforeSuite import org.testng.annotations.Test import java.nio.file.Paths -import java.util.Date +import java.util.* import kotlin.io.path.deleteIfExists import kotlin.io.path.fileSize import kotlin.io.path.name diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt index b3bd248..2b1d3f9 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt @@ -33,7 +33,6 @@ package net.thauvin.erik.mobibot.modules import assertk.assertFailure import assertk.assertThat import assertk.assertions.isEqualTo -import assertk.assertions.isFailure import assertk.assertions.isInstanceOf import net.objecthunter.exp4j.tokenizer.UnknownFunctionOrVariableException import net.thauvin.erik.mobibot.Utils.bold diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt index e4638b9..fa50fcb 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt @@ -34,7 +34,6 @@ import assertk.assertFailure import assertk.assertThat import assertk.assertions.contains import assertk.assertions.hasNoCause -import assertk.assertions.isFailure import assertk.assertions.isInstanceOf import net.thauvin.erik.mobibot.LocalProperties import org.testng.annotations.Test @@ -43,21 +42,21 @@ class ChatGptTest : LocalProperties() { @Test(groups = ["modules"]) fun testApiKey() { assertFailure { ChatGpt.chat("1 gallon to liter", "", 0) } - .isInstanceOf(ModuleException::class.java) - .hasNoCause() + .isInstanceOf(ModuleException::class.java) + .hasNoCause() } @Test(groups = ["modules", "no-ci"]) fun testChat() { val apiKey = getProperty(ChatGpt.API_KEY_PROP) assertThat( - ChatGpt.chat("how do I make an HTTP request in Javascript?", apiKey, 100) + ChatGpt.chat("how do I make an HTTP request in Javascript?", apiKey, 100) ).contains("XMLHttpRequest") assertThat( - ChatGpt.chat("how do I encode a URL in java?", apiKey, 60) + ChatGpt.chat("how do I encode a URL in java?", apiKey, 60) ).contains("URLEncoder") assertFailure { ChatGpt.chat("1 liter to gallon", apiKey, 0) } - .isInstanceOf(ModuleException::class.java) + .isInstanceOf(ModuleException::class.java) } } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt index 8c1d745..10a2470 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt @@ -58,16 +58,16 @@ class CurrencyConverterTest { @Test(groups = ["modules"]) fun testConvertCurrency() { assertThat( - convertCurrency("100 USD to EUR").msg, - "convertCurrency(100 USD to EUR)" + convertCurrency("100 USD to EUR").msg, + "convertCurrency(100 USD to EUR)" ).matches("100 United States Dollar = \\d{2,3}\\.\\d+ Euro".toRegex()) assertThat( - convertCurrency("1 USD to BTC").msg, - "convertCurrency(1 USD to BTC)" + convertCurrency("1 USD to BTC").msg, + "convertCurrency(1 USD to BTC)" ).matches("1 United States Dollar = 0\\.\\d+ Bitcoin".toRegex()) assertThat( - convertCurrency("100,000.00 GBP to BTC").msg, - "convertCurrency(100,000.00 GBP to BTC)" + convertCurrency("100,000.00 GBP to BTC").msg, + "convertCurrency(100,000.00 GBP to BTC)" ).matches("100,000.00 British Pound Sterling = \\d{1,2}\\.\\d+ Bitcoin".toRegex()) assertThat(convertCurrency("100 USD to USD"), "convertCurrency(100 USD to USD)").all { prop(Message::msg).contains("You're kidding, right?") diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/DiceTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/DiceTest.kt index cdc04f0..4225e3b 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/DiceTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/DiceTest.kt @@ -42,12 +42,12 @@ class DiceTest { fun testRoll() { assertThat(Dice.roll(1, 1), "roll(1d1)").isEqualTo("\u00021\u0002") assertThat(Dice.roll(2, 1), "roll(2d1)") - .isEqualTo("\u00021\u0002 + \u00021\u0002 = \u00022\u0002") + .isEqualTo("\u00021\u0002 + \u00021\u0002 = \u00022\u0002") assertThat(Dice.roll(5, 1), "roll(5d1)") - .isEqualTo("\u00021\u0002 + \u00021\u0002 + \u00021\u0002 + \u00021\u0002 + \u00021\u0002 = \u00025\u0002") + .isEqualTo("\u00021\u0002 + \u00021\u0002 + \u00021\u0002 + \u00021\u0002 + \u00021\u0002 = \u00025\u0002") assertThat(Dice.roll(2, 6), "roll(2d6)") - .matches("\u0002[1-6]\u0002 \\+ \u0002[1-6]\u0002 = \u0002[1-9][0-2]?\u0002".toRegex()) + .matches("\u0002[1-6]\u0002 \\+ \u0002[1-6]\u0002 = \u0002[1-9][0-2]?\u0002".toRegex()) assertThat(Dice.roll(3, 7), "roll(3d7)") - .matches("\u0002[1-7]\u0002 \\+ \u0002[1-7]\u0002 \\+ \u0002[1-7]\u0002 = \u0002\\d{1,2}\u0002".toRegex()) + .matches("\u0002[1-7]\u0002 \\+ \u0002[1-7]\u0002 \\+ \u0002[1-7]\u0002 = \u0002\\d{1,2}\u0002".toRegex()) } } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt index 175af47..640a721 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt @@ -33,15 +33,7 @@ package net.thauvin.erik.mobibot.modules import assertk.all import assertk.assertFailure import assertk.assertThat -import assertk.assertions.contains -import assertk.assertions.hasMessage -import assertk.assertions.hasNoCause -import assertk.assertions.index -import assertk.assertions.isEqualTo -import assertk.assertions.isFailure -import assertk.assertions.isInstanceOf -import assertk.assertions.isNotEmpty -import assertk.assertions.prop +import assertk.assertions.* import net.thauvin.erik.mobibot.ExceptionSanitizer.sanitize import net.thauvin.erik.mobibot.LocalProperties import net.thauvin.erik.mobibot.modules.GoogleSearch.Companion.searchGoogle @@ -56,19 +48,19 @@ class GoogleSearchTest : LocalProperties() { @Test(groups = ["modules"]) fun testAPIKeys() { assertThat( - searchGoogle("", "apikey", "cssKey").first(), - "searchGoogle(empty)" + searchGoogle("", "apikey", "cssKey").first(), + "searchGoogle(empty)" ).isInstanceOf(ErrorMessage::class.java) assertFailure { searchGoogle("test", "", "apiKey") } - .isInstanceOf(ModuleException::class.java).hasNoCause() + .isInstanceOf(ModuleException::class.java).hasNoCause() assertFailure { searchGoogle("test", "apiKey", "") } - .isInstanceOf(ModuleException::class.java).hasNoCause() + .isInstanceOf(ModuleException::class.java).hasNoCause() assertFailure { searchGoogle("test", "apiKey", "cssKey") } - .isInstanceOf(ModuleException::class.java) - .hasMessage("API key not valid. Please pass a valid API key.") + .isInstanceOf(ModuleException::class.java) + .hasMessage("API key not valid. Please pass a valid API key.") } @Test(groups = ["no-ci", "modules"]) diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/JokeTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/JokeTest.kt index fa063f4..55a7b8f 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/JokeTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/JokeTest.kt @@ -32,12 +32,7 @@ package net.thauvin.erik.mobibot.modules import assertk.all import assertk.assertThat -import assertk.assertions.doesNotContain -import assertk.assertions.each -import assertk.assertions.isGreaterThan -import assertk.assertions.isInstanceOf -import assertk.assertions.prop -import assertk.assertions.size +import assertk.assertions.* import net.thauvin.erik.mobibot.modules.Joke.Companion.randomJoke import net.thauvin.erik.mobibot.msg.Message import net.thauvin.erik.mobibot.msg.PublicMessage diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt index 34f778a..84f9375 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt @@ -42,13 +42,13 @@ class MastodonTest : LocalProperties() { fun testToot() { val msg = "Testing Mastodon API from ${getHostName()}" assertThat( - toot( - getProperty(Mastodon.ACCESS_TOKEN_PROP), - getProperty(Mastodon.INSTANCE_PROP), - getProperty(Mastodon.HANDLE_PROP), - msg, - true - ) + toot( + getProperty(Mastodon.ACCESS_TOKEN_PROP), + getProperty(Mastodon.INSTANCE_PROP), + getProperty(Mastodon.HANDLE_PROP), + msg, + true + ) ).contains(msg) } } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt index c7dbfc0..b36285b 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt @@ -32,13 +32,7 @@ package net.thauvin.erik.mobibot.modules import assertk.all import assertk.assertThat -import assertk.assertions.contains -import assertk.assertions.doesNotContain -import assertk.assertions.endsWith -import assertk.assertions.hasMessage -import assertk.assertions.isEqualTo -import assertk.assertions.isNotNull -import assertk.assertions.isNull +import assertk.assertions.* import net.thauvin.erik.mobibot.ExceptionSanitizer.sanitize import org.testng.annotations.DataProvider import org.testng.annotations.Test @@ -57,9 +51,9 @@ class ModuleExceptionTest { @DataProvider(name = "dp") fun createData(@Suppress("UNUSED_PARAMETER") m: Method?): Array<Array<Any>> { return arrayOf( - arrayOf(ModuleException(debugMessage, message, IOException("URL http://foobar.com"))), - arrayOf(ModuleException(debugMessage, message, IOException("URL http://foobar.com?"))), - arrayOf(ModuleException(debugMessage, message)) + arrayOf(ModuleException(debugMessage, message, IOException("URL http://foobar.com"))), + arrayOf(ModuleException(debugMessage, message, IOException("URL http://foobar.com?"))), + arrayOf(ModuleException(debugMessage, message)) ) } @@ -78,7 +72,7 @@ class ModuleExceptionTest { val apiKey = "1234567890" var e = ModuleException(debugMessage, message, IOException("URL http://foo.com?apiKey=$apiKey&userID=me")) assertThat( - e.sanitize(apiKey, "", "me").message, "ModuleException(debugMessage, message, IOException(url))" + e.sanitize(apiKey, "", "me").message, "ModuleException(debugMessage, message, IOException(url))" ).isNotNull().all { contains("xxxxxxxxxx", "userID=xx", "java.io.IOException") doesNotContain(apiKey, "me") @@ -92,7 +86,7 @@ class ModuleExceptionTest { e = ModuleException(debugMessage, apiKey) assertThat(e.sanitize(apiKey).message, "ModuleException(debugMessage, apiKey)").isNotNull() - .doesNotContain(apiKey) + .doesNotContain(apiKey) val msg: String? = null e = ModuleException(debugMessage, msg, IOException(msg)) @@ -100,8 +94,8 @@ class ModuleExceptionTest { e = ModuleException(debugMessage, msg, IOException("foo is $apiKey")) assertThat( - e.sanitize(" ", apiKey, "foo").message, - "ModuleException(debugMessage, msg, IOException(foo is $apiKey))" + e.sanitize(" ", apiKey, "foo").message, + "ModuleException(debugMessage, msg, IOException(foo is $apiKey))" ).isNotNull().all { doesNotContain(apiKey) endsWith("xxx is xxxxxxxxxx") diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt index b4a277e..17e5b92 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt @@ -33,14 +33,7 @@ package net.thauvin.erik.mobibot.modules import assertk.all import assertk.assertFailure import assertk.assertThat -import assertk.assertions.hasNoCause -import assertk.assertions.index -import assertk.assertions.isEqualTo -import assertk.assertions.isFailure -import assertk.assertions.isInstanceOf -import assertk.assertions.isNotEmpty -import assertk.assertions.matches -import assertk.assertions.prop +import assertk.assertions.* import net.thauvin.erik.mobibot.ExceptionSanitizer.sanitize import net.thauvin.erik.mobibot.LocalProperties import net.thauvin.erik.mobibot.modules.StockQuote.Companion.getQuote @@ -67,7 +60,7 @@ class StockQuoteTest : LocalProperties() { assertThat(messages, "getQuote($symbol)").index(0).prop(Message::msg).matches("Symbol: AAPL .*".toRegex()) assertThat(messages, "getQuote($symbol)").index(1).prop(Message::msg).matches(buildMatch("Price").toRegex()) assertThat(messages, "getQuote($symbol)").index(2).prop(Message::msg) - .matches(buildMatch("Previous").toRegex()) + .matches(buildMatch("Previous").toRegex()) assertThat(messages, "getQuote($symbol)").index(3).prop(Message::msg).matches(buildMatch("Open").toRegex()) symbol = "blahfoo" diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt index ca650bb..d7d65de 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt @@ -33,16 +33,7 @@ package net.thauvin.erik.mobibot.modules import assertk.all import assertk.assertFailure import assertk.assertThat -import assertk.assertions.contains -import assertk.assertions.endsWith -import assertk.assertions.hasNoCause -import assertk.assertions.index -import assertk.assertions.isEqualTo -import assertk.assertions.isFailure -import assertk.assertions.isInstanceOf -import assertk.assertions.isNotNull -import assertk.assertions.isTrue -import assertk.assertions.prop +import assertk.assertions.* import net.aksingh.owmjapis.api.APIException import net.aksingh.owmjapis.core.OWM import net.thauvin.erik.mobibot.LocalProperties @@ -69,7 +60,7 @@ class Weather2Test : LocalProperties() { assertThat(getCountry("foo"), "foo is not a valid country").isEqualTo(OWM.Country.UNITED_STATES) assertThat(getCountry("fr"), "country should France").isEqualTo(OWM.Country.FRANCE) - val country = OWM.Country.values() + val country = OWM.Country.entries.toTypedArray() repeat(3) { val rand = country[(country.indices).random()] assertThat(getCountry(rand.value), rand.name).isEqualTo(rand) diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt index ae1722d..281d8af 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt @@ -45,11 +45,11 @@ class WolframAlphaTest : LocalProperties() { @Test(groups = ["modules"]) fun testAppId() { assertFailure { queryWolfram("1 gallon to liter", appId = "DEMO") } - .isInstanceOf(ModuleException::class.java) - .hasMessage("Error 1: Invalid appid") + .isInstanceOf(ModuleException::class.java) + .hasMessage("Error 1: Invalid appid") assertFailure { queryWolfram("1 gallon to liter", appId = "") } - .isInstanceOf(ModuleException::class.java) + .isInstanceOf(ModuleException::class.java) } @Test(groups = ["modules", "no-ci"]) @@ -62,8 +62,8 @@ class WolframAlphaTest : LocalProperties() { query = "SFO to LAX" assertThat( - queryWolfram(query, WolframAlpha.METRIC, apiKey), - "queryWolfram($query)" + queryWolfram(query, WolframAlpha.METRIC, apiKey), + "queryWolfram($query)" ).contains("kilometers") } catch (e: ModuleException) { // Avoid displaying api key in CI logs diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt index 46888e3..29f5589 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt @@ -30,10 +30,8 @@ */ package net.thauvin.erik.mobibot.modules -import assertk.assertFailure import assertk.assertThat import assertk.assertions.endsWith -import assertk.assertions.isSuccess import assertk.assertions.matches import assertk.assertions.startsWith import net.thauvin.erik.mobibot.Utils.bold @@ -51,9 +49,9 @@ class WordTimeTest { @Test(groups = ["modules"]) fun testTime() { assertThat(time(), "time()").matches( - ("The time is ${Colors.BOLD}\\d{1,2}:\\d{2}${Colors.BOLD} " + - "on ${Colors.BOLD}\\w+, \\d{1,2} \\w+ \\d{4}${Colors.BOLD} " + - "in ${Colors.BOLD}Los Angeles${Colors.BOLD}").toRegex() + ("The time is ${Colors.BOLD}\\d{1,2}:\\d{2}${Colors.BOLD} " + + "on ${Colors.BOLD}\\w+, \\d{1,2} \\w+ \\d{4}${Colors.BOLD} " + + "in ${Colors.BOLD}Los Angeles${Colors.BOLD}").toRegex() ) assertThat(time(""), "time()").endsWith("Los Angeles".bold()) assertThat(time("PST"), "time(PST)").endsWith("Los Angeles".bold()) diff --git a/version.properties b/version.properties index b464c4e..b7cc5c2 100644 --- a/version.properties +++ b/version.properties @@ -1,9 +1,9 @@ #Generated by the Semver Plugin for Gradle -#Sun Jul 02 02:19:45 PDT 2023 -version.buildmeta=20230702021945 +#Thu Jul 06 10:21:40 PDT 2023 +version.buildmeta=20230706102140 version.major=0 version.minor=8 version.patch=0 version.prerelease=rc version.project=mobibot -version.semver=0.8.0-rc+20230702021945 +version.semver=0.8.0-rc+20230706102140 From c99debd740cb3f50ea742899efef82d4883a6ef8 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" <erik@thauvin.net> Date: Fri, 1 Sep 2023 15:29:45 -0700 Subject: [PATCH 723/844] Updated dependencies --- .gitignore | 1 - .idea/codeStyles/Project.xml | 35 ++++++++++++------ .idea/codeStyles/codeStyleConfig.xml | 1 + .idea/misc.xml | 1 - build.gradle | 18 ++++----- gradle.properties | 0 gradle/wrapper/gradle-wrapper.jar | Bin 63375 -> 63721 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 3 +- .../net/thauvin/erik/mobibot/modules/Joke.kt | 4 +- .../erik/mobibot/modules/CryptoPricesTest.kt | 2 +- version.properties | 6 +-- 12 files changed, 43 insertions(+), 30 deletions(-) create mode 100644 gradle.properties diff --git a/.gitignore b/.gitignore index 2b959f1..970cefd 100644 --- a/.gitignore +++ b/.gitignore @@ -67,7 +67,6 @@ dist/ ehthumbs.db fabric.properties gen/ -gradle.properties hs_err_pid* kobaltBuild kobaltw*-test diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 76b5425..10aa334 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -1,11 +1,17 @@ <component name="ProjectCodeStyleConfiguration"> - <code_scheme name="Project" version="173"> + <code_scheme name="Project" version="200"> <JetCodeStyleSettings> <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" /> </JetCodeStyleSettings> <codeStyleSettings language="JAVA"> <option name="IF_BRACE_FORCE" value="1" /> <arrangement> + <groups> + <group> + <type>OVERRIDDEN_METHODS</type> + <order>BY_NAME</order> + </group> + </groups> <rules> <section> <rule> @@ -17,6 +23,7 @@ <STATIC>true</STATIC> </AND> </match> + <order>BY_NAME</order> </rule> </section> <section> @@ -29,6 +36,7 @@ <STATIC>true</STATIC> </AND> </match> + <order>BY_NAME</order> </rule> </section> <section> @@ -41,6 +49,7 @@ <STATIC>true</STATIC> </AND> </match> + <order>BY_NAME</order> </rule> </section> <section> @@ -53,6 +62,7 @@ <STATIC>true</STATIC> </AND> </match> + <order>BY_NAME</order> </rule> </section> <section> @@ -64,6 +74,7 @@ <STATIC>true</STATIC> </AND> </match> + <order>BY_NAME</order> </rule> </section> <section> @@ -73,8 +84,10 @@ <FIELD>true</FIELD> <PROTECTED>true</PROTECTED> <STATIC>true</STATIC> + <visibility /> </AND> </match> + <order>BY_NAME</order> </rule> </section> <section> @@ -86,6 +99,7 @@ <STATIC>true</STATIC> </AND> </match> + <order>BY_NAME</order> </rule> </section> <section> @@ -97,6 +111,7 @@ <STATIC>true</STATIC> </AND> </match> + <order>BY_NAME</order> </rule> </section> <section> @@ -118,6 +133,7 @@ <PUBLIC>true</PUBLIC> </AND> </match> + <order>BY_NAME</order> </rule> </section> <section> @@ -129,6 +145,7 @@ <PROTECTED>true</PROTECTED> </AND> </match> + <order>BY_NAME</order> </rule> </section> <section> @@ -140,6 +157,7 @@ <PACKAGE_PRIVATE>true</PACKAGE_PRIVATE> </AND> </match> + <order>BY_NAME</order> </rule> </section> <section> @@ -151,6 +169,7 @@ <PRIVATE>true</PRIVATE> </AND> </match> + <order>BY_NAME</order> </rule> </section> <section> @@ -161,6 +180,7 @@ <PUBLIC>true</PUBLIC> </AND> </match> + <order>BY_NAME</order> </rule> </section> <section> @@ -171,6 +191,7 @@ <PROTECTED>true</PROTECTED> </AND> </match> + <order>BY_NAME</order> </rule> </section> <section> @@ -195,21 +216,12 @@ <order>BY_NAME</order> </rule> </section> - <section> - <rule> - <match> - <AND> - <FIELD>true</FIELD> - <PRIVATE>false</PRIVATE> - </AND> - </match> - </rule> - </section> <section> <rule> <match> <FIELD>true</FIELD> </match> + <order>BY_NAME</order> </rule> </section> <section> @@ -234,6 +246,7 @@ <STATIC>true</STATIC> </AND> </match> + <order>BY_NAME</order> </rule> </section> <section> diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml index d91f848..23f4bb5 100644 --- a/.idea/codeStyles/codeStyleConfig.xml +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -1,5 +1,6 @@ <component name="ProjectCodeStyleConfiguration"> <state> + <option name="USE_PER_PROJECT_SETTINGS" value="true" /> <option name="PREFERRED_PROJECT_CODE_STYLE" value="Erik's Code Style" /> </state> </component> \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index f648a66..e7a3cca 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,3 @@ -<?xml version="1.0" encoding="UTF-8"?> <project version="4"> <component name="ExternalStorageConfigurationManager" enabled="true" /> <component name="FrameworkDetectionExcludesConfiguration"> diff --git a/build.gradle b/build.gradle index fa00b54..caf1183 100644 --- a/build.gradle +++ b/build.gradle @@ -7,13 +7,13 @@ plugins { id 'application' id 'com.github.ben-manes.versions' version '0.47.0' id 'idea' - id 'io.gitlab.arturbosch.detekt' version '1.23.0' + id 'io.gitlab.arturbosch.detekt' version '1.23.1' id 'java' id 'net.thauvin.erik.gradle.semver' version '1.0.4' - id 'org.jetbrains.kotlin.jvm' version '1.9.0' - id 'org.jetbrains.kotlin.kapt' version '1.9.0' - id 'org.jetbrains.kotlinx.kover' version '0.7.2' - id 'org.sonarqube' version '4.2.1.3168' + id 'org.jetbrains.kotlin.jvm' version '1.9.10' + id 'org.jetbrains.kotlin.kapt' version '1.9.10' + id 'org.jetbrains.kotlinx.kover' version '0.7.3' + id 'org.sonarqube' version '4.3.1.3277' id 'pmd' } @@ -54,20 +54,20 @@ dependencies { // implementation fileTree(dir: 'lib', include: '*.jar') // Commons (mostly for PircBotX) - implementation 'org.apache.commons:commons-lang3:3.12.0' + implementation 'org.apache.commons:commons-lang3:3.13.0' implementation 'org.apache.commons:commons-text:1.10.0' implementation 'commons-codec:commons-codec:1.16.0' implementation 'commons-net:commons-net:3.9.0' // Google implementation 'com.google.code.gson:gson:2.10.1' - implementation 'com.google.guava:guava:32.1.1-jre' + implementation 'com.google.guava:guava:32.1.2-jre' // Kotlin implementation platform('org.jetbrains.kotlin:kotlin-bom') implementation 'org.jetbrains.kotlin:kotlin-stdlib' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.2' - implementation 'org.jetbrains.kotlinx:kotlinx-cli:0.3.5' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3' + implementation 'org.jetbrains.kotlinx:kotlinx-cli:0.3.6' // Logging implementation 'org.slf4j:slf4j-api:2.0.7' diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..e69de29 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 033e24c4cdf41af1ab109bc7f253b2b887023340..7f93135c49b765f8051ef9d0a6055ff8e46073d8 100644 GIT binary patch delta 28216 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 delta 27891 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 62f495d..ac72c34 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index fcb6fca..0adc8e1 100755 --- a/gradlew +++ b/gradlew @@ -83,7 +83,8 @@ done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Joke.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Joke.kt index a0e8fd4..2760fa7 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Joke.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Joke.kt @@ -32,7 +32,7 @@ package net.thauvin.erik.mobibot.modules import net.thauvin.erik.jokeapi.exceptions.HttpErrorException import net.thauvin.erik.jokeapi.exceptions.JokeException -import net.thauvin.erik.jokeapi.getJoke +import net.thauvin.erik.jokeapi.joke import net.thauvin.erik.jokeapi.models.Type import net.thauvin.erik.mobibot.Utils.bot import net.thauvin.erik.mobibot.Utils.colorize @@ -83,7 +83,7 @@ class Joke : AbstractModule() { @Throws(ModuleException::class) fun randomJoke(): List<Message> { return try { - val joke = getJoke(safe = true, type = Type.SINGLE, splitNewLine = true) + val joke = joke(safe = true, type = Type.SINGLE, splitNewLine = true) joke.joke.map { PublicMessage(it, Colors.CYAN) } } catch (e: JokeException) { throw ModuleException("randomJoke(): ${e.additionalInfo}", e.message, e) diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt index e3475f1..0547c95 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt @@ -72,7 +72,7 @@ class CryptoPricesTest { @Test(groups = ["modules"]) fun testGetCurrencyName() { - assertThat(getCurrencyName("USD"), "USD").isEqualTo("US Dollar") + assertThat(getCurrencyName("USD"), "USD").isEqualTo("United States Dollar") assertThat(getCurrencyName("EUR"), "EUR").isEqualTo("Euro") } } diff --git a/version.properties b/version.properties index b7cc5c2..854597d 100644 --- a/version.properties +++ b/version.properties @@ -1,9 +1,9 @@ #Generated by the Semver Plugin for Gradle -#Thu Jul 06 10:21:40 PDT 2023 -version.buildmeta=20230706102140 +#Fri Sep 01 15:28:31 PDT 2023 +version.buildmeta=20230901152831 version.major=0 version.minor=8 version.patch=0 version.prerelease=rc version.project=mobibot -version.semver=0.8.0-rc+20230706102140 +version.semver=0.8.0-rc+20230901152831 From 65fa55d51f20af2405692feb428171e2b6d99d5d Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" <erik@thauvin.net> Date: Fri, 22 Sep 2023 03:05:10 -0700 Subject: [PATCH 724/844] Updated dependencies --- .idea/kotlinc.xml | 2 +- build.gradle | 8 ++++---- src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt | 5 +++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index fdf8d99..f8467b4 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <project version="4"> <component name="KotlinJpsPluginSettings"> - <option name="version" value="1.9.0" /> + <option name="version" value="1.9.10" /> </component> </project> \ No newline at end of file diff --git a/build.gradle b/build.gradle index caf1183..d5a1151 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ import io.gitlab.arturbosch.detekt.DetektCreateBaselineTask plugins { id 'application' - id 'com.github.ben-manes.versions' version '0.47.0' + id 'com.github.ben-manes.versions' version '0.48.0' id 'idea' id 'io.gitlab.arturbosch.detekt' version '1.23.1' id 'java' @@ -70,7 +70,7 @@ dependencies { implementation 'org.jetbrains.kotlinx:kotlinx-cli:0.3.6' // Logging - implementation 'org.slf4j:slf4j-api:2.0.7' + implementation 'org.slf4j:slf4j-api:2.0.9' implementation "org.apache.logging.log4j:log4j-api:$versions.log4j" implementation "org.apache.logging.log4j:log4j-core:$versions.log4j" implementation "org.apache.logging.log4j:log4j-slf4j2-impl:$versions.log4j" @@ -86,9 +86,9 @@ dependencies { implementation 'net.thauvin.erik:cryptoprice:1.0.0' implementation 'net.thauvin.erik:jokeapi:0.9-SNAPSHOT' implementation 'net.thauvin.erik:pinboard-poster:1.0.3' - implementation 'net.thauvin.erik:urlencoder:1.3.0' + implementation 'net.thauvin.erik.urlencoder:urlencoder-lib:1.4.0' - testImplementation 'com.willowtreeapps.assertk:assertk-jvm:0.26.1' + testImplementation 'com.willowtreeapps.assertk:assertk-jvm:0.27.0' // testImplementation 'org.mockito.kotlin:mockito-kotlin:4.0.0' // testImplementation "org.mockito:mockito-core:4.0.0" testImplementation 'org.testng:testng:7.8.0' diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt index 0595220..51adc88 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt @@ -32,7 +32,7 @@ package net.thauvin.erik.mobibot import net.thauvin.erik.mobibot.msg.Message import net.thauvin.erik.mobibot.msg.Message.Companion.DEFAULT_COLOR -import net.thauvin.erik.urlencoder.UrlEncoder +import net.thauvin.erik.urlencoder.UrlEncoderUtil import org.jsoup.Jsoup import org.pircbotx.Colors import org.pircbotx.PircBotX @@ -42,6 +42,7 @@ import org.slf4j.Logger import java.io.* import java.net.HttpURLConnection import java.net.URL +import java.net.URLEncoder import java.nio.file.Files import java.nio.file.Paths import java.time.LocalDateTime @@ -145,7 +146,7 @@ object Utils { * URL encodes the given string. */ @JvmStatic - fun String.encodeUrl(): String = UrlEncoder.encode(this) + fun String.encodeUrl(): String = UrlEncoderUtil.encode(this) /** * Returns a property as an int. From 8fb872ad6fca07974e8143cdfc38895defcf1ee5 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" <erik@thauvin.net> Date: Fri, 22 Sep 2023 03:06:08 -0700 Subject: [PATCH 725/844] Switched to ExchangeRate-API --- config/detekt/baseline.xml | 3 +- properties/mobibot.properties | 6 ++ .../erik/mobibot/modules/CurrencyConverter.kt | 80 ++++++++++++------- .../mobibot/modules/CurrencyConverterTest.kt | 26 +++--- 4 files changed, 72 insertions(+), 43 deletions(-) diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml index f7cc151..9f157cf 100644 --- a/config/detekt/baseline.xml +++ b/config/detekt/baseline.xml @@ -59,7 +59,8 @@ <ID>NestedBlockDepth:Addons.kt$Addons$fun add(module: AbstractModule): Boolean</ID> <ID>NestedBlockDepth:ChatGpt.kt$ChatGpt.Companion$@JvmStatic @Throws(ModuleException::class) fun chat(query: String, apiKey: String?, maxTokens: Int): String</ID> <ID>NestedBlockDepth:Comment.kt$Comment$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent)</ID> - <ID>NestedBlockDepth:CurrencyConverter.kt$CurrencyConverter.Companion$@JvmStatic fun convertCurrency(query: String): Message</ID> + <ID>NestedBlockDepth:CurrencyConverter.kt$CurrencyConverter.Companion$@JvmStatic @Throws(ModuleException::class) fun loadSymbols(apiKey: String?)</ID> + <ID>NestedBlockDepth:CurrencyConverter.kt$CurrencyConverter.Companion$@JvmStatic fun convertCurrency(apiKey: String?, query: String): Message</ID> <ID>NestedBlockDepth:EntryLink.kt$EntryLink$private fun setTags(tags: List<String?>)</ID> <ID>NestedBlockDepth:FeedsManager.kt$FeedsManager.Companion$@JvmStatic @Throws(IOException::class, FeedException::class) fun loadFeed(entries: Entries, currentFile: String = currentXml): String</ID> <ID>NestedBlockDepth:FeedsManager.kt$FeedsManager.Companion$@JvmStatic fun saveFeed(entries: Entries, currentFile: String = currentXml)</ID> diff --git a/properties/mobibot.properties b/properties/mobibot.properties index fa8ce50..24d9977 100644 --- a/properties/mobibot.properties +++ b/properties/mobibot.properties @@ -45,6 +45,12 @@ disabled-modules=mastodon # Automatically post links to Mastodon #mastodon-auto-post=true + +# +# Get Exchange Rate API key from: https://www.exchangerate-api.com/ +# +#exchangerate-api-key= + # # Create custom search engine at: https://programmablesearchengine.google.com/ # and get API key from: https://console.cloud.google.com/apis diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt index 0bf9d7a..284f9d2 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt @@ -44,6 +44,7 @@ import org.pircbotx.hooks.types.GenericMessageEvent import org.slf4j.Logger import org.slf4j.LoggerFactory import java.io.IOException +import java.math.BigDecimal import java.net.URL import java.util.* @@ -57,10 +58,10 @@ class CurrencyConverter : AbstractModule() { override val name = "CurrencyConverter" // Reload currency codes - private fun reload() { - if (SYMBOLS.isEmpty()) { + private fun reload(apiKey: String?) { + if (!apiKey.isNullOrEmpty() && SYMBOLS.isEmpty()) { try { - loadSymbols() + loadSymbols(apiKey) } catch (e: ModuleException) { if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) } @@ -71,12 +72,12 @@ class CurrencyConverter : AbstractModule() { * Converts the specified currencies. */ override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - reload() + reload(properties[API_KEY_PROP]) if (SYMBOLS.isEmpty()) { event.respond(EMPTY_SYMBOLS_TABLE) } else if (args.matches("\\d+([,\\d]+)?(\\.\\d+)? [a-zA-Z]{3}+ to [a-zA-Z]{3}+".toRegex())) { - val msg = convertCurrency(args) + val msg = convertCurrency(properties[API_KEY_PROP], args) event.respond(msg.msg) if (msg.isError) { helpResponse(event) @@ -90,7 +91,7 @@ class CurrencyConverter : AbstractModule() { } override fun helpResponse(event: GenericMessageEvent): Boolean { - reload() + reload(properties[API_KEY_PROP]) if (SYMBOLS.isEmpty()) { event.sendMessage(EMPTY_SYMBOLS_TABLE) @@ -99,21 +100,26 @@ class CurrencyConverter : AbstractModule() { event.sendMessage("To convert from one currency to another:") event.sendMessage(helpFormat(helpCmdSyntax("%c $CURRENCY_CMD 100 USD to EUR", nick, isPrivateMsgEnabled))) event.sendMessage( - helpFormat( - helpCmdSyntax("%c $CURRENCY_CMD 50,000 GBP to BTC", nick, isPrivateMsgEnabled) - ) + helpFormat( + helpCmdSyntax("%c $CURRENCY_CMD 50,000 GBP to BTC", nick, isPrivateMsgEnabled) + ) ) event.sendMessage("To list the supported currency codes:") event.sendMessage( - helpFormat( - helpCmdSyntax("%c $CURRENCY_CMD $CODES_KEYWORD", nick, isPrivateMsgEnabled) - ) + helpFormat( + helpCmdSyntax("%c $CURRENCY_CMD $CODES_KEYWORD", nick, isPrivateMsgEnabled) + ) ) } return true } companion object { + /** + * The API Key property. + */ + const val API_KEY_PROP = "exchangerate-api-key" + // Currency command private const val CURRENCY_CMD = "currency" @@ -130,7 +136,11 @@ class CurrencyConverter : AbstractModule() { * Converts from a currency to another. */ @JvmStatic - fun convertCurrency(query: String): Message { + fun convertCurrency(apiKey: String?, query: String): Message { + if (apiKey.isNullOrEmpty()) { + throw ModuleException("${CURRENCY_CMD}($query)", "No Exchange Rate API key specified.") + } + val cmds = query.split(" ") return if (cmds.size == 4) { if (cmds[3] == cmds[1] || "0" == cmds[0]) { @@ -141,12 +151,14 @@ class CurrencyConverter : AbstractModule() { if (SYMBOLS.contains(to) && SYMBOLS.contains(from)) { try { val amt = cmds[0].replace(",", "") - val url = URL("https://api.exchangerate.host/convert?from=$to&to=$from&amount=$amt") - val json = JSONObject(url.reader().body) + val url = URL("https://v6.exchangerate-api.com/v6/$apiKey/pair/$to/$from/$amt") + val body = url.reader().body + val json = JSONObject(body) - if (json.getBoolean("success")) { + if (json.getString("result") == "success") { + val result = json.getDouble("conversion_result") PublicMessage( - "${cmds[0]} ${SYMBOLS[to]} = ${json.get("result")} ${SYMBOLS[from]}" + "${cmds[0]} ${SYMBOLS[to]} = $result ${SYMBOLS[from]}" ) } else { ErrorMessage("Sorry, an error occurred while converting the currencies.") @@ -158,7 +170,9 @@ class CurrencyConverter : AbstractModule() { ErrorMessage("Sounds like monopoly money to me!") } } - } else ErrorMessage("Invalid query. Let's try again.") + } else { + ErrorMessage("Invalid query. Let's try again.") + } } /** @@ -166,28 +180,32 @@ class CurrencyConverter : AbstractModule() { */ @JvmStatic @Throws(ModuleException::class) - fun loadSymbols() { - try { - val url = URL("https://api.exchangerate.host/symbols") - val json = JSONObject(url.reader().body) - if (json.getBoolean("success")) { - val symbols = json.getJSONObject("symbols") - for (key in symbols.keys()) { - SYMBOLS[key] = symbols.getJSONObject(key).getString("description") + fun loadSymbols(apiKey: String?) { + if (!apiKey.isNullOrEmpty()) { + try { + val url = URL("https://v6.exchangerate-api.com/v6/$apiKey/codes") + val json = JSONObject(url.reader().body) + if (json.getString("result") == "success") { + val codes = json.getJSONArray("supported_codes") + for (i in 0 until codes.length()) { + val code = codes.getJSONArray(i); + SYMBOLS[code.getString(0)] = code.getString(1); + } } - } - } catch (e: IOException) { - throw ModuleException( + } catch (e: IOException) { + throw ModuleException( "loadCodes(): IOE", "An IO error has occurred while retrieving the currencies.", e - ) + ) + } } } } init { commands.add(CURRENCY_CMD) - loadSymbols() + initProperties(API_KEY_PROP) + loadSymbols(properties[ChatGpt.API_KEY_PROP]) } } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt index 10a2470..59ea2e7 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt @@ -36,6 +36,7 @@ import assertk.assertions.contains import assertk.assertions.isInstanceOf import assertk.assertions.matches import assertk.assertions.prop +import net.thauvin.erik.mobibot.LocalProperties import net.thauvin.erik.mobibot.modules.CurrencyConverter.Companion.convertCurrency import net.thauvin.erik.mobibot.modules.CurrencyConverter.Companion.loadSymbols import net.thauvin.erik.mobibot.msg.ErrorMessage @@ -48,32 +49,35 @@ import org.testng.annotations.Test /** * The `CurrencyConvertTest` class. */ -class CurrencyConverterTest { +class CurrencyConverterTest: LocalProperties() { + @BeforeClass @Throws(ModuleException::class) fun before() { - loadSymbols() + val apiKey = getProperty(CurrencyConverter.API_KEY_PROP) + loadSymbols(apiKey) } @Test(groups = ["modules"]) fun testConvertCurrency() { + val apiKey = getProperty(CurrencyConverter.API_KEY_PROP) assertThat( - convertCurrency("100 USD to EUR").msg, + convertCurrency(apiKey,"100 USD to EUR").msg, "convertCurrency(100 USD to EUR)" ).matches("100 United States Dollar = \\d{2,3}\\.\\d+ Euro".toRegex()) assertThat( - convertCurrency("1 USD to BTC").msg, - "convertCurrency(1 USD to BTC)" - ).matches("1 United States Dollar = 0\\.\\d+ Bitcoin".toRegex()) + convertCurrency(apiKey,"1 USD to GBP").msg, + "convertCurrency(1 USD to BGP)" + ).matches("1 United States Dollar = 0\\.\\d+ Pound Sterling".toRegex()) assertThat( - convertCurrency("100,000.00 GBP to BTC").msg, - "convertCurrency(100,000.00 GBP to BTC)" - ).matches("100,000.00 British Pound Sterling = \\d{1,2}\\.\\d+ Bitcoin".toRegex()) - assertThat(convertCurrency("100 USD to USD"), "convertCurrency(100 USD to USD)").all { + convertCurrency(apiKey,"100,000.00 CAD to USD").msg, + "convertCurrency(100,000.00 GBP to USD)" + ).matches("100,000.00 Canadian Dollar = \\d+\\.\\d+ United States Dollar".toRegex()) + assertThat(convertCurrency(apiKey,"100 USD to USD"), "convertCurrency(100 USD to USD)").all { prop(Message::msg).contains("You're kidding, right?") isInstanceOf(PublicMessage::class.java) } - assertThat(convertCurrency("100 USD"), "convertCurrency(100 USD)").all { + assertThat(convertCurrency(apiKey,"100 USD"), "convertCurrency(100 USD)").all { prop(Message::msg).contains("Invalid query.") isInstanceOf(ErrorMessage::class.java) } From 8b6384627025b93d9dae9953006d48bbe4919573 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" <erik@thauvin.net> Date: Fri, 22 Sep 2023 04:21:24 -0700 Subject: [PATCH 726/844] Added ExchangeRate-API enviornment variable --- .github/workflows/gradle.yml | 1 + version.properties | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index c917819..aa034f9 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -47,6 +47,7 @@ jobs: MASTODON_ACCESS_TOKEN: ${{ secrets.MASTODON_ACCESS_TOKEN }} MASTODON_HANDLE: ${{ secrets.MASTODON_HANDLE }} MASTODON_INSTANCE: ${{ secrets.MASTODON_INSTANCE }} + EXCHANGERATE_API_KEY: ${{ secrets.EXCHANGERATE_API_KEY }} with: arguments: build check --stacktrace diff --git a/version.properties b/version.properties index 854597d..f272017 100644 --- a/version.properties +++ b/version.properties @@ -1,9 +1,9 @@ #Generated by the Semver Plugin for Gradle -#Fri Sep 01 15:28:31 PDT 2023 -version.buildmeta=20230901152831 +#Fri Sep 22 04:02:33 PDT 2023 +version.buildmeta=20230922040233 version.major=0 version.minor=8 version.patch=0 version.prerelease=rc version.project=mobibot -version.semver=0.8.0-rc+20230901152831 +version.semver=0.8.0-rc+20230922040233 From bc8bf6bf57247a81a934df3a435063c17d95697e Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" <erik@thauvin.net> Date: Wed, 4 Oct 2023 08:55:48 -0700 Subject: [PATCH 727/844] Added date format to currency converter response. --- .idea/misc.xml | 2 ++ build.gradle | 13 +++++++------ .../erik/mobibot/modules/CurrencyConverter.kt | 13 ++++++++----- version.properties | 6 +++--- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index e7a3cca..67f5457 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,3 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> <project version="4"> <component name="ExternalStorageConfigurationManager" enabled="true" /> <component name="FrameworkDetectionExcludesConfiguration"> @@ -7,6 +8,7 @@ <option name="customRuleSets"> <list> <option value="K:\java\semver\config\pmd.xml" /> + <option value="$PROJECT_DIR$/../../java/bld-exec/config/pmd.xml" /> </list> </option> <option name="skipTestSources" value="false" /> diff --git a/build.gradle b/build.gradle index d5a1151..7e13746 100644 --- a/build.gradle +++ b/build.gradle @@ -13,7 +13,7 @@ plugins { id 'org.jetbrains.kotlin.jvm' version '1.9.10' id 'org.jetbrains.kotlin.kapt' version '1.9.10' id 'org.jetbrains.kotlinx.kover' version '0.7.3' - id 'org.sonarqube' version '4.3.1.3277' + id 'org.sonarqube' version '4.4.1.3373' id 'pmd' } @@ -21,7 +21,7 @@ defaultTasks 'deploy' final def packageName = 'net.thauvin.erik.mobibot' final def deployDir = 'deploy' -final def semverProcessor = "net.thauvin.erik:semver:1.2.0" +final def semverProcessor = "net.thauvin.erik:semver:1.2.1" final def isCI = (System.getenv('CI') != null) @@ -77,15 +77,16 @@ dependencies { implementation 'com.rometools:rome:2.1.0' implementation 'com.squareup.okhttp3:okhttp:4.11.0' + implementation 'com.squareup.okio:okio:3.6.0' implementation 'net.aksingh:owm-japis:2.5.3.0' implementation 'net.objecthunter:exp4j:0.4.8' implementation 'org.json:json:20230618' implementation 'org.jsoup:jsoup:1.16.1' // Thauvin - implementation 'net.thauvin.erik:cryptoprice:1.0.0' - implementation 'net.thauvin.erik:jokeapi:0.9-SNAPSHOT' - implementation 'net.thauvin.erik:pinboard-poster:1.0.3' + implementation 'net.thauvin.erik:cryptoprice:1.0.1' + implementation 'net.thauvin.erik:jokeapi:0.9.0' + implementation 'net.thauvin.erik:pinboard-poster:1.1.0' implementation 'net.thauvin.erik.urlencoder:urlencoder-lib:1.4.0' testImplementation 'com.willowtreeapps.assertk:assertk-jvm:0.27.0' @@ -211,7 +212,7 @@ sonarqube { property('sonar.organization', 'ethauvin-github') property('sonar.projectKey', 'ethauvin_mobibot') property('sonar.host.url', 'https://sonarcloud.io') - property('sonar.coverage.jacoco.xmlReportPaths', "${project.buildDir}/reports/kover/report.xml") + property('sonar.coverage.jacoco.xmlReportPaths', "${layout.buildDirectory.get()}/reports/kover/report.xml") } } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt index 284f9d2..fc56d42 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt @@ -44,8 +44,8 @@ import org.pircbotx.hooks.types.GenericMessageEvent import org.slf4j.Logger import org.slf4j.LoggerFactory import java.io.IOException -import java.math.BigDecimal import java.net.URL +import java.text.DecimalFormat import java.util.* @@ -101,7 +101,7 @@ class CurrencyConverter : AbstractModule() { event.sendMessage(helpFormat(helpCmdSyntax("%c $CURRENCY_CMD 100 USD to EUR", nick, isPrivateMsgEnabled))) event.sendMessage( helpFormat( - helpCmdSyntax("%c $CURRENCY_CMD 50,000 GBP to BTC", nick, isPrivateMsgEnabled) + helpCmdSyntax("%c $CURRENCY_CMD 50,000 GBP to USD", nick, isPrivateMsgEnabled) ) ) event.sendMessage("To list the supported currency codes:") @@ -132,6 +132,9 @@ class CurrencyConverter : AbstractModule() { // Currency symbols private val SYMBOLS: TreeMap<String, String> = TreeMap() + // Decimal format + private val DECIMAL_FORMAT = DecimalFormat("0.00") + /** * Converts from a currency to another. */ @@ -156,7 +159,7 @@ class CurrencyConverter : AbstractModule() { val json = JSONObject(body) if (json.getString("result") == "success") { - val result = json.getDouble("conversion_result") + val result = DECIMAL_FORMAT.format(json.getDouble("conversion_result")) PublicMessage( "${cmds[0]} ${SYMBOLS[to]} = $result ${SYMBOLS[from]}" ) @@ -188,8 +191,8 @@ class CurrencyConverter : AbstractModule() { if (json.getString("result") == "success") { val codes = json.getJSONArray("supported_codes") for (i in 0 until codes.length()) { - val code = codes.getJSONArray(i); - SYMBOLS[code.getString(0)] = code.getString(1); + val code = codes.getJSONArray(i) + SYMBOLS[code.getString(0)] = code.getString(1) } } } catch (e: IOException) { diff --git a/version.properties b/version.properties index f272017..1765f9b 100644 --- a/version.properties +++ b/version.properties @@ -1,9 +1,9 @@ #Generated by the Semver Plugin for Gradle -#Fri Sep 22 04:02:33 PDT 2023 -version.buildmeta=20230922040233 +#Wed Oct 04 08:46:27 PDT 2023 +version.buildmeta=20231004084627 version.major=0 version.minor=8 version.patch=0 version.prerelease=rc version.project=mobibot -version.semver=0.8.0-rc+20230922040233 +version.semver=0.8.0-rc+20231004084627 From b562b674a776a7a108f38c6f31accce1694aad6e Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" <erik@thauvin.net> Date: Fri, 13 Oct 2023 12:37:20 -0700 Subject: [PATCH 728/844] Updated dependencies --- build.gradle | 8 ++++---- gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 14 +++++++------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/build.gradle b/build.gradle index 7e13746..4bd1a08 100644 --- a/build.gradle +++ b/build.gradle @@ -5,14 +5,14 @@ import io.gitlab.arturbosch.detekt.DetektCreateBaselineTask plugins { id 'application' - id 'com.github.ben-manes.versions' version '0.48.0' + id 'com.github.ben-manes.versions' version '0.49.0' id 'idea' id 'io.gitlab.arturbosch.detekt' version '1.23.1' id 'java' id 'net.thauvin.erik.gradle.semver' version '1.0.4' id 'org.jetbrains.kotlin.jvm' version '1.9.10' id 'org.jetbrains.kotlin.kapt' version '1.9.10' - id 'org.jetbrains.kotlinx.kover' version '0.7.3' + id 'org.jetbrains.kotlinx.kover' version '0.7.4' id 'org.sonarqube' version '4.4.1.3373' id 'pmd' } @@ -57,11 +57,11 @@ dependencies { implementation 'org.apache.commons:commons-lang3:3.13.0' implementation 'org.apache.commons:commons-text:1.10.0' implementation 'commons-codec:commons-codec:1.16.0' - implementation 'commons-net:commons-net:3.9.0' + implementation 'commons-net:commons-net:3.10.0' // Google implementation 'com.google.code.gson:gson:2.10.1' - implementation 'com.google.guava:guava:32.1.2-jre' + implementation 'com.google.guava:guava:32.1.3-jre' // Kotlin implementation platform('org.jetbrains.kotlin:kotlin-bom') diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ac72c34..3fa8f86 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 0adc8e1..1aa94a4 100755 --- a/gradlew +++ b/gradlew @@ -145,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -153,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -202,11 +202,11 @@ fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ From 5a3b1d3f1912eb2b68090ec0733afa11000a3240 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" <erik@thauvin.net> Date: Fri, 13 Oct 2023 12:37:55 -0700 Subject: [PATCH 729/844] Changed decimal formatting --- .../net/thauvin/erik/mobibot/modules/CurrencyConverter.kt | 2 +- .../thauvin/erik/mobibot/modules/CurrencyConverterTest.kt | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt index fc56d42..41cb995 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt @@ -133,7 +133,7 @@ class CurrencyConverter : AbstractModule() { private val SYMBOLS: TreeMap<String, String> = TreeMap() // Decimal format - private val DECIMAL_FORMAT = DecimalFormat("0.00") + private val DECIMAL_FORMAT = DecimalFormat("0.00#") /** * Converts from a currency to another. diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt index 59ea2e7..4ee9668 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt @@ -64,15 +64,15 @@ class CurrencyConverterTest: LocalProperties() { assertThat( convertCurrency(apiKey,"100 USD to EUR").msg, "convertCurrency(100 USD to EUR)" - ).matches("100 United States Dollar = \\d{2,3}\\.\\d+ Euro".toRegex()) + ).matches("100 United States Dollar = \\d{2,3}\\.\\d{2,3} Euro".toRegex()) assertThat( convertCurrency(apiKey,"1 USD to GBP").msg, "convertCurrency(1 USD to BGP)" - ).matches("1 United States Dollar = 0\\.\\d+ Pound Sterling".toRegex()) + ).matches("1 United States Dollar = 0\\.\\d{2,3} Pound Sterling".toRegex()) assertThat( convertCurrency(apiKey,"100,000.00 CAD to USD").msg, "convertCurrency(100,000.00 GBP to USD)" - ).matches("100,000.00 Canadian Dollar = \\d+\\.\\d+ United States Dollar".toRegex()) + ).matches("100,000.00 Canadian Dollar = \\d+\\.\\d{2,3} United States Dollar".toRegex()) assertThat(convertCurrency(apiKey,"100 USD to USD"), "convertCurrency(100 USD to USD)").all { prop(Message::msg).contains("You're kidding, right?") isInstanceOf(PublicMessage::class.java) From 105850990b8b7b185088d54def99b21817513431 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" <erik@thauvin.net> Date: Fri, 13 Oct 2023 13:34:30 -0700 Subject: [PATCH 730/844] Updated versions --- README.md | 2 +- version.properties | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index df026ab..1ecefeb 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # mobibot [![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) -[![Kotlin](https://img.shields.io/badge/kotlin-1.9.0-7f52ff.svg)](https://kotlinlang.org) +[![Kotlin](https://img.shields.io/badge/kotlin-1.9.10-7f52ff.svg)](https://kotlinlang.org) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ethauvin_mobibot&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=ethauvin_mobibot) [![GitHub CI](https://github.com/ethauvin/mobibot/actions/workflows/gradle.yml/badge.svg)](https://github.com/ethauvin/mobibot/actions/workflows/gradle.yml) [![CircleCI](https://circleci.com/gh/ethauvin/mobibot/tree/master.svg?style=shield)](https://circleci.com/gh/ethauvin/mobibot/tree/master) diff --git a/version.properties b/version.properties index 1765f9b..8b93b12 100644 --- a/version.properties +++ b/version.properties @@ -1,9 +1,9 @@ #Generated by the Semver Plugin for Gradle -#Wed Oct 04 08:46:27 PDT 2023 -version.buildmeta=20231004084627 +#Fri Oct 13 13:31:20 PDT 2023 +version.buildmeta=20231013133120 version.major=0 version.minor=8 version.patch=0 version.prerelease=rc version.project=mobibot -version.semver=0.8.0-rc+20231004084627 +version.semver=0.8.0-rc+20231013133120 From 86b35874bfb6f5ec5f259cfbc3c1c54cc6a2d20c Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" <erik@thauvin.net> Date: Fri, 13 Oct 2023 13:35:19 -0700 Subject: [PATCH 731/844] Using lorem-rss instead of my server for testing --- src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt index 7611ae3..51e2296 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt @@ -54,12 +54,13 @@ class FeedReaderTest { index(1).prop(Message::msg).contains("erik.thauvin.net") } - messages = readFeed("https://www.mobitopia.org/mobibot/logs/2021-10-27.xml") + messages = readFeed("https://lorem-rss.herokuapp.com/feed?length=0") assertThat(messages, "messages").index(0).prop(Message::msg).contains("nothing") - messages = readFeed("https://www.mobitopia.org/mobibot/logs/2005-10-11.xml", 42) + messages = readFeed("https://lorem-rss.herokuapp.com/feed?length=84", 42) assertThat(messages, "messages").size().isEqualTo(84) - assertThat(messages.last(), "messages.last").prop(Message::msg).contains("techdigest.tv") + assertThat(messages[messages.size - 2], "messages.size - 2").prop(Message::msg).startsWith("Lorem ipsum") + assertThat(messages.last(), "messages.last").prop(Message::msg).contains("http://example.com/test/") assertFailure { readFeed("blah") }.isInstanceOf(MalformedURLException::class.java) From 8e37c3912a5d14bc35a17ad61c67238a856e6fd1 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" <erik@thauvin.net> Date: Tue, 17 Oct 2023 13:26:24 -0700 Subject: [PATCH 732/844] Improved feed reader testing --- .../net/thauvin/erik/mobibot/FeedReaderTest.kt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt index 51e2296..78f5b18 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt @@ -59,8 +59,13 @@ class FeedReaderTest { messages = readFeed("https://lorem-rss.herokuapp.com/feed?length=84", 42) assertThat(messages, "messages").size().isEqualTo(84) - assertThat(messages[messages.size - 2], "messages.size - 2").prop(Message::msg).startsWith("Lorem ipsum") - assertThat(messages.last(), "messages.last").prop(Message::msg).contains("http://example.com/test/") + messages.forEachIndexed { i, m -> + if (i % 2 == 0) { + assertThat(m, "messages($i)").prop(Message::msg).startsWith("Lorem ipsum") + } else { + assertThat(m, "messages($i)").prop(Message::msg).contains("http://example.com/test/") + } + } assertFailure { readFeed("blah") }.isInstanceOf(MalformedURLException::class.java) @@ -68,7 +73,6 @@ class FeedReaderTest { assertFailure { readFeed("https://www.thauvin.net/foo") }.isInstanceOf(IOException::class.java) - assertFailure { readFeed("https://www.examplesfoo.com/") } - .isInstanceOf(UnknownHostException::class.java) + assertFailure { readFeed("https://www.examplesfoo.com/") }.isInstanceOf(UnknownHostException::class.java) } } From abebca50796430694d12eecd478d5399c78377a9 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" <erik@thauvin.net> Date: Tue, 17 Oct 2023 13:26:43 -0700 Subject: [PATCH 733/844] Updated dependencies --- build.gradle | 4 ++-- version.properties | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index 4bd1a08..75db38b 100644 --- a/build.gradle +++ b/build.gradle @@ -34,7 +34,7 @@ def isNonStable = { String version -> mainClassName = packageName + '.Mobibot' ext.versions = [ - log4j: '2.20.0', + log4j: '2.21.0', pmd : '6.55.0', ] @@ -80,7 +80,7 @@ dependencies { implementation 'com.squareup.okio:okio:3.6.0' implementation 'net.aksingh:owm-japis:2.5.3.0' implementation 'net.objecthunter:exp4j:0.4.8' - implementation 'org.json:json:20230618' + implementation 'org.json:json:20231013' implementation 'org.jsoup:jsoup:1.16.1' // Thauvin diff --git a/version.properties b/version.properties index 8b93b12..ad204e5 100644 --- a/version.properties +++ b/version.properties @@ -1,9 +1,9 @@ #Generated by the Semver Plugin for Gradle -#Fri Oct 13 13:31:20 PDT 2023 -version.buildmeta=20231013133120 +#Fri Oct 13 20:37:28 PDT 2023 +version.buildmeta=20231013203728 version.major=0 version.minor=8 version.patch=0 version.prerelease=rc version.project=mobibot -version.semver=0.8.0-rc+20231013133120 +version.semver=0.8.0-rc+20231013203728 From acaa27f20de4ba34ee3d18d07071d38dae8ea2d0 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" <erik@thauvin.net> Date: Thu, 26 Oct 2023 20:46:36 -0700 Subject: [PATCH 734/844] Added support for currency X in Y command --- .../net/thauvin/erik/mobibot/modules/CurrencyConverter.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt index 41cb995..c194571 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt @@ -76,7 +76,7 @@ class CurrencyConverter : AbstractModule() { if (SYMBOLS.isEmpty()) { event.respond(EMPTY_SYMBOLS_TABLE) - } else if (args.matches("\\d+([,\\d]+)?(\\.\\d+)? [a-zA-Z]{3}+ to [a-zA-Z]{3}+".toRegex())) { + } else if (args.matches("\\d+([,\\d]+)?(\\.\\d+)? [a-zA-Z]{3}+ (to|in) [a-zA-Z]{3}+".toRegex())) { val msg = convertCurrency(properties[API_KEY_PROP], args) event.respond(msg.msg) if (msg.isError) { From adaff5ec38a809545b6b2832a8665a228600c2a4 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" <erik@thauvin.net> Date: Thu, 26 Oct 2023 20:46:53 -0700 Subject: [PATCH 735/844] Updated dependencies --- build.gradle | 7 +++---- version.properties | 6 +++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/build.gradle b/build.gradle index 75db38b..9fb85c6 100644 --- a/build.gradle +++ b/build.gradle @@ -34,7 +34,7 @@ def isNonStable = { String version -> mainClassName = packageName + '.Mobibot' ext.versions = [ - log4j: '2.21.0', + log4j: '2.21.1', pmd : '6.55.0', ] @@ -76,12 +76,11 @@ dependencies { implementation "org.apache.logging.log4j:log4j-slf4j2-impl:$versions.log4j" implementation 'com.rometools:rome:2.1.0' - implementation 'com.squareup.okhttp3:okhttp:4.11.0' - implementation 'com.squareup.okio:okio:3.6.0' + implementation 'com.squareup.okhttp3:okhttp:4.12.0' implementation 'net.aksingh:owm-japis:2.5.3.0' implementation 'net.objecthunter:exp4j:0.4.8' implementation 'org.json:json:20231013' - implementation 'org.jsoup:jsoup:1.16.1' + implementation 'org.jsoup:jsoup:1.16.2' // Thauvin implementation 'net.thauvin.erik:cryptoprice:1.0.1' diff --git a/version.properties b/version.properties index ad204e5..c73da9e 100644 --- a/version.properties +++ b/version.properties @@ -1,9 +1,9 @@ #Generated by the Semver Plugin for Gradle -#Fri Oct 13 20:37:28 PDT 2023 -version.buildmeta=20231013203728 +#Thu Oct 26 20:43:39 PDT 2023 +version.buildmeta=20231026204339 version.major=0 version.minor=8 version.patch=0 version.prerelease=rc version.project=mobibot -version.semver=0.8.0-rc+20231013203728 +version.semver=0.8.0-rc+20231026204339 From d700aa06dfe785ab6dee411482f5866d554f6440 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" <erik@thauvin.net> Date: Thu, 26 Oct 2023 21:13:46 -0700 Subject: [PATCH 736/844] Fixed SonarCloud code smells --- .idea/misc.xml | 1 - .../kotlin/net/thauvin/erik/mobibot/Utils.kt | 22 ++++++++------- .../thauvin/erik/mobibot/commands/Ignore.kt | 2 +- .../erik/mobibot/commands/tell/Tell.kt | 27 +++++++++++-------- .../erik/mobibot/entries/FeedsManager.kt | 2 +- .../erik/mobibot/modules/CurrencyConverter.kt | 27 +++++++++++-------- 6 files changed, 47 insertions(+), 34 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index 67f5457..a59e398 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,3 @@ -<?xml version="1.0" encoding="UTF-8"?> <project version="4"> <component name="ExternalStorageConfigurationManager" enabled="true" /> <component name="FrameworkDetectionExcludesConfiguration"> diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt index 51adc88..38b89e3 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt @@ -42,7 +42,6 @@ import org.slf4j.Logger import java.io.* import java.net.HttpURLConnection import java.net.URL -import java.net.URLEncoder import java.nio.file.Files import java.nio.file.Paths import java.time.LocalDateTime @@ -125,14 +124,19 @@ object Utils { */ @JvmStatic fun String?.colorize(color: String): String { - return if (isNullOrEmpty()) { - "" - } else if (color == DEFAULT_COLOR) { - this - } else if (Colors.BOLD == color || Colors.REVERSE == color) { - color + this + color - } else { - color + this + Colors.NORMAL + return when { + isNullOrEmpty() -> { + "" + } + color == DEFAULT_COLOR -> { + this + } + Colors.BOLD == color || Colors.REVERSE == color -> { + color + this + color + } + else -> { + color + this + Colors.NORMAL + } } } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt index 88109e8..723108d 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt @@ -129,7 +129,7 @@ class Ignore : AbstractCommand() { } } - if (ignored.size > 0) { + if (ignored.isNotEmpty()) { event.sendMessage("The following nicks are ignored:") event.sendList(ignored.sorted(), 8, isIndent = true) } else { diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt index 96800bb..cdeb943 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt @@ -85,18 +85,23 @@ class Tell(private val serialObject: String) : AbstractCommand() { override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { if (isEnabled()) { - if (args.isBlank()) { - helpResponse(channel, args, event) - } else if (args.startsWith(View.VIEW_CMD)) { - if (event.isChannelOp(channel) && "${View.VIEW_CMD} $TELL_ALL_KEYWORD" == args) { - viewAll(event) - } else { - viewMessages(event) + when { + args.isBlank() -> { + helpResponse(channel, args, event) + } + args.startsWith(View.VIEW_CMD) -> { + if (event.isChannelOp(channel) && "${View.VIEW_CMD} $TELL_ALL_KEYWORD" == args) { + viewAll(event) + } else { + viewMessages(event) + } + } + args.startsWith("$TELL_DEL_KEYWORD ") -> { + deleteMessage(channel, args, event) + } + else -> { + newMessage(channel, args, event) } - } else if (args.startsWith("$TELL_DEL_KEYWORD ")) { - deleteMessage(channel, args, event) - } else { - newMessage(channel, args, event) } if (clean()) { save() diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt index a30ba24..2d87dbf 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt @@ -141,7 +141,7 @@ class FeedsManager private constructor() { .append("\"><b>") .append(channel) .append("</b></a>") - if (comments.size > 0) { + if (comments.isNotEmpty()) { buff.append(" <br/><br/>") for (j in comments.indices) { if (j > 0) { diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt index c194571..3aad379 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt @@ -74,19 +74,24 @@ class CurrencyConverter : AbstractModule() { override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { reload(properties[API_KEY_PROP]) - if (SYMBOLS.isEmpty()) { - event.respond(EMPTY_SYMBOLS_TABLE) - } else if (args.matches("\\d+([,\\d]+)?(\\.\\d+)? [a-zA-Z]{3}+ (to|in) [a-zA-Z]{3}+".toRegex())) { - val msg = convertCurrency(properties[API_KEY_PROP], args) - event.respond(msg.msg) - if (msg.isError) { + when { + SYMBOLS.isEmpty() -> { + event.respond(EMPTY_SYMBOLS_TABLE) + } + args.matches("\\d+([,\\d]+)?(\\.\\d+)? [a-zA-Z]{3}+ (to|in) [a-zA-Z]{3}+".toRegex()) -> { + val msg = convertCurrency(properties[API_KEY_PROP], args) + event.respond(msg.msg) + if (msg.isError) { + helpResponse(event) + } + } + args.contains(CODES_KEYWORD) -> { + event.sendMessage("The supported currency codes are:") + event.sendList(SYMBOLS.keys.toList(), 11, isIndent = true) + } + else -> { helpResponse(event) } - } else if (args.contains(CODES_KEYWORD)) { - event.sendMessage("The supported currency codes are:") - event.sendList(SYMBOLS.keys.toList(), 11, isIndent = true) - } else { - helpResponse(event) } } From 4c90870f4a2f9ff75adb842b6fc10a2d9bd39a55 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" <erik@thauvin.net> Date: Wed, 1 Nov 2023 22:02:54 -0700 Subject: [PATCH 737/844] Cleaned up code --- .../net/thauvin/erik/mobibot/Constants.kt | 2 +- .../net/thauvin/erik/mobibot/Mobibot.kt | 60 ++++++++--------- .../net/thauvin/erik/mobibot/Pinboard.kt | 2 +- .../kotlin/net/thauvin/erik/mobibot/Utils.kt | 29 ++++---- .../thauvin/erik/mobibot/commands/Ignore.kt | 14 ++-- .../net/thauvin/erik/mobibot/commands/Info.kt | 10 +-- .../net/thauvin/erik/mobibot/commands/Msg.kt | 4 +- .../thauvin/erik/mobibot/commands/Recap.kt | 8 +-- .../thauvin/erik/mobibot/commands/Versions.kt | 8 +-- .../erik/mobibot/commands/links/Comment.kt | 46 ++++++------- .../mobibot/commands/links/LinksManager.kt | 6 +- .../erik/mobibot/commands/links/Posting.kt | 20 +++--- .../erik/mobibot/commands/links/Tags.kt | 4 +- .../erik/mobibot/commands/links/View.kt | 10 +-- .../mobibot/commands/seen/NickComparator.kt | 1 + .../erik/mobibot/commands/seen/Seen.kt | 14 ++-- .../erik/mobibot/commands/seen/SeenNick.kt | 1 + .../erik/mobibot/commands/tell/Tell.kt | 47 ++++++------- .../erik/mobibot/commands/tell/TellMessage.kt | 25 +++---- .../thauvin/erik/mobibot/entries/Entries.kt | 8 +-- .../erik/mobibot/entries/EntriesUtils.kt | 6 +- .../erik/mobibot/entries/EntryComment.kt | 1 + .../thauvin/erik/mobibot/entries/EntryLink.kt | 57 ++++++++-------- .../erik/mobibot/entries/FeedsManager.kt | 48 +++++++------- .../thauvin/erik/mobibot/modules/ChatGpt.kt | 38 +++++------ .../erik/mobibot/modules/CryptoPrices.kt | 6 +- .../erik/mobibot/modules/CurrencyConverter.kt | 3 + .../erik/mobibot/modules/GoogleSearch.kt | 30 ++++----- .../thauvin/erik/mobibot/modules/Lookup.kt | 6 +- .../thauvin/erik/mobibot/modules/Mastodon.kt | 40 +++++------ .../erik/mobibot/modules/ModuleException.kt | 7 +- .../net/thauvin/erik/mobibot/modules/Ping.kt | 24 +++---- .../erik/mobibot/modules/RockPaperScissors.kt | 8 +-- .../erik/mobibot/modules/StockQuote.kt | 66 +++++++++---------- .../thauvin/erik/mobibot/modules/Weather2.kt | 34 +++++----- .../erik/mobibot/modules/WolframAlpha.kt | 28 ++++---- .../thauvin/erik/mobibot/modules/WorldTime.kt | 4 +- .../thauvin/erik/mobibot/msg/ErrorMessage.kt | 2 +- .../net/thauvin/erik/mobibot/msg/Message.kt | 10 +-- .../thauvin/erik/mobibot/msg/NoticeMessage.kt | 2 +- .../erik/mobibot/msg/PrivateMessage.kt | 2 +- .../erik/mobibot/social/SocialModule.kt | 4 +- .../net/thauvin/erik/mobibot/AddonsTest.kt | 10 +-- .../erik/mobibot/ExceptionSanitizer.kt | 6 +- .../net/thauvin/erik/mobibot/PinboardTest.kt | 2 +- .../net/thauvin/erik/mobibot/UtilsTest.kt | 32 ++++----- .../thauvin/erik/mobibot/commands/InfoTest.kt | 8 +-- .../erik/mobibot/commands/RecapTest.kt | 6 +- .../commands/links/LinksManagerTest.kt | 4 +- .../erik/mobibot/commands/links/ViewTest.kt | 16 ++--- .../erik/mobibot/entries/EntriesUtilsTest.kt | 20 +++--- .../erik/mobibot/entries/EntryLinkTest.kt | 10 +-- .../erik/mobibot/modules/ChatGptTest.kt | 10 +-- .../mobibot/modules/CurrencyConverterTest.kt | 18 ++--- .../thauvin/erik/mobibot/modules/DiceTest.kt | 8 +-- .../erik/mobibot/modules/GoogleSearchTest.kt | 12 ++-- .../erik/mobibot/modules/MastodonTest.kt | 14 ++-- .../mobibot/modules/ModuleExceptionTest.kt | 38 +++++------ .../erik/mobibot/modules/StockQuoteTest.kt | 2 +- .../erik/mobibot/modules/WolframAlphaTest.kt | 10 +-- .../erik/mobibot/modules/WordTimeTest.kt | 6 +- 61 files changed, 496 insertions(+), 481 deletions(-) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt index 7cf6719..98ef74a 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt @@ -63,7 +63,7 @@ object Constants { * User-Agent */ const val USER_AGENT = - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36" + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36" /** * The help command. diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt index 3342077..f91c457 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt @@ -97,9 +97,9 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro event.sendMessage("Type a URL on $channel to post it.") event.sendMessage("For more information on a specific command, type:") event.sendMessage( - helpFormat( - helpCmdSyntax("%c ${Constants.HELP_CMD} <command>", event.bot().nick, event is PrivateMessageEvent) - ) + helpFormat( + helpCmdSyntax("%c ${Constants.HELP_CMD} <command>", event.bot().nick, event is PrivateMessageEvent) + ) ) event.sendMessage("The commands are:") event.sendList(addons.names.commands, 8, isBold = true, isIndent = true) @@ -161,7 +161,7 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro with(event.getBot<PircBotX>()) { if (user.nick == nick) { LinksManager.socialManager.notification( - "$nick has joined ${event.channel.name} on $serverHostname" + "$nick has joined ${event.channel.name} on $serverHostname" ) seen.add(userChannelDao.getChannel(channel).users) } else { @@ -209,7 +209,7 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro with(event.getBot<PircBotX>()) { if (user.nick == nick) { LinksManager.socialManager.notification( - "$nick has left ${event.channel.name} on $serverHostname" + "$nick has left ${event.channel.name} on $serverHostname" ) seen.add(userChannelDao.getChannel(channel).users) } else { @@ -232,22 +232,22 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro // Set up the command line options val parser = ArgParser(Constants.CLI_CMD) val debug by parser.option( - ArgType.Boolean, - Constants.DEBUG_ARG, - Constants.DEBUG_ARG.substring(0, 1), - "Print debug & logging data directly to the console" + ArgType.Boolean, + Constants.DEBUG_ARG, + Constants.DEBUG_ARG.substring(0, 1), + "Print debug & logging data directly to the console" ).default(false) val property by parser.option( - ArgType.String, - Constants.PROPS_ARG, - Constants.PROPS_ARG.substring(0, 1), - "Use alternate properties file" + ArgType.String, + Constants.PROPS_ARG, + Constants.PROPS_ARG.substring(0, 1), + "Use alternate properties file" ).default("./${ReleaseInfo.PROJECT}.properties") val version by parser.option( - ArgType.Boolean, - Constants.VERSION_ARG, - Constants.VERSION_ARG.substring(0, 1), - "Print version info" + ArgType.Boolean, + Constants.VERSION_ARG, + Constants.VERSION_ARG.substring(0, 1), + "Print version info" ).default(false) // Parse the command line @@ -256,8 +256,8 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro if (version) { // Output the version println( - "${ReleaseInfo.PROJECT.capitalise()} ${ReleaseInfo.VERSION}" + - " (${ReleaseInfo.BUILDDATE.toIsoLocalDate()})" + "${ReleaseInfo.PROJECT.capitalise()} ${ReleaseInfo.VERSION}" + + " (${ReleaseInfo.BUILDDATE.toIsoLocalDate()})" ) println(ReleaseInfo.WEBSITE) } else { @@ -265,7 +265,7 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro val p = Properties() try { Files.newInputStream( - Paths.get(property) + Paths.get(property) ).use { fis -> p.load(fis) } @@ -284,11 +284,11 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro if (!debug) { try { val stdout = PrintStream( - BufferedOutputStream( - FileOutputStream( - logsDir + channel.substring(1) + '.' + Utils.today() + ".log", true - ) - ), true + BufferedOutputStream( + FileOutputStream( + logsDir + channel.substring(1) + '.' + Utils.today() + ".log", true + ) + ), true ) System.setOut(stdout) } catch (ignore: IOException) { @@ -297,9 +297,9 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro } try { val stderr = PrintStream( - BufferedOutputStream( - FileOutputStream("$logsDir$nickname.err", true) - ), true + BufferedOutputStream( + FileOutputStream("$logsDir$nickname.err", true) + ), true ) System.setErr(stderr) } catch (ignore: IOException) { @@ -324,8 +324,8 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro login = p.getProperty("login", nickname) realName = p.getProperty("realname", nickname) addServer( - ircServer, - p.getIntProperty("port", Constants.DEFAULT_PORT) + ircServer, + p.getIntProperty("port", Constants.DEFAULT_PORT) ) addAutoJoinChannel(channel) addListener(this@Mobibot) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt index 1a4260d..7cb5aed 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt @@ -92,7 +92,7 @@ class Pinboard { */ private fun Date.toTimestamp(): String { return ZonedDateTime.ofInstant( - toInstant().truncatedTo(ChronoUnit.SECONDS), ZoneId.systemDefault() + toInstant().truncatedTo(ChronoUnit.SECONDS), ZoneId.systemDefault() ).format(DateTimeFormatter.ISO_INSTANT) } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt index 38b89e3..e4760d2 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt @@ -128,12 +128,15 @@ object Utils { isNullOrEmpty() -> { "" } + color == DEFAULT_COLOR -> { this } + Colors.BOLD == color || Colors.REVERSE == color -> { color + this + color } + else -> { color + this + Colors.NORMAL } @@ -220,7 +223,7 @@ object Utils { if (serialFile.exists() && serialFile.fileSize() > 0) { try { ObjectInputStream( - BufferedInputStream(Files.newInputStream(serialFile)) + BufferedInputStream(Files.newInputStream(serialFile)) ).use { input -> if (logger.isDebugEnabled) logger.debug("Loading the ${description}.") return input.readObject() @@ -307,20 +310,20 @@ object Utils { @JvmStatic @JvmOverloads fun GenericMessageEvent.sendList( - list: List<String>, - maxPerLine: Int, - separator: String = " ", - isBold: Boolean = false, - isIndent: Boolean = false + list: List<String>, + maxPerLine: Int, + separator: String = " ", + isBold: Boolean = false, + isIndent: Boolean = false ) { var i = 0 while (i < list.size) { sendMessage( - helpFormat( - list.subList(i, list.size.coerceAtMost(i + maxPerLine)).joinToString(separator, truncated = ""), - isBold, - isIndent - ), + helpFormat( + list.subList(i, list.size.coerceAtMost(i + maxPerLine)).joinToString(separator, truncated = ""), + isBold, + isIndent + ), ) i += maxPerLine } @@ -419,8 +422,8 @@ object Utils { fun URL.reader(): UrlReaderResponse { val connection = this.openConnection() as HttpURLConnection connection.setRequestProperty( - "User-Agent", - "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/109.0" + "User-Agent", + "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/109.0" ) return if (connection.responseCode.isHttpSuccess()) { UrlReaderResponse(connection.responseCode, connection.inputStream.bufferedReader().use { it.readText() }) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt index 723108d..d083c10 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt @@ -50,15 +50,15 @@ class Ignore : AbstractCommand() { override val name = IGNORE_CMD override val help = listOf( - "To ignore a link posted to the channel:", - helpFormat("https://www.foo.bar %n"), - "To check your ignore status:", - helpFormat("%c $name"), - "To toggle your ignore status:", - helpFormat("%c $name $me") + "To ignore a link posted to the channel:", + helpFormat("https://www.foo.bar %n"), + "To check your ignore status:", + helpFormat("%c $name"), + "To toggle your ignore status:", + helpFormat("%c $name $me") ) private val helpOp = help.plus( - arrayOf("To add/remove nicks from the ignored list:", helpFormat("%c $name <nick> [<nick> ...]")) + arrayOf("To add/remove nicks from the ignored list:", helpFormat("%c $name <nick> [<nick> ...]")) ) override val isOpOnly = false diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Info.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Info.kt index 7eb3bdb..ed0b6ef 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Info.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Info.kt @@ -48,8 +48,8 @@ import kotlin.time.toDuration class Info(private val tell: Tell, private val seen: Seen) : AbstractCommand() { private val allVersions = listOf( - "${ReleaseInfo.PROJECT.capitalise()} ${ReleaseInfo.VERSION} (${ReleaseInfo.WEBSITE.green()})", - "Written by ${ReleaseInfo.AUTHOR} (${ReleaseInfo.AUTHOR_URL.green()})" + "${ReleaseInfo.PROJECT.capitalise()} ${ReleaseInfo.VERSION} (${ReleaseInfo.WEBSITE.green()})", + "Written by ${ReleaseInfo.AUTHOR} (${ReleaseInfo.AUTHOR_URL.green()})" ) override val name = "info" override val help = listOf("To view information about the bot:", helpFormat("%c $name")) @@ -104,9 +104,9 @@ class Info(private val tell: Tell, private val seen: Seen) : AbstractCommand() { event.sendList(allVersions, 1) val info = StringBuilder() info.append("Uptime: ") - .append(ManagementFactory.getRuntimeMXBean().uptime.toUptime()) - .append(" [Entries: ") - .append(LinksManager.entries.links.size) + .append(ManagementFactory.getRuntimeMXBean().uptime.toUptime()) + .append(" [Entries: ") + .append(LinksManager.entries.links.size) if (seen.isEnabled()) { info.append(", Seen: ").append(seen.count()) } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Msg.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Msg.kt index 48ff38f..20a6635 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Msg.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Msg.kt @@ -39,8 +39,8 @@ import org.pircbotx.hooks.types.GenericMessageEvent class Msg : AbstractCommand() { override val name = "msg" override val help = listOf( - "To have the bot send a private message to someone:", - helpFormat("%c $name <nick> <text>") + "To have the bot send a private message to someone:", + helpFormat("%c $name <nick> <text>") ) override val isOpOnly = true override val isPublic = false diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Recap.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Recap.kt index 66e721e..77154c7 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Recap.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Recap.kt @@ -41,8 +41,8 @@ import java.time.LocalDateTime class Recap : AbstractCommand() { override val name = "recap" override val help = listOf( - "To list the last 10 public channel messages:", - helpFormat("%c $name") + "To list the last 10 public channel messages:", + helpFormat("%c $name") ) override val isOpOnly = false override val isPublic = true @@ -60,8 +60,8 @@ class Recap : AbstractCommand() { @JvmStatic fun storeRecap(sender: String, message: String, isAction: Boolean) { recaps.add( - LocalDateTime.now(Clock.systemUTC()).toUtcDateTime() - + " - $sender" + (if (isAction) " " else ": ") + message + LocalDateTime.now(Clock.systemUTC()).toUtcDateTime() + + " - $sender" + (if (isAction) " " else ": ") + message ) if (recaps.size > MAX_RECAPS) { recaps.removeFirst() diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Versions.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Versions.kt index f920891..896c569 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Versions.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Versions.kt @@ -40,10 +40,10 @@ import org.pircbotx.hooks.types.GenericMessageEvent class Versions : AbstractCommand() { private val allVersions = listOf( - "Version: ${ReleaseInfo.VERSION} (${ReleaseInfo.BUILDDATE.toIsoLocalDate()})", - "${System.getProperty("os.name")} ${System.getProperty("os.version")} (${System.getProperty("os.arch")})" + - ", JVM ${System.getProperty("java.runtime.version")}", - "Kotlin ${KotlinVersion.CURRENT}, PircBotX ${PircBotX.VERSION}" + "Version: ${ReleaseInfo.VERSION} (${ReleaseInfo.BUILDDATE.toIsoLocalDate()})", + "${System.getProperty("os.name")} ${System.getProperty("os.version")} (${System.getProperty("os.arch")})" + + ", JVM ${System.getProperty("java.runtime.version")}", + "Kotlin ${KotlinVersion.CURRENT}, PircBotX ${PircBotX.VERSION}" ) override val name = "versions" override val help = listOf("To view the versions data (bot, platform, java, etc.):", helpFormat("%c $name")) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Comment.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Comment.kt index 9fe250d..1443d44 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Comment.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Comment.kt @@ -45,13 +45,13 @@ import org.pircbotx.hooks.types.GenericMessageEvent class Comment : AbstractCommand() { override val name = COMMAND override val help = listOf( - "To add a comment:", - helpFormat("${Constants.LINK_CMD}1:This is a comment"), - "I will reply with a label, for example: ${Constants.LINK_CMD.bold()}1.1", - "To edit a comment, use its label: ", - helpFormat("${Constants.LINK_CMD}1.1:This is an edited comment"), - "To delete a comment, use its label and a minus sign: ", - helpFormat("${Constants.LINK_CMD}1.1:-") + "To add a comment:", + helpFormat("${Constants.LINK_CMD}1:This is a comment"), + "I will reply with a label, for example: ${Constants.LINK_CMD.bold()}1.1", + "To edit a comment, use its label: ", + helpFormat("${Constants.LINK_CMD}1.1:This is an edited comment"), + "To delete a comment, use its label and a minus sign: ", + helpFormat("${Constants.LINK_CMD}1.1:-") ) override val isOpOnly = false override val isPublic = true @@ -100,12 +100,12 @@ class Comment : AbstractCommand() { } private fun changeAuthor( - channel: String, - cmd: String, - entry: EntryLink, - entryIndex: Int, - commentIndex: Int, - event: GenericMessageEvent + channel: String, + cmd: String, + entry: EntryLink, + entryIndex: Int, + commentIndex: Int, + event: GenericMessageEvent ) { if (event.isChannelOp(channel) && cmd.length > 1) { val comment = entry.getComment(commentIndex) @@ -118,11 +118,11 @@ class Comment : AbstractCommand() { } private fun deleteComment( - channel: String, - entry: EntryLink, - entryIndex: Int, - commentIndex: Int, - event: GenericMessageEvent + channel: String, + entry: EntryLink, + entryIndex: Int, + commentIndex: Int, + event: GenericMessageEvent ) { if (event.isChannelOp(channel) || event.user.nick == entry.getComment(commentIndex).nick) { entry.deleteComment(commentIndex) @@ -134,11 +134,11 @@ class Comment : AbstractCommand() { } private fun setComment( - cmd: String, - entry: EntryLink, - entryIndex: Int, - commentIndex: Int, - event: GenericMessageEvent + cmd: String, + entry: EntryLink, + entryIndex: Int, + commentIndex: Int, + event: GenericMessageEvent ) { entry.setComment(commentIndex, cmd, event.user.nick) event.sendMessage(printComment(entryIndex, commentIndex, entry.getComment(commentIndex))) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManager.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManager.kt index fb1a634..fba6b99 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManager.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManager.kt @@ -161,8 +161,8 @@ class LinksManager : AbstractCommand() { internal fun fetchTitle(link: String): String { try { val html = Jsoup.connect(link) - .userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0") - .get() + .userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0") + .get() val title = html.title() if (title.isNotBlank()) { return title @@ -178,7 +178,7 @@ class LinksManager : AbstractCommand() { return try { val match = entries.links.single { it.link == link } event.sendMessage( - "Duplicate".bold() + " >> " + printLink(entries.links.indexOf(match), match) + "Duplicate".bold() + " >> " + printLink(entries.links.indexOf(match), match) ) true } catch (ignore: NoSuchElementException) { diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Posting.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Posting.kt index e04cd15..ff4278d 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Posting.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Posting.kt @@ -47,16 +47,16 @@ import org.pircbotx.hooks.types.GenericMessageEvent class Posting : AbstractCommand() { override val name = "posting" override val help = listOf( - "Post a URL, by saying it on a line on its own:", - helpFormat("<url> [<title>] ${Tags.COMMAND}: <+tag> [...]]"), - "I will reply with a label, for example: ${Constants.LINK_CMD.bold()}1", - "To add a title, use its label and a pipe:", - helpFormat("${Constants.LINK_CMD}1:|This is the title"), - "To add a comment:", - helpFormat("${Constants.LINK_CMD}1:This is a comment"), - "I will reply with a label, for example: ${Constants.LINK_CMD.bold()}1.1", - "To edit a comment, see: ", - helpFormat("%c ${Constants.HELP_CMD} ${Comment.COMMAND}") + "Post a URL, by saying it on a line on its own:", + helpFormat("<url> [<title>] ${Tags.COMMAND}: <+tag> [...]]"), + "I will reply with a label, for example: ${Constants.LINK_CMD.bold()}1", + "To add a title, use its label and a pipe:", + helpFormat("${Constants.LINK_CMD}1:|This is the title"), + "To add a comment:", + helpFormat("${Constants.LINK_CMD}1:This is a comment"), + "I will reply with a label, for example: ${Constants.LINK_CMD.bold()}1.1", + "To edit a comment, see: ", + helpFormat("%c ${Constants.HELP_CMD} ${Comment.COMMAND}") ) override val isOpOnly = false override val isPublic = true diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Tags.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Tags.kt index 9071059..1662857 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Tags.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Tags.kt @@ -44,8 +44,8 @@ import org.pircbotx.hooks.types.GenericMessageEvent class Tags : AbstractCommand() { override val name = COMMAND override val help = listOf( - "To categorize or tag a URL, use its label and a ${Constants.TAG_CMD}:", - helpFormat("${Constants.LINK_CMD}1${Constants.TAG_CMD}:<+tag|-tag> [...]") + "To categorize or tag a URL, use its label and a ${Constants.TAG_CMD}:", + helpFormat("${Constants.LINK_CMD}1${Constants.TAG_CMD}:<+tag|-tag> [...]") ) override val isOpOnly = false override val isPublic = true diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/View.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/View.kt index ea1ebf8..825e374 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/View.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/View.kt @@ -46,8 +46,8 @@ import org.pircbotx.hooks.types.GenericMessageEvent class View : AbstractCommand() { override val name = VIEW_CMD override val help = listOf( - "To list or search the current URL posts:", - helpFormat("%c $name [<start>] [<query>]") + "To list or search the current URL posts:", + helpFormat("%c $name [<start>] [<query>]") ) override val isOpOnly = false override val isPublic = true @@ -107,9 +107,9 @@ class View : AbstractCommand() { if (sent == MAX_ENTRIES && index < entries.links.size) { event.sendMessage("To view more, try: ") event.sendMessage( - helpFormat( - helpCmdSyntax("%c $name ${index + 1} $query", event.bot().nick, event is PrivateMessageEvent) - ) + helpFormat( + helpCmdSyntax("%c $name ${index + 1} $query", event.bot().nick, event is PrivateMessageEvent) + ) ) } } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt index d29b30d..cfd2c27 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt @@ -39,6 +39,7 @@ class NickComparator : Comparator<String>, Serializable { } companion object { + @Suppress("ConstPropertyName") private const val serialVersionUID = 1L } } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt index 05ad330..c9ee0f3 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt @@ -58,7 +58,7 @@ class Seen(private val serialObject: String) : AbstractCommand() { override val name = "seen" override val help = listOf("To view when a nickname was last seen:", helpFormat("%c $name <nick>")) private val helpOp = help.plus( - arrayOf("To view all ${"seen".bold()} nicks:", helpFormat("%c $name $allKeyword")) + arrayOf("To view all ${"seen".bold()} nicks:", helpFormat("%c $name $allKeyword")) ) override val isOpOnly = false override val isPublic = true @@ -130,12 +130,12 @@ class Seen(private val serialObject: String) : AbstractCommand() { if (isEnabled()) { @Suppress("UNCHECKED_CAST") seenNicks.putAll( - loadSerialData( - serialObject, - TreeMap<String, SeenNick>(), - logger, - "seen nicknames" - ) as TreeMap<String, SeenNick> + loadSerialData( + serialObject, + TreeMap<String, SeenNick>(), + logger, + "seen nicknames" + ) as TreeMap<String, SeenNick> ) } } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt index b09cbf4..7924977 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt @@ -35,6 +35,7 @@ import java.io.Serializable data class SeenNick(val nick: String, val lastSeen: Long) : Serializable { companion object { + @Suppress("ConstPropertyName") private const val serialVersionUID = 1L } } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt index cdeb943..061ca6a 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt @@ -66,11 +66,11 @@ class Tell(private val serialObject: String) : AbstractCommand() { override val name = "tell" override val help = listOf( - "To send a message to someone when they join the channel:", - helpFormat("%c $name <nick> <message>"), - "To view queued and sent messages:", - helpFormat("%c $name ${View.VIEW_CMD}"), - "Messages are kept for ${maxDays.bold()}" + " day".plural(maxDays.toLong()) + '.' + "To send a message to someone when they join the channel:", + helpFormat("%c $name <nick> <message>"), + "To view queued and sent messages:", + helpFormat("%c $name ${View.VIEW_CMD}"), + "Messages are kept for ${maxDays.bold()}" + " day".plural(maxDays.toLong()) + '.' ) override val isOpOnly: Boolean = false override val isPublic: Boolean = isEnabled() @@ -89,6 +89,7 @@ class Tell(private val serialObject: String) : AbstractCommand() { args.isBlank() -> { helpResponse(channel, args, event) } + args.startsWith(View.VIEW_CMD) -> { if (event.isChannelOp(channel) && "${View.VIEW_CMD} $TELL_ALL_KEYWORD" == args) { viewAll(event) @@ -96,9 +97,11 @@ class Tell(private val serialObject: String) : AbstractCommand() { viewMessages(event) } } + args.startsWith("$TELL_DEL_KEYWORD ") -> { deleteMessage(channel, args, event) } + else -> { newMessage(channel, args, event) } @@ -123,9 +126,9 @@ class Tell(private val serialObject: String) : AbstractCommand() { } } else { if (messages.removeIf { - it.id == id && - (it.sender.equals(event.user.nick, true) || event.isChannelOp(channel)) - }) { + it.id == id && + (it.sender.equals(event.user.nick, true) || event.isChannelOp(channel)) + }) { save() event.sendMessage("The message was deleted from the queue.") } else { @@ -185,7 +188,7 @@ class Tell(private val serialObject: String) : AbstractCommand() { if (message.sender == nickname) { if (event !is MessageEvent) { event.user.send().message( - "${"You".bold()} wanted me to remind you: ${message.message.reverseColor()}" + "${"You".bold()} wanted me to remind you: ${message.message.reverseColor()}" ) message.isReceived = true message.isNotified = true @@ -193,17 +196,17 @@ class Tell(private val serialObject: String) : AbstractCommand() { } } else { event.user.send().message( - "${message.sender} wanted me to tell you: ${message.message.reverseColor()}" + "${message.sender} wanted me to tell you: ${message.message.reverseColor()}" ) message.isReceived = true save() } } else if (message.sender.equals(nickname, ignoreCase = true) && message.isReceived - && !message.isNotified + && !message.isNotified ) { event.user.send().message( - "Your message ${"[ID ${message.id}]".reverseColor()} was sent to " - + "${message.recipient.bold()} on ${message.receptionDate}" + "Your message ${"[ID ${message.id}]".reverseColor()} was sent to " + + "${message.recipient.bold()} on ${message.receptionDate}" ) message.isNotified = true save() @@ -224,8 +227,8 @@ class Tell(private val serialObject: String) : AbstractCommand() { if (messages.isNotEmpty()) { for (message in messages) { event.sendMessage( - "${message.sender.bold()}$ARROW${message.recipient.bold()} [ID: ${message.id}, " + - (if (message.isReceived) "DELIVERED]" else "QUEUED]") + "${message.sender.bold()}$ARROW${message.recipient.bold()} [ID: ${message.id}, " + + (if (message.isReceived) "DELIVERED]" else "QUEUED]") ) } } else { @@ -243,13 +246,13 @@ class Tell(private val serialObject: String) : AbstractCommand() { } if (message.isReceived) { event.sendMessage( - message.sender.bold() + ARROW + message.recipient.bold() + - " [${message.receptionDate.toUtcDateTime()}, ID: ${message.id.bold()}, DELIVERED]" + message.sender.bold() + ARROW + message.recipient.bold() + + " [${message.receptionDate.toUtcDateTime()}, ID: ${message.id.bold()}, DELIVERED]" ) } else { event.sendMessage( - message.sender.bold() + ARROW + message.recipient.bold() + - " [${message.queued.toUtcDateTime()}, ID: ${message.id.bold()}, QUEUED]" + message.sender.bold() + ARROW + message.recipient.bold() + + " [${message.queued.toUtcDateTime()}, ID: ${message.id.bold()}, QUEUED]" ) } event.sendMessage(helpFormat(message.message)) @@ -259,9 +262,9 @@ class Tell(private val serialObject: String) : AbstractCommand() { } else { event.sendMessage("To delete one or all delivered messages:") event.sendMessage( - helpFormat( - helpCmdSyntax("%c $name $TELL_DEL_KEYWORD <id|$TELL_ALL_KEYWORD>", event.bot().nick, true) - ) + helpFormat( + helpCmdSyntax("%c $name $TELL_DEL_KEYWORD <id|$TELL_ALL_KEYWORD>", event.bot().nick, true) + ) ) event.sendMessage(help.last()) } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt index 33bc1e9..d17fbb5 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt @@ -39,20 +39,20 @@ import java.time.format.DateTimeFormatter * Tell Message. */ class TellMessage( - /** - * Returns the message's sender. - */ - val sender: String, + /** + * Returns the message's sender. + */ + val sender: String, - /** - * Returns the message's recipient. - */ - val recipient: String, + /** + * Returns the message's recipient. + */ + val recipient: String, - /** - * Returns the message text. - */ - val message: String + /** + * Returns the message text. + */ + val message: String ) : Serializable { /** * Returns the queued date/time. @@ -98,6 +98,7 @@ class TellMessage( } companion object { + @Suppress("ConstPropertyName") private const val serialVersionUID = 2L } } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/Entries.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/Entries.kt index ba22746..e8676ec 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/Entries.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/Entries.kt @@ -34,10 +34,10 @@ package net.thauvin.erik.mobibot.entries import net.thauvin.erik.mobibot.Utils.today class Entries( - var channel: String = "", - var ircServer: String = "", - var logsDir: String = "", - var backlogs: String = "" + var channel: String = "", + var ircServer: String = "", + var logsDir: String = "", + var backlogs: String = "" ) { val links = mutableListOf<EntryLink>() diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt index ff1e423..9c09626 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt @@ -43,7 +43,7 @@ object EntriesUtils { */ @JvmStatic fun printComment(entryIndex: Int, commentIndex: Int, comment: EntryComment): String = - ("${entryIndex.toLinkLabel()}.${commentIndex + 1}: [${comment.nick}] ${comment.comment}") + ("${entryIndex.toLinkLabel()}.${commentIndex + 1}: [${comment.nick}] ${comment.comment}") /** * Prints an entry's link for display on the channel. @@ -52,7 +52,7 @@ object EntriesUtils { @JvmOverloads fun printLink(entryIndex: Int, entry: EntryLink, isView: Boolean = false): String { val buff = StringBuilder().append(entryIndex.toLinkLabel()).append(": ") - .append('[').append(entry.nick).append(']') + .append('[').append(entry.nick).append(']') if (isView && entry.comments.isNotEmpty()) { buff.append("[+").append(entry.comments.size).append(']') } @@ -73,7 +73,7 @@ object EntriesUtils { */ @JvmStatic fun printTags(entryIndex: Int, entry: EntryLink): String = - entryIndex.toLinkLabel() + "${Constants.TAG_CMD}: " + entry.formatTags(", ") + entryIndex.toLinkLabel() + "${Constants.TAG_CMD}: " + entry.formatTags(", ") /** * Builds link label based on its index. e.g: L1 diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryComment.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryComment.kt index 8de54e4..e18d692 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryComment.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryComment.kt @@ -46,6 +46,7 @@ data class EntryComment(var comment: String, var nick: String) : Serializable { companion object { // Serial version UID + @Suppress("ConstPropertyName") private const val serialVersionUID: Long = 1L } } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt index 80ca536..4a69446 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt @@ -40,40 +40,40 @@ import java.util.* * The class used to store link entries. */ class EntryLink( - // Link's comments - val comments: MutableList<EntryComment> = mutableListOf(), + // Link's comments + val comments: MutableList<EntryComment> = mutableListOf(), - // Tags/categories - val tags: MutableList<SyndCategory> = mutableListOf(), + // Tags/categories + val tags: MutableList<SyndCategory> = mutableListOf(), - // Channel - var channel: String, + // Channel + var channel: String, - // Creation date - var date: Date = Calendar.getInstance().time, + // Creation date + var date: Date = Calendar.getInstance().time, - // Link's URL - var link: String, + // Link's URL + var link: String, - // Author's login - var login: String = "", + // Author's login + var login: String = "", - // Author's nickname - var nick: String, + // Author's nickname + var nick: String, - // Link's title - var title: String + // Link's title + var title: String ) : Serializable { /** * Creates a new entry. */ constructor( - link: String, - title: String, - nick: String, - login: String, - channel: String, - tags: List<String?> + link: String, + title: String, + nick: String, + login: String, + channel: String, + tags: List<String?> ) : this(link = link, title = title, nick = nick, login = login, channel = channel) { setTags(tags) } @@ -82,12 +82,12 @@ class EntryLink( * Creates a new entry. */ constructor( - link: String, - title: String, - nick: String, - channel: String, - date: Date, - tags: List<SyndCategory> + link: String, + title: String, + nick: String, + channel: String, + date: Date, + tags: List<SyndCategory> ) : this(link = link, title = title, nick = nick, channel = channel, date = Date(date.time)) { this.tags.addAll(tags) } @@ -207,6 +207,7 @@ class EntryLink( companion object { // Serial version UID + @Suppress("ConstPropertyName") private const val serialVersionUID: Long = 1L } } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt index 2d87dbf..f786cb2 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt @@ -55,24 +55,24 @@ class FeedsManager private constructor() { private val logger: Logger = LoggerFactory.getLogger(FeedsManager::class.java) // The file containing the current entries. - private const val currentXml = "current.xml" + private const val CURRENT_XML = "current.xml" // The .xml extension. - private const val dotXml = ".xml" + private const val DOT_XML = ".xml" /** * Loads the current feed. */ @JvmStatic @Throws(IOException::class, FeedException::class) - fun loadFeed(entries: Entries, currentFile: String = currentXml): String { + fun loadFeed(entries: Entries, currentFile: String = CURRENT_XML): String { entries.links.clear() val xml = Paths.get("${entries.logsDir}${currentFile}") var pubDate = today() if (xml.exists()) { val input = SyndFeedInput() InputStreamReader( - Files.newInputStream(xml), StandardCharsets.UTF_8 + Files.newInputStream(xml), StandardCharsets.UTF_8 ).use { reader -> val feed = input.build(reader) pubDate = feed.publishedDate.toIsoLocalDate() @@ -81,12 +81,12 @@ class FeedsManager private constructor() { for (i in items.indices.reversed()) { with(items[i]) { entry = EntryLink( - link, - title, - author.substring(author.lastIndexOf('(') + 1, author.length - 1), - entries.channel, - publishedDate, - categories + link, + title, + author.substring(author.lastIndexOf('(') + 1, author.length - 1), + entries.channel, + publishedDate, + categories ) var split: List<String> for (comment in description.value.split("<br/>")) { @@ -110,7 +110,7 @@ class FeedsManager private constructor() { * Saves the feeds. */ @JvmStatic - fun saveFeed(entries: Entries, currentFile: String = currentXml) { + fun saveFeed(entries: Entries, currentFile: String = CURRENT_XML) { if (logger.isDebugEnabled) logger.debug("Saving the feeds...") if (entries.logsDir.isNotBlank()) { try { @@ -119,7 +119,7 @@ class FeedsManager private constructor() { val items: MutableList<SyndEntry> = mutableListOf() var item: SyndEntry OutputStreamWriter( - Files.newOutputStream(Paths.get("${entries.logsDir}${currentFile}")), StandardCharsets.UTF_8 + Files.newOutputStream(Paths.get("${entries.logsDir}${currentFile}")), StandardCharsets.UTF_8 ).use { fw -> with(rss) { feedType = "rss_2.0" @@ -134,13 +134,13 @@ class FeedsManager private constructor() { with(entries.links[i]) { buff.setLength(0) buff.append("Posted by <b>") - .append(nick) - .append("</b> on <a href=\"irc://") - .append(entries.ircServer).append('/') - .append(channel) - .append("\"><b>") - .append(channel) - .append("</b></a>") + .append(nick) + .append("</b> on <a href=\"irc://") + .append(entries.ircServer).append('/') + .append(channel) + .append("\"><b>") + .append(channel) + .append("</b></a>") if (comments.isNotEmpty()) { buff.append(" <br/><br/>") for (j in comments.indices) { @@ -165,11 +165,11 @@ class FeedsManager private constructor() { output.output(rss, fw) } OutputStreamWriter( - Files.newOutputStream( - Paths.get( - entries.logsDir + today() + dotXml - ) - ), StandardCharsets.UTF_8 + Files.newOutputStream( + Paths.get( + entries.logsDir + today() + DOT_XML + ) + ), StandardCharsets.UTF_8 ).use { fw -> output.output(rss, fw) } } catch (e: FeedException) { if (logger.isWarnEnabled) logger.warn("Unable to generate the entries feed.", e) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt index e1e86df..bd92332 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt @@ -56,8 +56,8 @@ class ChatGpt : AbstractModule() { if (args.isNotBlank()) { try { val answer = chat( - args.trim(), properties[API_KEY_PROP], - properties.getOrDefault(MAX_TOKENS_PROP, "1024").toInt() + args.trim(), properties[API_KEY_PROP], + properties.getOrDefault(MAX_TOKENS_PROP, "1024").toInt() ) if (answer.isNotBlank()) { event.sendMessage(WordUtils.wrap(answer, 400)) @@ -107,13 +107,13 @@ class ChatGpt : AbstractModule() { if (!apiKey.isNullOrEmpty()) { val prompt = JSONWriter.valueToString("Q:$query\nA:") val request = HttpRequest.newBuilder() - .uri(URI.create(API_URL)) - .header("Content-Type", "application/json") - .header("Authorization", "Bearer $apiKey") - .header("User-Agent", Constants.USER_AGENT) - .POST( - HttpRequest.BodyPublishers.ofString( - """{ + .uri(URI.create(API_URL)) + .header("Content-Type", "application/json") + .header("Authorization", "Bearer $apiKey") + .header("User-Agent", Constants.USER_AGENT) + .POST( + HttpRequest.BodyPublishers.ofString( + """{ "model": "text-davinci-003", "prompt": $prompt, "temperature": 0, @@ -122,9 +122,9 @@ class ChatGpt : AbstractModule() { "frequency_penalty": 0, "presence_penalty": 0 }""".trimIndent() - ) ) - .build() + ) + .build() try { val response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString()) if (response.statusCode() == 200) { @@ -134,16 +134,16 @@ class ChatGpt : AbstractModule() { return choices.getJSONObject(0).getString("text").trim() } catch (e: JSONException) { throw ModuleException( - "$CHATGPT_CMD($query): JSON", - "A JSON error has occurred while conversing with $CHATGPT_NAME.", - e + "$CHATGPT_CMD($query): JSON", + "A JSON error has occurred while conversing with $CHATGPT_NAME.", + e ) } } else { if (response.statusCode() == 429) { throw ModuleException( - "$CHATGPT_CMD($query): Rate limit reached", - "Rate limit reached. Please try again later." + "$CHATGPT_CMD($query): Rate limit reached", + "Rate limit reached. Please try again later." ) } else { throw IOException("HTTP Status Code: " + response.statusCode()) @@ -151,9 +151,9 @@ class ChatGpt : AbstractModule() { } } catch (e: IOException) { throw ModuleException( - "$CHATGPT_CMD($query): IO", - "An IO error has occurred while conversing with $CHATGPT_NAME.", - e + "$CHATGPT_CMD($query): IO", + "An IO error has occurred while conversing with $CHATGPT_NAME.", + e ) } } else { diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt index 5136504..d14056e 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt @@ -134,9 +134,9 @@ class CryptoPrices : AbstractModule() { } } catch (e: CryptoException) { throw ModuleException( - "loadCurrencies(): CE", - "An error has occurred while retrieving the currencies table.", - e + "loadCurrencies(): CE", + "An error has occurred while retrieving the currencies table.", + e ) } } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt index 3aad379..da0efd8 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt @@ -78,6 +78,7 @@ class CurrencyConverter : AbstractModule() { SYMBOLS.isEmpty() -> { event.respond(EMPTY_SYMBOLS_TABLE) } + args.matches("\\d+([,\\d]+)?(\\.\\d+)? [a-zA-Z]{3}+ (to|in) [a-zA-Z]{3}+".toRegex()) -> { val msg = convertCurrency(properties[API_KEY_PROP], args) event.respond(msg.msg) @@ -85,10 +86,12 @@ class CurrencyConverter : AbstractModule() { helpResponse(event) } } + args.contains(CODES_KEYWORD) -> { event.sendMessage("The supported currency codes are:") event.sendList(SYMBOLS.keys.toList(), 11, isIndent = true) } + else -> { helpResponse(event) } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt index b0e911c..f426d1e 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt @@ -65,10 +65,10 @@ class GoogleSearch : AbstractModule() { if (args.isNotBlank()) { try { val results = searchGoogle( - args, - properties[API_KEY_PROP], - properties[CSE_KEY_PROP], - event.user.nick + args, + properties[API_KEY_PROP], + properties[CSE_KEY_PROP], + event.user.nick ) for (msg in results) { if (msg.isError) { @@ -104,23 +104,23 @@ class GoogleSearch : AbstractModule() { @JvmStatic @Throws(ModuleException::class) fun searchGoogle( - query: String, - apiKey: String?, - cseKey: String?, - quotaUser: String = ReleaseInfo.PROJECT + query: String, + apiKey: String?, + cseKey: String?, + quotaUser: String = ReleaseInfo.PROJECT ): List<Message> { if (apiKey.isNullOrBlank() || cseKey.isNullOrBlank()) { throw ModuleException( - "${GoogleSearch::class.java.name} is disabled.", - "${GOOGLE_CMD.capitalise()} is disabled. The API keys are missing." + "${GoogleSearch::class.java.name} is disabled.", + "${GOOGLE_CMD.capitalise()} is disabled. The API keys are missing." ) } val results = mutableListOf<Message>() if (query.isNotBlank()) { try { val url = URL( - "https://www.googleapis.com/customsearch/v1?key=$apiKey&cx=$cseKey" + - ""aUser=${quotaUser}&q=${query.encodeUrl()}&filter=1&num=5&alt=json" + "https://www.googleapis.com/customsearch/v1?key=$apiKey&cx=$cseKey" + + ""aUser=${quotaUser}&q=${query.encodeUrl()}&filter=1&num=5&alt=json" ) val json = JSONObject(url.reader().body) if (json.has("items")) { @@ -141,9 +141,9 @@ class GoogleSearch : AbstractModule() { throw ModuleException("searchGoogle($query): IOE", "An IO error has occurred searching Google.", e) } catch (e: JSONException) { throw ModuleException( - "searchGoogle($query): JSON", - "A JSON error has occurred searching Google.", - e + "searchGoogle($query): JSON", + "A JSON error has occurred searching Google.", + e ) } } else { diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Lookup.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Lookup.kt index fc85226..9ab2ead 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Lookup.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Lookup.kt @@ -55,9 +55,9 @@ class Lookup : AbstractModule() { event.respondWith(nslookup(args).prependIndent()) } catch (ignore: UnknownHostException) { if (args.matches( - ("(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)") - .toRegex() - ) + ("(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)") + .toRegex() + ) ) { try { val lines = whois(args) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Mastodon.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Mastodon.kt index 4cf2fe9..3be3a5f 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Mastodon.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Mastodon.kt @@ -65,7 +65,7 @@ class Mastodon : SocialModule() { private fun formatTags(entry: EntryLink): String { return entry.tags.filter { !it.name.equals(entry.channel.removePrefix("#"), true) } - .joinToString(separator = " ", prefix = "\n\n") { "#${it.name}" } + .joinToString(separator = " ", prefix = "\n\n") { "#${it.name}" } } /** @@ -74,11 +74,11 @@ class Mastodon : SocialModule() { @Throws(ModuleException::class) override fun post(message: String, isDm: Boolean): String { return toot( - apiKey = properties[ACCESS_TOKEN_PROP], - instance = properties[INSTANCE_PROP], - handle = handle, - message = message, - isDm = isDm + apiKey = properties[ACCESS_TOKEN_PROP], + instance = properties[INSTANCE_PROP], + handle = handle, + message = message, + isDm = isDm ) } @@ -99,21 +99,21 @@ class Mastodon : SocialModule() { @Throws(ModuleException::class) fun toot(apiKey: String?, instance: String?, handle: String?, message: String, isDm: Boolean): String { val request = HttpRequest.newBuilder() - .uri(URI.create("https://$instance/api/v1/statuses")) - .header("Content-Type", "application/json") - .header("Authorization", "Bearer $apiKey") - .POST( - HttpRequest.BodyPublishers.ofString( - JSONWriter.valueToString( - if (isDm) { - mapOf("status" to "${handle?.prefixIfMissing('@')} $message", "visibility" to "direct") - } else { - mapOf("status" to message) - } - ) - ) + .uri(URI.create("https://$instance/api/v1/statuses")) + .header("Content-Type", "application/json") + .header("Authorization", "Bearer $apiKey") + .POST( + HttpRequest.BodyPublishers.ofString( + JSONWriter.valueToString( + if (isDm) { + mapOf("status" to "${handle?.prefixIfMissing('@')} $message", "visibility" to "direct") + } else { + mapOf("status" to message) + } + ) ) - .build() + ) + .build() try { val response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString()) if (response.statusCode() == 200) { diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ModuleException.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ModuleException.kt index 017efd4..a7416c2 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ModuleException.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ModuleException.kt @@ -34,11 +34,12 @@ package net.thauvin.erik.mobibot.modules * The `ModuleException` class. */ class ModuleException @JvmOverloads constructor( - val debugMessage: String, - message: String? = null, - cause: Throwable? = null + val debugMessage: String, + message: String? = null, + cause: Throwable? = null ) : Exception(message, cause) { companion object { + @Suppress("ConstPropertyName") private const val serialVersionUID = 1L } } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Ping.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Ping.kt index de5c1e8..944dbc1 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Ping.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Ping.kt @@ -50,18 +50,18 @@ class Ping : AbstractModule() { */ @JvmField val PINGS = listOf( - "is barely alive.", - "is trying to stay awake.", - "has gone fishing.", - "is somewhere over the rainbow.", - "has fallen and can't get up.", - "is running. You better go chase it.", - "has just spontaneously combusted.", - "is talking to itself... don't interrupt. That's rude.", - "is bartending at an AA meeting.", - "is hibernating.", - "is saving energy: apathetic mode activated.", - "is busy. Go away!" + "is barely alive.", + "is trying to stay awake.", + "has gone fishing.", + "is somewhere over the rainbow.", + "has fallen and can't get up.", + "is running. You better go chase it.", + "has just spontaneously combusted.", + "is talking to itself... don't interrupt. That's rude.", + "is bartending at an AA meeting.", + "is hibernating.", + "is saving energy: apathetic mode activated.", + "is busy. Go away!" ) @JvmStatic diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt index 359956a..a299d8d 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt @@ -52,10 +52,10 @@ class RockPaperScissors : AbstractModule() { with(help) { add("To play Rock Paper Scissors:") add( - helpFormat( - "%c ${Hands.ROCK.name.lowercase()} | ${Hands.PAPER.name.lowercase()}" - + " | ${Hands.SCISSORS.name.lowercase()}" - ) + helpFormat( + "%c ${Hands.ROCK.name.lowercase()} | ${Hands.PAPER.name.lowercase()}" + + " | ${Hands.SCISSORS.name.lowercase()}" + ) ) } } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt index 661a4e8..dcae5e7 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt @@ -132,8 +132,8 @@ class StockQuote : AbstractModule() { fun getQuote(symbol: String, apiKey: String?): List<Message> { if (apiKey.isNullOrBlank()) { throw ModuleException( - "${StockQuote::class.java.name} is disabled.", - "${STOCK_CMD.capitalise()} is disabled. The API key is missing." + "${StockQuote::class.java.name} is disabled.", + "${STOCK_CMD.capitalise()} is disabled. The API key is missing." ) } val messages = mutableListOf<Message>() @@ -144,8 +144,8 @@ class StockQuote : AbstractModule() { with(messages) { // Search for symbol/keywords response = URL( - "${API_URL}SYMBOL_SEARCH&keywords=" + symbol.encodeUrl() + "&apikey=" - + apiKey.encodeUrl() + "${API_URL}SYMBOL_SEARCH&keywords=" + symbol.encodeUrl() + "&apikey=" + + apiKey.encodeUrl() ).reader().body var json = getJsonResponse(response, debugMessage) val symbols = json.getJSONArray("bestMatches") @@ -156,9 +156,9 @@ class StockQuote : AbstractModule() { // Get quote for symbol response = URL( - "${API_URL}GLOBAL_QUOTE&symbol=" - + symbolInfo.getString("1. symbol").encodeUrl() + "&apikey=" - + apiKey.encodeUrl() + "${API_URL}GLOBAL_QUOTE&symbol=" + + symbolInfo.getString("1. symbol").encodeUrl() + "&apikey=" + + apiKey.encodeUrl() ).reader().body json = getJsonResponse(response, debugMessage) val quote = json.getJSONObject("Global Quote") @@ -167,50 +167,50 @@ class StockQuote : AbstractModule() { } else { add( - PublicMessage( - "Symbol: " + quote.getString("01. symbol").unescapeXml() - + " [" + symbolInfo.getString("2. name").unescapeXml() + ']' - ) + PublicMessage( + "Symbol: " + quote.getString("01. symbol").unescapeXml() + + " [" + symbolInfo.getString("2. name").unescapeXml() + ']' + ) ) val pad = 10 add( - PublicMessage( - "Price:".padEnd(pad).prependIndent() - + quote.getString("05. price").unescapeXml() - ) + PublicMessage( + "Price:".padEnd(pad).prependIndent() + + quote.getString("05. price").unescapeXml() + ) ) add( - PublicMessage( - "Previous:".padEnd(pad).prependIndent() - + quote.getString("08. previous close").unescapeXml() - ) + PublicMessage( + "Previous:".padEnd(pad).prependIndent() + + quote.getString("08. previous close").unescapeXml() + ) ) val data = arrayOf( - "Open" to "02. open", - "High" to "03. high", - "Low" to "04. low", - "Volume" to "06. volume", - "Latest" to "07. latest trading day" + "Open" to "02. open", + "High" to "03. high", + "Low" to "04. low", + "Volume" to "06. volume", + "Latest" to "07. latest trading day" ) data.forEach { add( - NoticeMessage( - "${it.first}:".padEnd(pad).prependIndent() - + quote.getString(it.second).unescapeXml() - ) + NoticeMessage( + "${it.first}:".padEnd(pad).prependIndent() + + quote.getString(it.second).unescapeXml() + ) ) } add( - NoticeMessage( - "Change:".padEnd(pad).prependIndent() - + quote.getString("09. change").unescapeXml() - + " [" + quote.getString("10. change percent").unescapeXml() + ']' - ) + NoticeMessage( + "Change:".padEnd(pad).prependIndent() + + quote.getString("09. change").unescapeXml() + + " [" + quote.getString("10. change percent").unescapeXml() + ']' + ) ) } } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt index 533cce6..80a06fa 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt @@ -120,8 +120,8 @@ class Weather2 : AbstractModule() { fun getWeather(query: String, apiKey: String?): List<Message> { if (apiKey.isNullOrBlank()) { throw ModuleException( - "${Weather2::class.java.name} is disabled.", - "${WEATHER_CMD.capitalise()} is disabled. The API key is missing." + "${Weather2::class.java.name} is disabled.", + "${WEATHER_CMD.capitalise()} is disabled. The API key is missing." ) } val owm = OWM(apiKey) @@ -145,10 +145,10 @@ class Weather2 : AbstractModule() { } if (cwd.hasCityName()) { messages.add( - PublicMessage( - "City: ${cwd.cityName}, " + - country.name.replace('_', ' ').capitalizeWords() + " [${country.value}]" - ) + PublicMessage( + "City: ${cwd.cityName}, " + + country.name.replace('_', ' ').capitalizeWords() + " [${country.value}]" + ) ) cwd.mainData?.let { with(it) { @@ -181,8 +181,8 @@ class Weather2 : AbstractModule() { for (w in it) { w?.let { condition.append(' ') - .append(w.getDescription().capitalise()) - .append('.') + .append(w.getDescription().capitalise()) + .append('.') } } messages.add(NoticeMessage(condition.toString())) @@ -192,15 +192,15 @@ class Weather2 : AbstractModule() { cwd.cityId?.let { if (it > 0) { messages.add( - NoticeMessage("https://openweathermap.org/city/$it", Colors.GREEN) + NoticeMessage("https://openweathermap.org/city/$it", Colors.GREEN) ) } else { messages.add( - NoticeMessage( - "https://openweathermap.org/find?q=" - + "$city,${code.uppercase()}".encodeUrl(), - Colors.GREEN - ) + NoticeMessage( + "https://openweathermap.org/find?q=" + + "$city,${code.uppercase()}".encodeUrl(), + Colors.GREEN + ) ) } } @@ -209,9 +209,9 @@ class Weather2 : AbstractModule() { } catch (e: APIException) { if (e.code == 404) { throw ModuleException( - "getWeather($query): API ${e.code}", - "The requested city was not found.", - e + "getWeather($query): API ${e.code}", + "The requested city was not found.", + e ) } else { throw ModuleException("getWeather($query): API ${e.code}", e.message, e) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt index 049807a..a72efab 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt @@ -60,15 +60,15 @@ class WolframAlpha : AbstractModule() { try { val query = args.trim().split("units=", limit = 2, ignoreCase = true) event.sendMessage( - queryWolfram( - query[0].trim(), - units = if (query.size == 2) { - getUnits(query[1].trim()) - } else { - getUnits(properties[UNITS_PROP]) - }, - appId = properties[APPID_KEY_PROP] - ) + queryWolfram( + query[0].trim(), + units = if (query.size == 2) { + getUnits(query[1].trim()) + } else { + getUnits(properties[UNITS_PROP]) + }, + appId = properties[APPID_KEY_PROP] + ) ) } catch (e: ModuleException) { if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) @@ -111,15 +111,15 @@ class WolframAlpha : AbstractModule() { return urlReader.body } else { throw ModuleException( - "wolfram($query): ${urlReader.responseCode} : ${urlReader.body} ", - urlReader.body.ifEmpty { - "Looks like Wolfram Alpha isn't able to answer that. (${urlReader.responseCode})" - } + "wolfram($query): ${urlReader.responseCode} : ${urlReader.body} ", + urlReader.body.ifEmpty { + "Looks like Wolfram Alpha isn't able to answer that. (${urlReader.responseCode})" + } ) } } catch (ioe: IOException) { throw ModuleException( - "wolfram($query): IOE", "An IO Error occurred while querying Wolfram Alpha.", ioe + "wolfram($query): IOE", "An IO Error occurred while querying Wolfram Alpha.", ioe ) } } else { diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WorldTime.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WorldTime.kt index debbe98..18072bc 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WorldTime.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WorldTime.kt @@ -322,7 +322,7 @@ class WorldTime : AbstractModule() { put("ZULU", "Zulu") put("ZW", "Africa/Harare") ZoneId.getAvailableZoneIds().filter { it.length <= 3 && !containsKey(it) } - .forEach { tz -> put(tz, tz) } + .forEach { tz -> put(tz, tz) } } // The Time command @@ -336,7 +336,7 @@ class WorldTime : AbstractModule() { // Date/Time Format private var dtf = - DateTimeFormatter.ofPattern("'The time is ${"'HH:mm'".bold()} on ${"'EEEE, d MMMM yyyy'".bold()} in '") + DateTimeFormatter.ofPattern("'The time is ${"'HH:mm'".bold()} on ${"'EEEE, d MMMM yyyy'".bold()} in '") /** * Returns the current Internet (beat) Time. diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/ErrorMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/ErrorMessage.kt index 2695a3b..0607936 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/ErrorMessage.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/msg/ErrorMessage.kt @@ -34,4 +34,4 @@ package net.thauvin.erik.mobibot.msg * The `ErrorMessage` class. */ class ErrorMessage @JvmOverloads constructor(msg: String, color: String = DEFAULT_COLOR) : - Message(msg, color, isError = true) + Message(msg, color, isError = true) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/Message.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/Message.kt index 3b4be49..23a33b9 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/Message.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/msg/Message.kt @@ -36,11 +36,11 @@ import net.thauvin.erik.semver.Constants * The `Message` class. */ open class Message @JvmOverloads constructor( - var msg: String, - var color: String = DEFAULT_COLOR, - var isNotice: Boolean = false, - isError: Boolean = false, - var isPrivate: Boolean = false + var msg: String, + var color: String = DEFAULT_COLOR, + var isNotice: Boolean = false, + isError: Boolean = false, + var isPrivate: Boolean = false ) { companion object { var DEFAULT_COLOR = Constants.EMPTY diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/NoticeMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/NoticeMessage.kt index cd6721c..037d504 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/NoticeMessage.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/msg/NoticeMessage.kt @@ -34,5 +34,5 @@ package net.thauvin.erik.mobibot.msg * The `NoticeMessage` class. */ class NoticeMessage @JvmOverloads constructor(msg: String, color: String = DEFAULT_COLOR) : - Message(msg, color, isNotice = true) + Message(msg, color, isNotice = true) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/PrivateMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/PrivateMessage.kt index 3033d1a..b424fdf 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/PrivateMessage.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/msg/PrivateMessage.kt @@ -34,4 +34,4 @@ package net.thauvin.erik.mobibot.msg * The `PrivateMessage` class. */ class PrivateMessage @JvmOverloads constructor(msg: String, color: String = DEFAULT_COLOR) : - Message(msg, color, isPrivate = true) + Message(msg, color, isPrivate = true) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialModule.kt b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialModule.kt index 32e670a..b594670 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialModule.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialModule.kt @@ -76,8 +76,8 @@ abstract class SocialModule : AbstractModule() { post(message = formatEntry(LinksManager.entries.links[index]), isDm = false) } catch (e: ModuleException) { if (logger.isWarnEnabled) logger.warn( - "Failed to post entry ${index.toLinkLabel()} on $name.", - e + "Failed to post entry ${index.toLinkLabel()} on $name.", + e ) } } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt index 5a8a638..3241bf0 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt @@ -76,11 +76,11 @@ class AddonsTest { assertThat(addons.names.ops, "names.ops").containsExactly("cycle") assertThat(addons.names.commands, "names.command").containsExactly( - "joke", - "rock", - "paper", - "scissors", - "ignore" + "joke", + "rock", + "paper", + "scissors", + "ignore" ) } } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/ExceptionSanitizer.kt b/src/test/kotlin/net/thauvin/erik/mobibot/ExceptionSanitizer.kt index be2deb3..a3994ec 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/ExceptionSanitizer.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/ExceptionSanitizer.kt @@ -46,9 +46,9 @@ object ExceptionSanitizer { with(this) { if (!cause?.message.isNullOrBlank()) { return ModuleException( - debugMessage, - cause?.javaClass?.name + ": " + cause?.message?.replaceEach(search, obfuscate), - this + debugMessage, + cause?.javaClass?.name + ": " + cause?.message?.replaceEach(search, obfuscate), + this ) } else if (!message.isNullOrBlank()) { return ModuleException(debugMessage, message?.replaceEach(search, obfuscate), this) diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/PinboardTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/PinboardTest.kt index 4ebb53c..87617e8 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/PinboardTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/PinboardTest.kt @@ -68,7 +68,7 @@ class PinboardTest : LocalProperties() { private fun validatePin(apiToken: String, url: String, vararg matches: String): Boolean { val response = - URL("https://api.pinboard.in/v1/posts/get?auth_token=${apiToken}&tag=test&" + url.encodeUrl()).reader().body + URL("https://api.pinboard.in/v1/posts/get?auth_token=${apiToken}&tag=test&" + url.encodeUrl()).reader().body matches.forEach { if (!response.contains(it)) { diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt index 8ddb013..7a3f5d2 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt @@ -73,7 +73,7 @@ import java.util.* */ class UtilsTest { private val ascii = - " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" + " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" private val cal = Calendar.getInstance() private val localDateTime = LocalDateTime.of(1952, 2, 17, 12, 30, 0) private val test = "This is a test." @@ -89,7 +89,7 @@ class UtilsTest { val sep = '/' val url = "https://erik.thauvin.net" assertThat(dir.appendIfMissing(File.separatorChar), "appendIfMissing(dir)") - .isEqualTo(dir + File.separatorChar) + .isEqualTo(dir + File.separatorChar) assertThat(url.appendIfMissing(sep), "appendIfMissing(url)").isEqualTo("$url$sep") assertThat("$url$sep".appendIfMissing(sep), "appendIfMissing($url$sep)").isEqualTo("$url$sep") } @@ -115,24 +115,24 @@ class UtilsTest { fun textCapitaliseWords() { assertThat(test.capitalizeWords(), "captiatlizeWords(test)").isEqualTo("This Is A Test.") assertThat("Already Capitalized".capitalizeWords(), "already capitalized") - .isEqualTo("Already Capitalized") + .isEqualTo("Already Capitalized") assertThat(" a test ".capitalizeWords(), "with spaces").isEqualTo(" A Test ") } @Test fun testColorize() { assertThat(ascii.colorize(Colors.REVERSE), "reverse.colorize()").isEqualTo( - Colors.REVERSE + ascii + Colors.REVERSE + Colors.REVERSE + ascii + Colors.REVERSE ) assertThat(ascii.colorize(Colors.RED), "red.colorize()") - .isEqualTo(Colors.RED + ascii + Colors.NORMAL) + .isEqualTo(Colors.RED + ascii + Colors.NORMAL) assertThat(ascii.colorize(Colors.BOLD), "colorized(bold)") - .isEqualTo(Colors.BOLD + ascii + Colors.BOLD) + .isEqualTo(Colors.BOLD + ascii + Colors.BOLD) assertThat(null.colorize(Colors.RED), "null.colorize()").isEqualTo("") assertThat("".colorize(Colors.RED), "colorize()").isEqualTo("") assertThat(ascii.colorize(DEFAULT_COLOR), "ascii.colorize()").isEqualTo(ascii) assertThat(" ".colorize(Colors.NORMAL), "blank.colorize()") - .isEqualTo(Colors.NORMAL + " " + Colors.NORMAL) + .isEqualTo(Colors.NORMAL + " " + Colors.NORMAL) } @Test @@ -164,19 +164,19 @@ class UtilsTest { fun testHelpCmdSyntax() { val bot = "mobibot" assertThat(helpCmdSyntax("%c $test %n $test", bot, false), "helpCmdSyntax(private)") - .isEqualTo("$bot: $test $bot $test") + .isEqualTo("$bot: $test $bot $test") assertThat(helpCmdSyntax("%c %n $test %c $test %n", bot, true), "helpCmdSyntax(public)") - .isEqualTo("/msg $bot $bot $test /msg $bot $test $bot") + .isEqualTo("/msg $bot $bot $test /msg $bot $test $bot") } @Test fun testHelpFormat() { assertThat(helpFormat(test, isBold = true, isIndent = false), "helpFormat(bold)") - .isEqualTo("${Colors.BOLD}$test${Colors.BOLD}") + .isEqualTo("${Colors.BOLD}$test${Colors.BOLD}") assertThat(helpFormat(test, isBold = false, isIndent = true), "helpFormat(indent)") - .isEqualTo(test.prependIndent()) + .isEqualTo(test.prependIndent()) assertThat(helpFormat(test, isBold = true, isIndent = true), "helpFormat(bold,indent)") - .isEqualTo(test.colorize(Colors.BOLD).prependIndent()) + .isEqualTo(test.colorize(Colors.BOLD).prependIndent()) } @@ -218,15 +218,15 @@ class UtilsTest { val search = arrayOf("one", "two", "three") val replace = arrayOf("1", "2", "3") assertThat(search.joinToString(",").replaceEach(search, replace), "replaceEach(1,2,3") - .isEqualTo(replace.joinToString(",")) + .isEqualTo(replace.joinToString(",")) assertThat(test.replaceEach(search, replace), "replaceEach(nothing)").isEqualTo(test) assertThat(test.replaceEach(arrayOf("t", "e"), arrayOf("", "E")), "replaceEach($test)") - .isEqualTo(test.replace("t", "").replace("e", "E")) + .isEqualTo(test.replace("t", "").replace("e", "E")) assertThat(test.replaceEach(search, emptyArray()), "replaceEach(search, empty)") - .isEqualTo(test) + .isEqualTo(test) } @Test @@ -258,7 +258,7 @@ class UtilsTest { @Test fun testUnescapeXml() { assertThat("<a name="test & ''">".unescapeXml()).isEqualTo( - "<a name=\"test & ''\">" + "<a name=\"test & ''\">" ) } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/InfoTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/InfoTest.kt index 1f28049..265009b 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/InfoTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/InfoTest.kt @@ -40,14 +40,14 @@ class InfoTest { @Test(groups = ["commands"]) fun testToUptime() { assertThat( - 547800300076L.toUptime(), - "upTime(full)" + 547800300076L.toUptime(), + "upTime(full)" ).isEqualTo("17 years 4 months 2 weeks 1 day 6 hours 45 minutes") assertThat(24300000L.toUptime(), "upTime(hours minutes)").isEqualTo("6 hours 45 minutes") assertThat(110700000L.toUptime(), "upTime(days hours minutes)").isEqualTo("1 day 6 hours 45 minutes") assertThat( - 1320300000L.toUptime(), - "upTime(weeks days hours minutes)" + 1320300000L.toUptime(), + "upTime(weeks days hours minutes)" ).isEqualTo("2 weeks 1 day 6 hours 45 minutes") assertThat(2700000L.toUptime(), "upTime(45 minutes)").isEqualTo("45 minutes") assertThat(60000L.toUptime(), "upTime(1 minute)").isEqualTo("1 minute") diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/RecapTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/RecapTest.kt index 5f1a690..f1fbe11 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/RecapTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/RecapTest.kt @@ -48,13 +48,13 @@ class RecapTest { assertThat(Recap.recaps, "Recap.recaps").all { size().isEqualTo(Recap.MAX_RECAPS) prop(MutableList<String>::first) - .matches("[1-2]\\d{3}-[01]\\d-[0-3]\\d [0-2]\\d:[0-6]\\d - sender11: test 11".toRegex()) + .matches("[1-2]\\d{3}-[01]\\d-[0-3]\\d [0-2]\\d:[0-6]\\d - sender11: test 11".toRegex()) prop(MutableList<String>::last) - .matches("[1-2]\\d{3}-[01]\\d-[0-3]\\d [0-2]\\d:[0-6]\\d - sender20: test 20".toRegex()) + .matches("[1-2]\\d{3}-[01]\\d-[0-3]\\d [0-2]\\d:[0-6]\\d - sender20: test 20".toRegex()) } Recap.storeRecap("sender", "test action", true) assertThat(Recap.recaps.last()) - .matches("[1-2]\\d{3}-[01]\\d-[0-3]\\d [0-2]\\d:[0-6]\\d - sender test action".toRegex()) + .matches("[1-2]\\d{3}-[01]\\d-[0-3]\\d [0-2]\\d:[0-6]\\d - sender test action".toRegex()) } } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt index 8fcbd8b..8e49b5e 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt @@ -47,8 +47,8 @@ class LinksManagerTest { fun fetchTitle() { assertThat(linksManager.fetchTitle("https://erik.thauvin.net/"), "fetchTitle(Erik)").contains("Erik's Weblog") assertThat( - linksManager.fetchTitle("https://www.google.com/foo"), - "fetchTitle(Foo)" + linksManager.fetchTitle("https://www.google.com/foo"), + "fetchTitle(Foo)" ).isEqualTo(Constants.NO_TITLE) } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/ViewTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/ViewTest.kt index 0853a9d..c28090d 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/ViewTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/ViewTest.kt @@ -45,14 +45,14 @@ class ViewTest { for (i in 1..10) { LinksManager.entries.links.add( - EntryLink( - "https://www.example.com/$i", - "Example $i", - "nick$i", - "login$i", - "#channel", - emptyList() - ) + EntryLink( + "https://www.example.com/$i", + "Example $i", + "nick$i", + "login$i", + "#channel", + emptyList() + ) ) } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt index a09ebb9..6eef16e 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt @@ -46,14 +46,14 @@ class EntriesUtilsTest { private val links = buildList { for (i in 0..5) { add( - EntryLink( - "https://www.mobitopia.org/$i", - "Mobitopia$i", - "Skynx$i", - "JimH$i", - "#mobitopia$i", - listOf("tag1", "tag2", "tag3", "TAG4", "Tag5") - ) + EntryLink( + "https://www.mobitopia.org/$i", + "Mobitopia$i", + "Skynx$i", + "JimH$i", + "#mobitopia$i", + listOf("tag1", "tag2", "tag3", "TAG4", "Tag5") + ) ) } } @@ -67,7 +67,7 @@ class EntriesUtilsTest { fun printLinkTest() { for (i in links.indices) { assertThat( - printLink(i - 1, links[i]), "link $i" + printLink(i - 1, links[i]), "link $i" ).isEqualTo("L$i: [Skynx$i] \u0002Mobitopia$i\u0002 ( \u000303https://www.mobitopia.org/$i\u000F )") } @@ -79,7 +79,7 @@ class EntriesUtilsTest { fun printTagsTest() { for (i in links.indices) { assertThat( - printTags(i - 1, links[i]), "tag $i" + printTags(i - 1, links[i]), "tag $i" ).isEqualTo("L${i}T: tag1, tag2, tag3, tag4, tag5") } } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt index 4c20525..ab3feee 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt @@ -48,8 +48,8 @@ import java.util.* */ class EntryLinkTest { private val entryLink = EntryLink( - "https://www.mobitopia.org/", "Mobitopia", "Skynx", "JimH", "#mobitopia", - listOf("tag1", "tag2", "tag3", "TAG4", "Tag5") + "https://www.mobitopia.org/", "Mobitopia", "Skynx", "JimH", "#mobitopia", + listOf("tag1", "tag2", "tag3", "TAG4", "Tag5") ) @Test(groups = ["entries"]) @@ -117,12 +117,12 @@ class EntryLinkTest { entryLink.setTags("+mobitopia") entryLink.setTags("-mobitopia") assertThat( - entryLink.formatTags(","), - "formatTags(',')" + entryLink.formatTags(","), + "formatTags(',')" ).isEqualTo("tag1,tag2,tag3,tag4,mobitopia") entryLink.setTags("-tag4 tag5") assertThat( - entryLink.formatTags(" ", ","), "formatTag(' ',',')" + entryLink.formatTags(" ", ","), "formatTag(' ',',')" ).isEqualTo(",tag1 tag2 tag3 mobitopia tag5") val size = entryLink.tags.size entryLink.setTags("") diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt index fa50fcb..66fb98d 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt @@ -42,21 +42,21 @@ class ChatGptTest : LocalProperties() { @Test(groups = ["modules"]) fun testApiKey() { assertFailure { ChatGpt.chat("1 gallon to liter", "", 0) } - .isInstanceOf(ModuleException::class.java) - .hasNoCause() + .isInstanceOf(ModuleException::class.java) + .hasNoCause() } @Test(groups = ["modules", "no-ci"]) fun testChat() { val apiKey = getProperty(ChatGpt.API_KEY_PROP) assertThat( - ChatGpt.chat("how do I make an HTTP request in Javascript?", apiKey, 100) + ChatGpt.chat("how do I make an HTTP request in Javascript?", apiKey, 100) ).contains("XMLHttpRequest") assertThat( - ChatGpt.chat("how do I encode a URL in java?", apiKey, 60) + ChatGpt.chat("how do I encode a URL in java?", apiKey, 60) ).contains("URLEncoder") assertFailure { ChatGpt.chat("1 liter to gallon", apiKey, 0) } - .isInstanceOf(ModuleException::class.java) + .isInstanceOf(ModuleException::class.java) } } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt index 4ee9668..5375784 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt @@ -49,7 +49,7 @@ import org.testng.annotations.Test /** * The `CurrencyConvertTest` class. */ -class CurrencyConverterTest: LocalProperties() { +class CurrencyConverterTest : LocalProperties() { @BeforeClass @Throws(ModuleException::class) @@ -62,22 +62,22 @@ class CurrencyConverterTest: LocalProperties() { fun testConvertCurrency() { val apiKey = getProperty(CurrencyConverter.API_KEY_PROP) assertThat( - convertCurrency(apiKey,"100 USD to EUR").msg, - "convertCurrency(100 USD to EUR)" + convertCurrency(apiKey, "100 USD to EUR").msg, + "convertCurrency(100 USD to EUR)" ).matches("100 United States Dollar = \\d{2,3}\\.\\d{2,3} Euro".toRegex()) assertThat( - convertCurrency(apiKey,"1 USD to GBP").msg, - "convertCurrency(1 USD to BGP)" + convertCurrency(apiKey, "1 USD to GBP").msg, + "convertCurrency(1 USD to BGP)" ).matches("1 United States Dollar = 0\\.\\d{2,3} Pound Sterling".toRegex()) assertThat( - convertCurrency(apiKey,"100,000.00 CAD to USD").msg, - "convertCurrency(100,000.00 GBP to USD)" + convertCurrency(apiKey, "100,000.00 CAD to USD").msg, + "convertCurrency(100,000.00 GBP to USD)" ).matches("100,000.00 Canadian Dollar = \\d+\\.\\d{2,3} United States Dollar".toRegex()) - assertThat(convertCurrency(apiKey,"100 USD to USD"), "convertCurrency(100 USD to USD)").all { + assertThat(convertCurrency(apiKey, "100 USD to USD"), "convertCurrency(100 USD to USD)").all { prop(Message::msg).contains("You're kidding, right?") isInstanceOf(PublicMessage::class.java) } - assertThat(convertCurrency(apiKey,"100 USD"), "convertCurrency(100 USD)").all { + assertThat(convertCurrency(apiKey, "100 USD"), "convertCurrency(100 USD)").all { prop(Message::msg).contains("Invalid query.") isInstanceOf(ErrorMessage::class.java) } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/DiceTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/DiceTest.kt index 4225e3b..cdc04f0 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/DiceTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/DiceTest.kt @@ -42,12 +42,12 @@ class DiceTest { fun testRoll() { assertThat(Dice.roll(1, 1), "roll(1d1)").isEqualTo("\u00021\u0002") assertThat(Dice.roll(2, 1), "roll(2d1)") - .isEqualTo("\u00021\u0002 + \u00021\u0002 = \u00022\u0002") + .isEqualTo("\u00021\u0002 + \u00021\u0002 = \u00022\u0002") assertThat(Dice.roll(5, 1), "roll(5d1)") - .isEqualTo("\u00021\u0002 + \u00021\u0002 + \u00021\u0002 + \u00021\u0002 + \u00021\u0002 = \u00025\u0002") + .isEqualTo("\u00021\u0002 + \u00021\u0002 + \u00021\u0002 + \u00021\u0002 + \u00021\u0002 = \u00025\u0002") assertThat(Dice.roll(2, 6), "roll(2d6)") - .matches("\u0002[1-6]\u0002 \\+ \u0002[1-6]\u0002 = \u0002[1-9][0-2]?\u0002".toRegex()) + .matches("\u0002[1-6]\u0002 \\+ \u0002[1-6]\u0002 = \u0002[1-9][0-2]?\u0002".toRegex()) assertThat(Dice.roll(3, 7), "roll(3d7)") - .matches("\u0002[1-7]\u0002 \\+ \u0002[1-7]\u0002 \\+ \u0002[1-7]\u0002 = \u0002\\d{1,2}\u0002".toRegex()) + .matches("\u0002[1-7]\u0002 \\+ \u0002[1-7]\u0002 \\+ \u0002[1-7]\u0002 = \u0002\\d{1,2}\u0002".toRegex()) } } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt index 640a721..fa50f8c 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt @@ -48,19 +48,19 @@ class GoogleSearchTest : LocalProperties() { @Test(groups = ["modules"]) fun testAPIKeys() { assertThat( - searchGoogle("", "apikey", "cssKey").first(), - "searchGoogle(empty)" + searchGoogle("", "apikey", "cssKey").first(), + "searchGoogle(empty)" ).isInstanceOf(ErrorMessage::class.java) assertFailure { searchGoogle("test", "", "apiKey") } - .isInstanceOf(ModuleException::class.java).hasNoCause() + .isInstanceOf(ModuleException::class.java).hasNoCause() assertFailure { searchGoogle("test", "apiKey", "") } - .isInstanceOf(ModuleException::class.java).hasNoCause() + .isInstanceOf(ModuleException::class.java).hasNoCause() assertFailure { searchGoogle("test", "apiKey", "cssKey") } - .isInstanceOf(ModuleException::class.java) - .hasMessage("API key not valid. Please pass a valid API key.") + .isInstanceOf(ModuleException::class.java) + .hasMessage("API key not valid. Please pass a valid API key.") } @Test(groups = ["no-ci", "modules"]) diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt index 84f9375..34f778a 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt @@ -42,13 +42,13 @@ class MastodonTest : LocalProperties() { fun testToot() { val msg = "Testing Mastodon API from ${getHostName()}" assertThat( - toot( - getProperty(Mastodon.ACCESS_TOKEN_PROP), - getProperty(Mastodon.INSTANCE_PROP), - getProperty(Mastodon.HANDLE_PROP), - msg, - true - ) + toot( + getProperty(Mastodon.ACCESS_TOKEN_PROP), + getProperty(Mastodon.INSTANCE_PROP), + getProperty(Mastodon.HANDLE_PROP), + msg, + true + ) ).contains(msg) } } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt index b36285b..db68280 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt @@ -44,58 +44,58 @@ import java.lang.reflect.Method */ class ModuleExceptionTest { companion object { - const val debugMessage = "debugMessage" - const val message = "message" + const val DEBUG_MESSAGE = "debugMessage" + const val MESSAGE = "message" } @DataProvider(name = "dp") fun createData(@Suppress("UNUSED_PARAMETER") m: Method?): Array<Array<Any>> { return arrayOf( - arrayOf(ModuleException(debugMessage, message, IOException("URL http://foobar.com"))), - arrayOf(ModuleException(debugMessage, message, IOException("URL http://foobar.com?"))), - arrayOf(ModuleException(debugMessage, message)) + arrayOf(ModuleException(DEBUG_MESSAGE, MESSAGE, IOException("URL http://foobar.com"))), + arrayOf(ModuleException(DEBUG_MESSAGE, MESSAGE, IOException("URL http://foobar.com?"))), + arrayOf(ModuleException(DEBUG_MESSAGE, MESSAGE)) ) } @Test(dataProvider = "dp") fun testGetDebugMessage(e: ModuleException) { - assertThat(e::debugMessage).isEqualTo(debugMessage) + assertThat(e::debugMessage).isEqualTo(DEBUG_MESSAGE) } @Test(dataProvider = "dp") fun testGetMessage(e: ModuleException) { - assertThat(e).hasMessage(message) + assertThat(e).hasMessage(MESSAGE) } @Test(groups = ["modules"]) fun testSanitizeMessage() { val apiKey = "1234567890" - var e = ModuleException(debugMessage, message, IOException("URL http://foo.com?apiKey=$apiKey&userID=me")) + var e = ModuleException(DEBUG_MESSAGE, MESSAGE, IOException("URL http://foo.com?apiKey=$apiKey&userID=me")) assertThat( - e.sanitize(apiKey, "", "me").message, "ModuleException(debugMessage, message, IOException(url))" + e.sanitize(apiKey, "", "me").message, "ModuleException(debugMessage, message, IOException(url))" ).isNotNull().all { contains("xxxxxxxxxx", "userID=xx", "java.io.IOException") doesNotContain(apiKey, "me") } - e = ModuleException(debugMessage, message, null) - assertThat(e.sanitize(apiKey), "ModuleException(debugMessage, message, null)").hasMessage(message) + e = ModuleException(DEBUG_MESSAGE, MESSAGE, null) + assertThat(e.sanitize(apiKey), "ModuleException(debugMessage, message, null)").hasMessage(MESSAGE) - e = ModuleException(debugMessage, message, IOException()) - assertThat(e.sanitize(apiKey), "ModuleException(debugMessage, message, IOException())").hasMessage(message) + e = ModuleException(DEBUG_MESSAGE, MESSAGE, IOException()) + assertThat(e.sanitize(apiKey), "ModuleException(debugMessage, message, IOException())").hasMessage(MESSAGE) - e = ModuleException(debugMessage, apiKey) + e = ModuleException(DEBUG_MESSAGE, apiKey) assertThat(e.sanitize(apiKey).message, "ModuleException(debugMessage, apiKey)").isNotNull() - .doesNotContain(apiKey) + .doesNotContain(apiKey) val msg: String? = null - e = ModuleException(debugMessage, msg, IOException(msg)) + e = ModuleException(DEBUG_MESSAGE, msg, IOException(msg)) assertThat(e.sanitize(apiKey).message, "ModuleException(debugMessage, msg, IOException(msg))").isNull() - e = ModuleException(debugMessage, msg, IOException("foo is $apiKey")) + e = ModuleException(DEBUG_MESSAGE, msg, IOException("foo is $apiKey")) assertThat( - e.sanitize(" ", apiKey, "foo").message, - "ModuleException(debugMessage, msg, IOException(foo is $apiKey))" + e.sanitize(" ", apiKey, "foo").message, + "ModuleException(debugMessage, msg, IOException(foo is $apiKey))" ).isNotNull().all { doesNotContain(apiKey) endsWith("xxx is xxxxxxxxxx") diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt index 17e5b92..aff4188 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt @@ -60,7 +60,7 @@ class StockQuoteTest : LocalProperties() { assertThat(messages, "getQuote($symbol)").index(0).prop(Message::msg).matches("Symbol: AAPL .*".toRegex()) assertThat(messages, "getQuote($symbol)").index(1).prop(Message::msg).matches(buildMatch("Price").toRegex()) assertThat(messages, "getQuote($symbol)").index(2).prop(Message::msg) - .matches(buildMatch("Previous").toRegex()) + .matches(buildMatch("Previous").toRegex()) assertThat(messages, "getQuote($symbol)").index(3).prop(Message::msg).matches(buildMatch("Open").toRegex()) symbol = "blahfoo" diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt index 281d8af..ae1722d 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt @@ -45,11 +45,11 @@ class WolframAlphaTest : LocalProperties() { @Test(groups = ["modules"]) fun testAppId() { assertFailure { queryWolfram("1 gallon to liter", appId = "DEMO") } - .isInstanceOf(ModuleException::class.java) - .hasMessage("Error 1: Invalid appid") + .isInstanceOf(ModuleException::class.java) + .hasMessage("Error 1: Invalid appid") assertFailure { queryWolfram("1 gallon to liter", appId = "") } - .isInstanceOf(ModuleException::class.java) + .isInstanceOf(ModuleException::class.java) } @Test(groups = ["modules", "no-ci"]) @@ -62,8 +62,8 @@ class WolframAlphaTest : LocalProperties() { query = "SFO to LAX" assertThat( - queryWolfram(query, WolframAlpha.METRIC, apiKey), - "queryWolfram($query)" + queryWolfram(query, WolframAlpha.METRIC, apiKey), + "queryWolfram($query)" ).contains("kilometers") } catch (e: ModuleException) { // Avoid displaying api key in CI logs diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt index 29f5589..3602a27 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt @@ -49,9 +49,9 @@ class WordTimeTest { @Test(groups = ["modules"]) fun testTime() { assertThat(time(), "time()").matches( - ("The time is ${Colors.BOLD}\\d{1,2}:\\d{2}${Colors.BOLD} " + - "on ${Colors.BOLD}\\w+, \\d{1,2} \\w+ \\d{4}${Colors.BOLD} " + - "in ${Colors.BOLD}Los Angeles${Colors.BOLD}").toRegex() + ("The time is ${Colors.BOLD}\\d{1,2}:\\d{2}${Colors.BOLD} " + + "on ${Colors.BOLD}\\w+, \\d{1,2} \\w+ \\d{4}${Colors.BOLD} " + + "in ${Colors.BOLD}Los Angeles${Colors.BOLD}").toRegex() ) assertThat(time(""), "time()").endsWith("Los Angeles".bold()) assertThat(time("PST"), "time(PST)").endsWith("Los Angeles".bold()) From 1cd7c5a79e1b38d5f582a051bd2e20538b1d9edf Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" <erik@thauvin.net> Date: Wed, 1 Nov 2023 22:10:50 -0700 Subject: [PATCH 738/844] Upgraded to Kotlin 1.9.20 --- .idea/kotlinc.xml | 2 +- build.gradle | 8 ++++---- config/detekt/baseline.xml | 17 ++++------------- version.properties | 6 +++--- 4 files changed, 12 insertions(+), 21 deletions(-) diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index f8467b4..e805548 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <project version="4"> <component name="KotlinJpsPluginSettings"> - <option name="version" value="1.9.10" /> + <option name="version" value="1.9.20" /> </component> </project> \ No newline at end of file diff --git a/build.gradle b/build.gradle index 9fb85c6..6507e20 100644 --- a/build.gradle +++ b/build.gradle @@ -7,11 +7,11 @@ plugins { id 'application' id 'com.github.ben-manes.versions' version '0.49.0' id 'idea' - id 'io.gitlab.arturbosch.detekt' version '1.23.1' + id 'io.gitlab.arturbosch.detekt' version '1.23.3' id 'java' id 'net.thauvin.erik.gradle.semver' version '1.0.4' - id 'org.jetbrains.kotlin.jvm' version '1.9.10' - id 'org.jetbrains.kotlin.kapt' version '1.9.10' + id 'org.jetbrains.kotlin.jvm' version '1.9.20' + id 'org.jetbrains.kotlin.kapt' version '1.9.20' id 'org.jetbrains.kotlinx.kover' version '0.7.4' id 'org.sonarqube' version '4.4.1.3373' id 'pmd' @@ -55,7 +55,7 @@ dependencies { // Commons (mostly for PircBotX) implementation 'org.apache.commons:commons-lang3:3.13.0' - implementation 'org.apache.commons:commons-text:1.10.0' + implementation 'org.apache.commons:commons-text:1.11.0' implementation 'commons-codec:commons-codec:1.16.0' implementation 'commons-net:commons-net:3.10.0' diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml index 9f157cf..5c6be73 100644 --- a/config/detekt/baseline.xml +++ b/config/detekt/baseline.xml @@ -2,9 +2,9 @@ <SmellBaseline> <ManuallySuppressedIssues></ManuallySuppressedIssues> <CurrentIssues> - <ID>CyclomaticComplexMethod:FeedsManager.kt$FeedsManager.Companion$@JvmStatic fun saveFeed(entries: Entries, currentFile: String = currentXml)</ID> + <ID>CyclomaticComplexMethod:FeedsManager.kt$FeedsManager.Companion$@JvmStatic fun saveFeed(entries: Entries, currentFile: String = CURRENT_XML)</ID> <ID>CyclomaticComplexMethod:Weather2.kt$Weather2.Companion$@JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message></ID> - <ID>LongMethod:FeedsManager.kt$FeedsManager.Companion$@JvmStatic fun saveFeed(entries: Entries, currentFile: String = currentXml)</ID> + <ID>LongMethod:FeedsManager.kt$FeedsManager.Companion$@JvmStatic fun saveFeed(entries: Entries, currentFile: String = CURRENT_XML)</ID> <ID>LongMethod:Mobibot.kt$Mobibot.Companion$@JvmStatic @Throws(Exception::class) fun main(args: Array<String>)</ID> <ID>LongMethod:StockQuote.kt$StockQuote.Companion$@JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List<Message></ID> <ID>LongMethod:Weather2.kt$Weather2.Companion$@JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message></ID> @@ -46,15 +46,6 @@ <ID>MagicNumber:WorldTime.kt$WorldTime.Companion$3600</ID> <ID>MagicNumber:WorldTime.kt$WorldTime.Companion$60</ID> <ID>MagicNumber:WorldTime.kt$WorldTime.Companion$86.4</ID> - <ID>MaxLineLength:DiceTest.kt$DiceTest$.</ID> - <ID>MaxLineLength:Lookup.kt$Lookup$("(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)")</ID> - <ID>MaxLineLength:Mastodon.kt$Mastodon.Companion$mapOf("status" to "${handle?.prefixIfMissing('@')} $message", "visibility" to "direct")</ID> - <ID>MaxLineLength:Mobibot.kt$Mobibot$helpCmdSyntax("%c ${Constants.HELP_CMD} <command>", event.bot().nick, event is PrivateMessageEvent)</ID> - <ID>MaxLineLength:PinboardTest.kt$PinboardTest$URL("https://api.pinboard.in/v1/posts/get?auth_token=${apiToken}&tag=test&" + url.encodeUrl()).reader().body</ID> - <ID>MaxLineLength:StockQuote.kt$StockQuote.Companion$+</ID> - <ID>MaxLineLength:Utils.kt$Utils$list.subList(i, list.size.coerceAtMost(i + maxPerLine)).joinToString(separator, truncated = "")</ID> - <ID>MaxLineLength:View.kt$View$helpCmdSyntax("%c $name ${index + 1} $query", event.bot().nick, event is PrivateMessageEvent)</ID> - <ID>MaxLineLength:Weather2.kt$Weather2.Companion$country.name.replace('_', ' ').capitalizeWords()</ID> <ID>NestedBlockDepth:Addons.kt$Addons$fun add(command: AbstractCommand): Boolean</ID> <ID>NestedBlockDepth:Addons.kt$Addons$fun add(module: AbstractModule): Boolean</ID> <ID>NestedBlockDepth:ChatGpt.kt$ChatGpt.Companion$@JvmStatic @Throws(ModuleException::class) fun chat(query: String, apiKey: String?, maxTokens: Int): String</ID> @@ -62,8 +53,8 @@ <ID>NestedBlockDepth:CurrencyConverter.kt$CurrencyConverter.Companion$@JvmStatic @Throws(ModuleException::class) fun loadSymbols(apiKey: String?)</ID> <ID>NestedBlockDepth:CurrencyConverter.kt$CurrencyConverter.Companion$@JvmStatic fun convertCurrency(apiKey: String?, query: String): Message</ID> <ID>NestedBlockDepth:EntryLink.kt$EntryLink$private fun setTags(tags: List<String?>)</ID> - <ID>NestedBlockDepth:FeedsManager.kt$FeedsManager.Companion$@JvmStatic @Throws(IOException::class, FeedException::class) fun loadFeed(entries: Entries, currentFile: String = currentXml): String</ID> - <ID>NestedBlockDepth:FeedsManager.kt$FeedsManager.Companion$@JvmStatic fun saveFeed(entries: Entries, currentFile: String = currentXml)</ID> + <ID>NestedBlockDepth:FeedsManager.kt$FeedsManager.Companion$@JvmStatic @Throws(IOException::class, FeedException::class) fun loadFeed(entries: Entries, currentFile: String = CURRENT_XML): String</ID> + <ID>NestedBlockDepth:FeedsManager.kt$FeedsManager.Companion$@JvmStatic fun saveFeed(entries: Entries, currentFile: String = CURRENT_XML)</ID> <ID>NestedBlockDepth:GoogleSearch.kt$GoogleSearch$override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent)</ID> <ID>NestedBlockDepth:GoogleSearch.kt$GoogleSearch.Companion$@JvmStatic @Throws(ModuleException::class) fun searchGoogle( query: String, apiKey: String?, cseKey: String?, quotaUser: String = ReleaseInfo.PROJECT ): List<Message></ID> <ID>NestedBlockDepth:LinksManager.kt$LinksManager$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent)</ID> diff --git a/version.properties b/version.properties index c73da9e..9c446af 100644 --- a/version.properties +++ b/version.properties @@ -1,9 +1,9 @@ #Generated by the Semver Plugin for Gradle -#Thu Oct 26 20:43:39 PDT 2023 -version.buildmeta=20231026204339 +#Wed Nov 01 22:09:32 PDT 2023 +version.buildmeta=20231101220932 version.major=0 version.minor=8 version.patch=0 version.prerelease=rc version.project=mobibot -version.semver=0.8.0-rc+20231026204339 +version.semver=0.8.0-rc+20231101220932 From c68c25aa9504a4217cb9495b8086ea9d795a5aa6 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" <erik@thauvin.net> Date: Fri, 10 Nov 2023 23:43:20 -0800 Subject: [PATCH 739/844] Moved from Gradle to bld --- .circleci/config.yml | 42 +- .github/workflows/gradle.yml | 48 +- .gitignore | 150 +++--- .gitlab-ci.yml | 31 +- .idea/app.iml | 30 ++ .idea/bld.iml | 14 + .idea/codeStyles/Project.xml | 298 ------------ .idea/codeStyles/codeStyleConfig.xml | 6 - .idea/compiler.xml | 6 - ...{Erik_s_Copyright_Notice.xml => BSD_3.xml} | 4 +- .idea/copyright/profiles_settings.xml | 2 +- .idea/inspectionProfiles/Project_Default.xml | 64 --- .idea/jarRepositories.xml | 45 -- .idea/kotlinc.xml | 6 - .idea/libraries/bld.xml | 17 + .idea/libraries/compile.xml | 13 + .idea/libraries/runtime.xml | 14 + .idea/libraries/test.xml | 14 + .idea/misc.xml | 18 +- .idea/modules.xml | 9 + .idea/runConfigurations/Run Tests.xml | 9 + .vscode/launch.json | 11 + .vscode/settings.json | 15 + README.md | 6 +- bin/main/log4j2.xml | 69 +++ bin/main/net/thauvin/erik/mobibot/Addons.kt | 190 ++++++++ .../net/thauvin/erik/mobibot/Constants.kt | 102 ++++ .../net/thauvin/erik/mobibot/FeedReader.kt | 92 ++++ bin/main/net/thauvin/erik/mobibot/Mobibot.kt | 421 +++++++++++++++++ bin/main/net/thauvin/erik/mobibot/Pinboard.kt | 113 +++++ bin/main/net/thauvin/erik/mobibot/Utils.kt | 439 ++++++++++++++++++ .../erik/mobibot/commands/AbstractCommand.kt | 79 ++++ .../erik/mobibot/commands/ChannelFeed.kt | 62 +++ .../thauvin/erik/mobibot/commands/Cycle.kt | 66 +++ .../net/thauvin/erik/mobibot/commands/Die.kt | 62 +++ .../thauvin/erik/mobibot/commands/Ignore.kt | 147 ++++++ .../net/thauvin/erik/mobibot/commands/Info.kt | 124 +++++ .../net/thauvin/erik/mobibot/commands/Me.kt | 51 ++ .../thauvin/erik/mobibot/commands/Modules.kt | 63 +++ .../net/thauvin/erik/mobibot/commands/Msg.kt | 60 +++ .../net/thauvin/erik/mobibot/commands/Nick.kt | 51 ++ .../thauvin/erik/mobibot/commands/Recap.kt | 81 ++++ .../net/thauvin/erik/mobibot/commands/Say.kt | 51 ++ .../thauvin/erik/mobibot/commands/Users.kt | 50 ++ .../thauvin/erik/mobibot/commands/Versions.kt | 59 +++ .../erik/mobibot/commands/links/Comment.kt | 151 ++++++ .../mobibot/commands/links/LinksManager.kt | 207 +++++++++ .../erik/mobibot/commands/links/Posting.kt | 164 +++++++ .../erik/mobibot/commands/links/Tags.kt | 87 ++++ .../erik/mobibot/commands/links/View.kt | 120 +++++ .../mobibot/commands/seen/NickComparator.kt | 45 ++ .../erik/mobibot/commands/seen/Seen.kt | 150 ++++++ .../erik/mobibot/commands/seen/SeenNick.kt | 41 ++ .../erik/mobibot/commands/tell/Tell.kt | 306 ++++++++++++ .../erik/mobibot/commands/tell/TellManager.kt | 74 +++ .../erik/mobibot/commands/tell/TellMessage.kt | 104 +++++ .../thauvin/erik/mobibot/entries/Entries.kt | 54 +++ .../erik/mobibot/entries/EntriesUtils.kt | 83 ++++ .../erik/mobibot/entries/EntryComment.kt | 52 +++ .../thauvin/erik/mobibot/entries/EntryLink.kt | 213 +++++++++ .../erik/mobibot/entries/FeedsManager.kt | 187 ++++++++ .../erik/mobibot/modules/AbstractModule.kt | 131 ++++++ .../net/thauvin/erik/mobibot/modules/Calc.kt | 87 ++++ .../thauvin/erik/mobibot/modules/ChatGpt.kt | 176 +++++++ .../erik/mobibot/modules/CryptoPrices.kt | 159 +++++++ .../erik/mobibot/modules/CurrencyConverter.kt | 222 +++++++++ .../net/thauvin/erik/mobibot/modules/Dice.kt | 87 ++++ .../erik/mobibot/modules/GoogleSearch.kt | 162 +++++++ .../net/thauvin/erik/mobibot/modules/Joke.kt | 105 +++++ .../thauvin/erik/mobibot/modules/Lookup.kt | 171 +++++++ .../thauvin/erik/mobibot/modules/Mastodon.kt | 149 ++++++ .../erik/mobibot/modules/ModuleException.kt | 45 ++ .../net/thauvin/erik/mobibot/modules/Ping.kt | 83 ++++ .../erik/mobibot/modules/RockPaperScissors.kt | 114 +++++ .../erik/mobibot/modules/StockQuote.kt | 236 ++++++++++ .../thauvin/erik/mobibot/modules/War.class | Bin 0 -> 2452 bytes .../thauvin/erik/mobibot/modules/Weather2.kt | 250 ++++++++++ .../erik/mobibot/modules/WolframAlpha.kt | 142 ++++++ .../thauvin/erik/mobibot/modules/WorldTime.kt | 390 ++++++++++++++++ .../thauvin/erik/mobibot/msg/ErrorMessage.kt | 37 ++ .../net/thauvin/erik/mobibot/msg/Message.kt | 65 +++ .../thauvin/erik/mobibot/msg/NoticeMessage.kt | 38 ++ .../erik/mobibot/msg/PrivateMessage.kt | 37 ++ .../thauvin/erik/mobibot/msg/PublicMessage.kt | 36 ++ .../erik/mobibot/social/SocialManager.kt | 116 +++++ .../erik/mobibot/social/SocialModule.kt | 96 ++++ .../erik/mobibot/social/SocialTimer.kt | 40 ++ bin/test/current.xml | 67 +++ .../net/thauvin/erik/mobibot/AddonsTest.kt | 86 ++++ .../erik/mobibot/ExceptionSanitizer.kt | 60 +++ .../thauvin/erik/mobibot/FeedReaderTest.kt | 78 ++++ .../thauvin/erik/mobibot/LocalProperties.kt | 85 ++++ .../net/thauvin/erik/mobibot/PinboardTest.kt | 81 ++++ .../net/thauvin/erik/mobibot/UtilsTest.kt | 278 +++++++++++ .../thauvin/erik/mobibot/commands/InfoTest.kt | 58 +++ .../erik/mobibot/commands/RecapTest.kt | 60 +++ .../commands/links/LinksManagerTest.kt | 77 +++ .../erik/mobibot/commands/links/ViewTest.kt | 111 +++++ .../erik/mobibot/commands/seen/SeenTest.kt | 85 ++++ .../mobibot/commands/tell/TellMessageTest.kt | 72 +++ .../commands/tell/TellMessagesMgrTest.kt | 87 ++++ .../erik/mobibot/entries/EntriesUtilsTest.kt | 91 ++++ .../erik/mobibot/entries/EntryLinkTest.kt | 133 ++++++ .../erik/mobibot/entries/FeedMgrTest.kt | 115 +++++ .../thauvin/erik/mobibot/modules/CalcTest.kt | 53 +++ .../erik/mobibot/modules/ChatGptTest.kt | 62 +++ .../erik/mobibot/modules/CryptoPricesTest.kt | 78 ++++ .../mobibot/modules/CurrencyConverterTest.kt | 85 ++++ .../thauvin/erik/mobibot/modules/DiceTest.kt | 53 +++ .../erik/mobibot/modules/GoogleSearchTest.kt | 95 ++++ .../thauvin/erik/mobibot/modules/JokeTest.kt | 57 +++ .../erik/mobibot/modules/LookupTest.kt | 60 +++ .../erik/mobibot/modules/MastodonTest.kt | 54 +++ .../mobibot/modules/ModuleExceptionTest.kt | 105 +++++ .../thauvin/erik/mobibot/modules/PingTest.kt | 54 +++ .../mobibot/modules/RockPaperScissorsTest.kt | 50 ++ .../erik/mobibot/modules/StockQuoteTest.kt | 85 ++++ .../erik/mobibot/modules/Weather2Test.kt | 117 +++++ .../erik/mobibot/modules/WolframAlphaTest.kt | 77 +++ .../erik/mobibot/modules/WordTimeTest.kt | 70 +++ .../thauvin/erik/mobibot/msg/MessageTest.kt | 109 +++++ bitbucket-pipelines.yml | 9 +- bld | 2 + bld.bat | 4 + build.gradle | 247 ---------- deploy.sh | 2 +- gradle.properties | 0 gradle/wrapper/gradle-wrapper.jar | Bin 63721 -> 0 bytes gradle/wrapper/gradle-wrapper.properties | 7 - gradlew | 249 ---------- gradlew.bat | 92 ---- lib/bld/bld-wrapper.jar | Bin 0 -> 27321 bytes lib/bld/bld-wrapper.properties | 10 + release_info.txt | 27 ++ settings.gradle | 18 - sonar-project.properties | 7 + .../java/net/thauvin/erik/MobibotBuild.java | 170 +++++++ .../net/thauvin/erik/mobibot/modules/War.java | 108 ----- .../kotlin/net/thauvin/erik/mobibot/Addons.kt | 2 +- .../net/thauvin/erik/mobibot/Constants.kt | 2 +- .../net/thauvin/erik/mobibot/FeedReader.kt | 2 +- .../net/thauvin/erik/mobibot/Mobibot.kt | 6 +- .../net/thauvin/erik/mobibot/Pinboard.kt | 2 +- .../net/thauvin/erik/mobibot/ReleaseInfo.kt | 27 ++ .../kotlin/net/thauvin/erik/mobibot/Utils.kt | 2 +- .../erik/mobibot/commands/AbstractCommand.kt | 2 +- .../erik/mobibot/commands/ChannelFeed.kt | 2 +- .../thauvin/erik/mobibot/commands/Cycle.kt | 2 +- .../net/thauvin/erik/mobibot/commands/Die.kt | 2 +- .../thauvin/erik/mobibot/commands/Ignore.kt | 2 +- .../net/thauvin/erik/mobibot/commands/Info.kt | 2 +- .../net/thauvin/erik/mobibot/commands/Me.kt | 2 +- .../thauvin/erik/mobibot/commands/Modules.kt | 2 +- .../net/thauvin/erik/mobibot/commands/Msg.kt | 2 +- .../net/thauvin/erik/mobibot/commands/Nick.kt | 2 +- .../thauvin/erik/mobibot/commands/Recap.kt | 2 +- .../net/thauvin/erik/mobibot/commands/Say.kt | 2 +- .../thauvin/erik/mobibot/commands/Users.kt | 2 +- .../thauvin/erik/mobibot/commands/Versions.kt | 4 +- .../erik/mobibot/commands/links/Comment.kt | 2 +- .../mobibot/commands/links/LinksManager.kt | 2 +- .../erik/mobibot/commands/links/Posting.kt | 2 +- .../erik/mobibot/commands/links/Tags.kt | 2 +- .../erik/mobibot/commands/links/View.kt | 2 +- .../mobibot/commands/seen/NickComparator.kt | 2 +- .../erik/mobibot/commands/seen/Seen.kt | 2 +- .../erik/mobibot/commands/seen/SeenNick.kt | 2 +- .../erik/mobibot/commands/tell/Tell.kt | 2 +- .../erik/mobibot/commands/tell/TellManager.kt | 2 +- .../erik/mobibot/commands/tell/TellMessage.kt | 2 +- .../thauvin/erik/mobibot/entries/Entries.kt | 2 +- .../erik/mobibot/entries/EntriesUtils.kt | 2 +- .../erik/mobibot/entries/EntryComment.kt | 2 +- .../thauvin/erik/mobibot/entries/EntryLink.kt | 2 +- .../erik/mobibot/entries/FeedsManager.kt | 2 +- .../erik/mobibot/modules/AbstractModule.kt | 2 +- .../net/thauvin/erik/mobibot/modules/Calc.kt | 2 +- .../thauvin/erik/mobibot/modules/ChatGpt.kt | 2 +- .../erik/mobibot/modules/CryptoPrices.kt | 4 +- .../erik/mobibot/modules/CurrencyConverter.kt | 2 +- .../net/thauvin/erik/mobibot/modules/Dice.kt | 2 +- .../erik/mobibot/modules/GoogleSearch.kt | 2 +- .../net/thauvin/erik/mobibot/modules/Joke.kt | 2 +- .../thauvin/erik/mobibot/modules/Lookup.kt | 2 +- .../thauvin/erik/mobibot/modules/Mastodon.kt | 2 +- .../erik/mobibot/modules/ModuleException.kt | 2 +- .../net/thauvin/erik/mobibot/modules/Ping.kt | 2 +- .../erik/mobibot/modules/RockPaperScissors.kt | 2 +- .../erik/mobibot/modules/StockQuote.kt | 2 +- .../net/thauvin/erik/mobibot/modules/War.kt | 89 ++++ .../thauvin/erik/mobibot/modules/Weather2.kt | 2 +- .../erik/mobibot/modules/WolframAlpha.kt | 2 +- .../thauvin/erik/mobibot/modules/WorldTime.kt | 2 +- .../thauvin/erik/mobibot/msg/ErrorMessage.kt | 2 +- .../net/thauvin/erik/mobibot/msg/Message.kt | 6 +- .../thauvin/erik/mobibot/msg/NoticeMessage.kt | 2 +- .../erik/mobibot/msg/PrivateMessage.kt | 2 +- .../thauvin/erik/mobibot/msg/PublicMessage.kt | 2 +- .../erik/mobibot/social/SocialManager.kt | 2 +- .../erik/mobibot/social/SocialModule.kt | 2 +- .../erik/mobibot/social/SocialTimer.kt | 2 +- src/main/resources/log4j2.xml | 38 ++ .../net/thauvin/erik/mobibot/AddonsTest.kt | 4 +- .../net/thauvin/erik/mobibot/DisableOnCi.kt | 44 ++ .../erik/mobibot/DisableOnCiCondition.kt | 51 ++ .../erik/mobibot/ExceptionSanitizer.kt | 2 +- .../thauvin/erik/mobibot/FeedReaderTest.kt | 4 +- .../thauvin/erik/mobibot/LocalProperties.kt | 6 +- .../net/thauvin/erik/mobibot/PinboardTest.kt | 8 +- .../net/thauvin/erik/mobibot/UtilsTest.kt | 8 +- .../thauvin/erik/mobibot/commands/InfoTest.kt | 6 +- .../erik/mobibot/commands/RecapTest.kt | 6 +- .../commands/links/LinksManagerTest.kt | 10 +- .../erik/mobibot/commands/links/ViewTest.kt | 6 +- .../erik/mobibot/commands/seen/SeenTest.kt | 52 ++- .../mobibot/commands/tell/TellMessageTest.kt | 6 +- .../commands/tell/TellMessagesMgrTest.kt | 30 +- .../erik/mobibot/entries/EntriesUtilsTest.kt | 12 +- .../erik/mobibot/entries/EntryLinkTest.kt | 12 +- .../erik/mobibot/entries/FeedMgrTest.kt | 10 +- .../thauvin/erik/mobibot/modules/CalcTest.kt | 6 +- .../erik/mobibot/modules/ChatGptTest.kt | 10 +- .../erik/mobibot/modules/CryptoPricesTest.kt | 13 +- .../mobibot/modules/CurrencyConverterTest.kt | 12 +- .../thauvin/erik/mobibot/modules/DiceTest.kt | 6 +- .../erik/mobibot/modules/GoogleSearchTest.kt | 10 +- .../thauvin/erik/mobibot/modules/JokeTest.kt | 6 +- .../erik/mobibot/modules/LookupTest.kt | 8 +- .../erik/mobibot/modules/MastodonTest.kt | 6 +- .../mobibot/modules/ModuleExceptionTest.kt | 34 +- .../thauvin/erik/mobibot/modules/PingTest.kt | 8 +- .../mobibot/modules/RockPaperScissorsTest.kt | 6 +- .../erik/mobibot/modules/StockQuoteTest.kt | 6 +- .../erik/mobibot/modules/Weather2Test.kt | 12 +- .../erik/mobibot/modules/WolframAlphaTest.kt | 10 +- .../erik/mobibot/modules/WordTimeTest.kt | 8 +- .../thauvin/erik/mobibot/msg/MessageTest.kt | 4 +- src/test/resources/current.xml | 31 -- version.mustache | 32 -- version.properties | 9 - 240 files changed, 11508 insertions(+), 1650 deletions(-) create mode 100644 .idea/app.iml create mode 100644 .idea/bld.iml delete mode 100644 .idea/codeStyles/Project.xml delete mode 100644 .idea/codeStyles/codeStyleConfig.xml delete mode 100644 .idea/compiler.xml rename .idea/copyright/{Erik_s_Copyright_Notice.xml => BSD_3.xml} (93%) delete mode 100644 .idea/jarRepositories.xml delete mode 100644 .idea/kotlinc.xml create mode 100644 .idea/libraries/bld.xml create mode 100644 .idea/libraries/compile.xml create mode 100644 .idea/libraries/runtime.xml create mode 100644 .idea/libraries/test.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/runConfigurations/Run Tests.xml create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 bin/main/log4j2.xml create mode 100644 bin/main/net/thauvin/erik/mobibot/Addons.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/Constants.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/FeedReader.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/Mobibot.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/Pinboard.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/Utils.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/commands/AbstractCommand.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/commands/ChannelFeed.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/commands/Cycle.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/commands/Die.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/commands/Ignore.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/commands/Info.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/commands/Me.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/commands/Modules.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/commands/Msg.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/commands/Nick.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/commands/Recap.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/commands/Say.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/commands/Users.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/commands/Versions.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/commands/links/Comment.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/commands/links/LinksManager.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/commands/links/Posting.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/commands/links/Tags.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/commands/links/View.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/commands/seen/Seen.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/commands/tell/Tell.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/commands/tell/TellManager.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/entries/Entries.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/entries/EntriesUtils.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/entries/EntryComment.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/entries/EntryLink.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/entries/FeedsManager.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/modules/AbstractModule.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/modules/Calc.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/modules/ChatGpt.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/modules/CryptoPrices.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/modules/Dice.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/modules/GoogleSearch.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/modules/Joke.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/modules/Lookup.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/modules/Mastodon.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/modules/ModuleException.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/modules/Ping.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/modules/StockQuote.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/modules/War.class create mode 100644 bin/main/net/thauvin/erik/mobibot/modules/Weather2.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/modules/WolframAlpha.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/modules/WorldTime.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/msg/ErrorMessage.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/msg/Message.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/msg/NoticeMessage.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/msg/PrivateMessage.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/msg/PublicMessage.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/social/SocialManager.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/social/SocialModule.kt create mode 100644 bin/main/net/thauvin/erik/mobibot/social/SocialTimer.kt create mode 100644 bin/test/current.xml create mode 100644 bin/test/net/thauvin/erik/mobibot/AddonsTest.kt create mode 100644 bin/test/net/thauvin/erik/mobibot/ExceptionSanitizer.kt create mode 100644 bin/test/net/thauvin/erik/mobibot/FeedReaderTest.kt create mode 100644 bin/test/net/thauvin/erik/mobibot/LocalProperties.kt create mode 100644 bin/test/net/thauvin/erik/mobibot/PinboardTest.kt create mode 100644 bin/test/net/thauvin/erik/mobibot/UtilsTest.kt create mode 100644 bin/test/net/thauvin/erik/mobibot/commands/InfoTest.kt create mode 100644 bin/test/net/thauvin/erik/mobibot/commands/RecapTest.kt create mode 100644 bin/test/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt create mode 100644 bin/test/net/thauvin/erik/mobibot/commands/links/ViewTest.kt create mode 100644 bin/test/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt create mode 100644 bin/test/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt create mode 100644 bin/test/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt create mode 100644 bin/test/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt create mode 100644 bin/test/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt create mode 100644 bin/test/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt create mode 100644 bin/test/net/thauvin/erik/mobibot/modules/CalcTest.kt create mode 100644 bin/test/net/thauvin/erik/mobibot/modules/ChatGptTest.kt create mode 100644 bin/test/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt create mode 100644 bin/test/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt create mode 100644 bin/test/net/thauvin/erik/mobibot/modules/DiceTest.kt create mode 100644 bin/test/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt create mode 100644 bin/test/net/thauvin/erik/mobibot/modules/JokeTest.kt create mode 100644 bin/test/net/thauvin/erik/mobibot/modules/LookupTest.kt create mode 100644 bin/test/net/thauvin/erik/mobibot/modules/MastodonTest.kt create mode 100644 bin/test/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt create mode 100644 bin/test/net/thauvin/erik/mobibot/modules/PingTest.kt create mode 100644 bin/test/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt create mode 100644 bin/test/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt create mode 100644 bin/test/net/thauvin/erik/mobibot/modules/Weather2Test.kt create mode 100644 bin/test/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt create mode 100644 bin/test/net/thauvin/erik/mobibot/modules/WordTimeTest.kt create mode 100644 bin/test/net/thauvin/erik/mobibot/msg/MessageTest.kt create mode 100755 bld create mode 100644 bld.bat delete mode 100644 build.gradle delete mode 100644 gradle.properties delete mode 100644 gradle/wrapper/gradle-wrapper.jar delete mode 100644 gradle/wrapper/gradle-wrapper.properties delete mode 100755 gradlew delete mode 100644 gradlew.bat create mode 100644 lib/bld/bld-wrapper.jar create mode 100644 lib/bld/bld-wrapper.properties create mode 100644 release_info.txt delete mode 100644 settings.gradle create mode 100644 sonar-project.properties create mode 100644 src/bld/java/net/thauvin/erik/MobibotBuild.java delete mode 100644 src/main/java/net/thauvin/erik/mobibot/modules/War.java create mode 100644 src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt create mode 100644 src/main/kotlin/net/thauvin/erik/mobibot/modules/War.kt create mode 100644 src/main/resources/log4j2.xml create mode 100644 src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCi.kt create mode 100644 src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCiCondition.kt delete mode 100644 version.mustache delete mode 100644 version.properties diff --git a/.circleci/config.yml b/.circleci/config.yml index 1868b37..77889be 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -6,49 +6,39 @@ defaults: &defaults TERM: dumb CI_NAME: "CircleCI" -defaults_gradle: &defaults_gradle +defaults_gradle: &defaults_bld steps: - checkout - - restore_cache: - keys: - - gradle-dependencies-{{ checksum "build.gradle" }} - # fallback to using the latest cache if no exact match is found - - gradle-dependencies- - run: - name: Gradle Dependencies - command: ./gradlew dependencies - - save_cache: - paths: - - ~/.m2 - key: gradle-dependencies-{{ checksum "build.gradle" }} + name: Download the bld dependencies + command: ./bld download - run: - name: Run All Checks - command: ./gradlew check - - store_artifacts: - path: build/reports/ - destination: reports - - store_test_results: - path: build/reports/ + name: Compile source with bld + command: ./bld compile + - run: + name: Run tests with bld + command: ./bld test jobs: - build_gradle_jdk17: + bld_jdk17: <<: *defaults docker: - image: cimg/openjdk:17.0 - <<: *defaults_gradle + <<: *defaults_bld - build_gradle_jdk19: + bld_jdk20: <<: *defaults docker: - - image: cimg/openjdk:19.0 + - image: cimg/openjdk:20.0 - <<: *defaults_gradle + <<: *defaults_bld workflows: version: 2 - gradle: + bld: jobs: - - build_gradle_jdk17 + - bld_jdk17 + - bld_jdk20 diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index aa034f9..ae6c66f 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -1,21 +1,21 @@ -name: gradle-ci +name: bld-ci on: [ push, pull_request, workflow_dispatch ] jobs: - build: + build-bld-project: runs-on: ubuntu-latest env: - GRADLE_OPTS: "-Dorg.gradle.jvmargs=-XX:MaxMetaspaceSize=512m" - SONAR_JDK: "17" + COVERAGE_SDK: "17" strategy: matrix: java-version: [ 17, 20 ] steps: - - uses: actions/checkout@v3 + - name: Checkout source repository + uses: actions/checkout@v3 with: fetch-depth: 0 @@ -25,35 +25,21 @@ jobs: distribution: 'zulu' java-version: ${{ matrix.java-version }} - - name: Grant execute permission for gradlew - run: chmod +x gradlew + - name: Grant bld execute permission + run: chmod +x bld - - name: Cache SonarCloud packages - if: matrix.java-version == env.SONAR_JDK - uses: actions/cache@v3 - with: - path: ~/.sonar/cache - key: ${{ runner.os }}-sonar - restore-keys: ${{ runner.os }}-sonar + - name: Download the bld dependencies + run: ./bld download - - name: Test with Gradle - uses: gradle/gradle-build-action@v2 - env: - CI_NAME: "GitHub CI" - ALPHAVANTAGE_API_KEY: ${{ secrets.ALPHAVANTAGE_API_KEY }} - CHATGPT_API_KEY: ${{ secrets.CHATGPT_API_KEY }} - OWM_API_KEY: ${{ secrets.OWM_API_KEY }} - PINBOARD_API_TOKEN: ${{ secrets.PINBOARD_API_TOKEN }} - MASTODON_ACCESS_TOKEN: ${{ secrets.MASTODON_ACCESS_TOKEN }} - MASTODON_HANDLE: ${{ secrets.MASTODON_HANDLE }} - MASTODON_INSTANCE: ${{ secrets.MASTODON_INSTANCE }} - EXCHANGERATE_API_KEY: ${{ secrets.EXCHANGERATE_API_KEY }} - with: - arguments: build check --stacktrace + - name: Compile source with bld + run: ./bld compile - - name: SonarCloud - if: success() && matrix.java-version == env.SONAR_JDK + - name: Run tests with bld + run: ./bld jacoco + + - name: SonarCloud Scan + uses: sonarsource/sonarcloud-github-action@master + if: success() && matrix.java-version == env.COVERAGE_SDK env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - run: ./gradlew sonar --info diff --git a/.gitignore b/.gitignore index 970cefd..fa550e5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,89 +1,61 @@ -!.vscode/extensions.json -!.vscode/launch.json -!.vscode/settings.json -!.vscode/tasks.json -!gradle-wrapper.jar -!properties/* -*.class -*.code-workspace -*.ctxt -*.ear -*.iws -*.jar -*.log -*.nar -*.rar -*.sublime-* -*.tar.gz -*.war -*.zip -.DS_Store -.classpath -.gradle -.history -.idea/**/caches/build_file_checksums.ser -.idea/**/contentModel.xml -.idea/**/dataSources.ids -.idea/**/dataSources.local.xml -.idea/**/dataSources/ -.idea/**/dbnavigator.xml -.idea/**/dictionaries -.idea/**/dynamic.xml -.idea/**/gradle.xml -.idea/**/httpRequests -.idea/**/libraries -.idea/**/mongoSettings.xml -.idea/**/replstate.xml -.idea/**/shelf -.idea/**/shelf/ -.idea/**/sonarlint* -.idea/**/sqlDataSources.xml -.idea/**/tasks.xml -.idea/**/uiDesigner.xml -.idea/**/usage.statistics.xml -.idea/**/workspace.xml -.idea_modules/ -.kobalt -.mtj.tmp/ -.mvn/timing.properties -.mvn/wrapper/maven-wrapper.jar -.nb-gradle -.project -.scannerwork -.settings -.vscode/* -Thumbs.db -__pycache__ -atlassian-ide-plugin.xml -bin/ -build/ -cmake-build-*/ -com_crashlytics_export_strings.xml -crashlytics-build.properties -crashlytics.properties -dependency-reduced-pom.xml -deploy/ -dist/ -ehthumbs.db -fabric.properties -gen/ -hs_err_pid* -kobaltBuild -kobaltw*-test -lib/kotlin* -libs/ -local.properties -log4j2.xml -logs/ -mobibot.properties -out/ -pom.xml.next -pom.xml.releaseBackup -pom.xml.tag -pom.xml.versionsBackup -proguard-project.txt -project.properties -release.properties -target/ -test-output -venv +.gradle +.DS_Store +build +lib/bld/** +!lib/bld/bld-wrapper.jar +!lib/bld/bld-wrapper.properties +lib/compile/ +lib/runtime/ +lib/standalone/ +lib/test/ + +# IDEA ignores + +# User-specific +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Editor-based Rest Client +.idea/httpRequests + +local.properties + +deploy +logs +mobibot.properties diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 48a3396..052df48 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,32 +1,11 @@ -image: gradle:8-jdk17 - -variables: - GRADLE_OPTS: "-Dorg.gradle.daemon=false" - CI_NAME: "GitLab CI" - -before_script: - - export GRADLE_USER_HOME=`pwd`/.gradle +image: openjdk:17 stages: - - build - test -build: - stage: build - script: gradle --build-cache assemble - cache: - key: "$CI_COMMIT_REF_NAME" - policy: push - paths: - - build - - .gradle - test: stage: test - script: gradle check - cache: - key: "$CI_COMMIT_REF_NAME" - policy: pull - paths: - - build - - .gradle + script: + - ./bld download + - ./bld compile + - ./bld test diff --git a/.idea/app.iml b/.idea/app.iml new file mode 100644 index 0000000..2c1fe21 --- /dev/null +++ b/.idea/app.iml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<module type="JAVA_MODULE" version="4"> + <component name="NewModuleRootManager"> + <output url="file://$MODULE_DIR$/build/main" /> + <output-test url="file://$MODULE_DIR$/build/test" /> + <exclude-output /> + <content url="file://$MODULE_DIR$"> + <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" /> + <sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" relativeOutputPath="resources" /> + <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" /> + <sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" /> + <sourceFolder url="file://$MODULE_DIR$/src/main/kotlin" isTestSource="false" /> + <sourceFolder url="file://$MODULE_DIR$/src/test/kotlin" isTestSource="true" /> + </content> + <orderEntry type="inheritedJdk" /> + <orderEntry type="sourceFolder" forTests="false" /> + <orderEntry type="module-library" scope="RUNTIME"> + <library> + <CLASSES> + <root url="file://$MODULE_DIR$/src/main/resources/templates" /> + </CLASSES> + <JAVADOC /> + <SOURCES /> + </library> + </orderEntry> + <orderEntry type="library" name="compile" level="project" /> + <orderEntry type="library" scope="RUNTIME" name="runtime" level="project" /> + <orderEntry type="library" scope="TEST" name="test" level="project" /> + </component> +</module> \ No newline at end of file diff --git a/.idea/bld.iml b/.idea/bld.iml new file mode 100644 index 0000000..e63e11e --- /dev/null +++ b/.idea/bld.iml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<module type="JAVA_MODULE" version="4"> + <component name="NewModuleRootManager"> + <output url="file://$MODULE_DIR$/build/bld" /> + <output-test url="file://$MODULE_DIR$/build/bld" /> + <exclude-output /> + <content url="file://$MODULE_DIR$/src/bld"> + <sourceFolder url="file://$MODULE_DIR$/src/bld/java" isTestSource="false" /> + </content> + <orderEntry type="inheritedJdk" /> + <orderEntry type="sourceFolder" forTests="false" /> + <orderEntry type="library" name="bld" level="project" /> + </component> +</module> \ No newline at end of file diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml deleted file mode 100644 index 10aa334..0000000 --- a/.idea/codeStyles/Project.xml +++ /dev/null @@ -1,298 +0,0 @@ -<component name="ProjectCodeStyleConfiguration"> - <code_scheme name="Project" version="200"> - <JetCodeStyleSettings> - <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" /> - </JetCodeStyleSettings> - <codeStyleSettings language="JAVA"> - <option name="IF_BRACE_FORCE" value="1" /> - <arrangement> - <groups> - <group> - <type>OVERRIDDEN_METHODS</type> - <order>BY_NAME</order> - </group> - </groups> - <rules> - <section> - <rule> - <match> - <AND> - <FIELD>true</FIELD> - <FINAL>true</FINAL> - <PUBLIC>true</PUBLIC> - <STATIC>true</STATIC> - </AND> - </match> - <order>BY_NAME</order> - </rule> - </section> - <section> - <rule> - <match> - <AND> - <FIELD>true</FIELD> - <FINAL>true</FINAL> - <PROTECTED>true</PROTECTED> - <STATIC>true</STATIC> - </AND> - </match> - <order>BY_NAME</order> - </rule> - </section> - <section> - <rule> - <match> - <AND> - <FIELD>true</FIELD> - <FINAL>true</FINAL> - <PACKAGE_PRIVATE>true</PACKAGE_PRIVATE> - <STATIC>true</STATIC> - </AND> - </match> - <order>BY_NAME</order> - </rule> - </section> - <section> - <rule> - <match> - <AND> - <FIELD>true</FIELD> - <FINAL>true</FINAL> - <PRIVATE>true</PRIVATE> - <STATIC>true</STATIC> - </AND> - </match> - <order>BY_NAME</order> - </rule> - </section> - <section> - <rule> - <match> - <AND> - <FIELD>true</FIELD> - <PUBLIC>true</PUBLIC> - <STATIC>true</STATIC> - </AND> - </match> - <order>BY_NAME</order> - </rule> - </section> - <section> - <rule> - <match> - <AND> - <FIELD>true</FIELD> - <PROTECTED>true</PROTECTED> - <STATIC>true</STATIC> - <visibility /> - </AND> - </match> - <order>BY_NAME</order> - </rule> - </section> - <section> - <rule> - <match> - <AND> - <FIELD>true</FIELD> - <PACKAGE_PRIVATE>true</PACKAGE_PRIVATE> - <STATIC>true</STATIC> - </AND> - </match> - <order>BY_NAME</order> - </rule> - </section> - <section> - <rule> - <match> - <AND> - <FIELD>true</FIELD> - <PRIVATE>true</PRIVATE> - <STATIC>true</STATIC> - </AND> - </match> - <order>BY_NAME</order> - </rule> - </section> - <section> - <rule> - <match> - <AND> - <INITIALIZER_BLOCK>true</INITIALIZER_BLOCK> - <STATIC>true</STATIC> - </AND> - </match> - </rule> - </section> - <section> - <rule> - <match> - <AND> - <FIELD>true</FIELD> - <FINAL>true</FINAL> - <PUBLIC>true</PUBLIC> - </AND> - </match> - <order>BY_NAME</order> - </rule> - </section> - <section> - <rule> - <match> - <AND> - <FIELD>true</FIELD> - <FINAL>true</FINAL> - <PROTECTED>true</PROTECTED> - </AND> - </match> - <order>BY_NAME</order> - </rule> - </section> - <section> - <rule> - <match> - <AND> - <FIELD>true</FIELD> - <FINAL>true</FINAL> - <PACKAGE_PRIVATE>true</PACKAGE_PRIVATE> - </AND> - </match> - <order>BY_NAME</order> - </rule> - </section> - <section> - <rule> - <match> - <AND> - <FIELD>true</FIELD> - <FINAL>true</FINAL> - <PRIVATE>true</PRIVATE> - </AND> - </match> - <order>BY_NAME</order> - </rule> - </section> - <section> - <rule> - <match> - <AND> - <FIELD>true</FIELD> - <PUBLIC>true</PUBLIC> - </AND> - </match> - <order>BY_NAME</order> - </rule> - </section> - <section> - <rule> - <match> - <AND> - <FIELD>true</FIELD> - <PROTECTED>true</PROTECTED> - </AND> - </match> - <order>BY_NAME</order> - </rule> - </section> - <section> - <rule> - <match> - <AND> - <FIELD>true</FIELD> - <PACKAGE_PRIVATE>true</PACKAGE_PRIVATE> - </AND> - </match> - <order>BY_NAME</order> - </rule> - </section> - <section> - <rule> - <match> - <AND> - <FIELD>true</FIELD> - <PRIVATE>true</PRIVATE> - </AND> - </match> - <order>BY_NAME</order> - </rule> - </section> - <section> - <rule> - <match> - <FIELD>true</FIELD> - </match> - <order>BY_NAME</order> - </rule> - </section> - <section> - <rule> - <match> - <INITIALIZER_BLOCK>true</INITIALIZER_BLOCK> - </match> - </rule> - </section> - <section> - <rule> - <match> - <CONSTRUCTOR>true</CONSTRUCTOR> - </match> - </rule> - </section> - <section> - <rule> - <match> - <AND> - <METHOD>true</METHOD> - <STATIC>true</STATIC> - </AND> - </match> - <order>BY_NAME</order> - </rule> - </section> - <section> - <rule> - <match> - <METHOD>true</METHOD> - </match> - <order>BY_NAME</order> - </rule> - </section> - <section> - <rule> - <match> - <ENUM>true</ENUM> - </match> - </rule> - </section> - <section> - <rule> - <match> - <INTERFACE>true</INTERFACE> - </match> - </rule> - </section> - <section> - <rule> - <match> - <AND> - <CLASS>true</CLASS> - <STATIC>true</STATIC> - </AND> - </match> - </rule> - </section> - <section> - <rule> - <match> - <CLASS>true</CLASS> - </match> - </rule> - </section> - </rules> - </arrangement> - </codeStyleSettings> - <codeStyleSettings language="kotlin"> - <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" /> - </codeStyleSettings> - </code_scheme> -</component> \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml deleted file mode 100644 index 23f4bb5..0000000 --- a/.idea/codeStyles/codeStyleConfig.xml +++ /dev/null @@ -1,6 +0,0 @@ -<component name="ProjectCodeStyleConfiguration"> - <state> - <option name="USE_PER_PROJECT_SETTINGS" value="true" /> - <option name="PREFERRED_PROJECT_CODE_STYLE" value="Erik's Code Style" /> - </state> -</component> \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml deleted file mode 100644 index b589d56..0000000 --- a/.idea/compiler.xml +++ /dev/null @@ -1,6 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project version="4"> - <component name="CompilerConfiguration"> - <bytecodeTargetLevel target="17" /> - </component> -</project> \ No newline at end of file diff --git a/.idea/copyright/Erik_s_Copyright_Notice.xml b/.idea/copyright/BSD_3.xml similarity index 93% rename from .idea/copyright/Erik_s_Copyright_Notice.xml rename to .idea/copyright/BSD_3.xml index 055999a..275eca9 100644 --- a/.idea/copyright/Erik_s_Copyright_Notice.xml +++ b/.idea/copyright/BSD_3.xml @@ -1,6 +1,6 @@ <component name="CopyrightManager"> <copyright> - <option name="notice" value="&#36;file.fileName Copyright 2004-&#36;today.year Erik C. Thauvin (erik@thauvin.net) Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of this project nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." /> - <option name="myName" value="Erik's Copyright Notice" /> + <option name="notice" value="&#36;file.fileName Copyright 2021-&#36;today.year Erik C. Thauvin (erik@thauvin.net) Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of this project nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." /> + <option name="myName" value="BSD-3" /> </copyright> </component> \ No newline at end of file diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml index 1419e40..3203074 100644 --- a/.idea/copyright/profiles_settings.xml +++ b/.idea/copyright/profiles_settings.xml @@ -1,3 +1,3 @@ <component name="CopyrightManager"> - <settings default="Erik's Copyright Notice" /> + <settings default="BSD-3" /> </component> \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index 60682bf..1e01b48 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -1,72 +1,8 @@ <component name="InspectionProjectProfileManager"> <profile version="1.0"> <option name="myName" value="Project Default" /> - <inspection_tool class="JavaDoc" enabled="true" level="WARNING" enabled_by_default="true"> - <option name="TOP_LEVEL_CLASS_OPTIONS"> - <value> - <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" /> - <option name="REQUIRED_TAGS" value="" /> - </value> - </option> - <option name="INNER_CLASS_OPTIONS"> - <value> - <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" /> - <option name="REQUIRED_TAGS" value="" /> - </value> - </option> - <option name="METHOD_OPTIONS"> - <value> - <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" /> - <option name="REQUIRED_TAGS" value="@return@param@throws or @exception" /> - </value> - </option> - <option name="FIELD_OPTIONS"> - <value> - <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" /> - <option name="REQUIRED_TAGS" value="" /> - </value> - </option> - <option name="IGNORE_DEPRECATED" value="false" /> - <option name="IGNORE_JAVADOC_PERIOD" value="true" /> - <option name="IGNORE_DUPLICATED_THROWS" value="false" /> - <option name="IGNORE_POINT_TO_ITSELF" value="false" /> - <option name="myAdditionalJavadocTags" value="created" /> - </inspection_tool> <inspection_tool class="JavadocDeclaration" enabled="true" level="WARNING" enabled_by_default="true"> <option name="ADDITIONAL_TAGS" value="created" /> </inspection_tool> - <inspection_tool class="MissingJavadoc" enabled="true" level="WARNING" enabled_by_default="true"> - <option name="PACKAGE_SETTINGS"> - <Options> - <option name="ENABLED" value="false" /> - </Options> - </option> - <option name="MODULE_SETTINGS"> - <Options> - <option name="ENABLED" value="false" /> - </Options> - </option> - <option name="TOP_LEVEL_CLASS_SETTINGS"> - <Options> - <option name="ENABLED" value="false" /> - </Options> - </option> - <option name="INNER_CLASS_SETTINGS"> - <Options> - <option name="ENABLED" value="false" /> - </Options> - </option> - <option name="METHOD_SETTINGS"> - <Options> - <option name="REQUIRED_TAGS" value="@return@param@throws or @exception" /> - <option name="ENABLED" value="false" /> - </Options> - </option> - <option name="FIELD_SETTINGS"> - <Options> - <option name="ENABLED" value="false" /> - </Options> - </option> - </inspection_tool> </profile> </component> \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml deleted file mode 100644 index 0e29f96..0000000 --- a/.idea/jarRepositories.xml +++ /dev/null @@ -1,45 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project version="4"> - <component name="RemoteRepositoriesConfiguration"> - <remote-repository> - <option name="id" value="central" /> - <option name="name" value="Maven Central repository" /> - <option name="url" value="https://repo1.maven.org/maven2" /> - </remote-repository> - <remote-repository> - <option name="id" value="jboss.community" /> - <option name="name" value="JBoss Community repository" /> - <option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" /> - </remote-repository> - <remote-repository> - <option name="id" value="MavenLocal" /> - <option name="name" value="MavenLocal" /> - <option name="url" value="file:$MAVEN_REPOSITORY$/" /> - </remote-repository> - <remote-repository> - <option name="id" value="MavenLocal" /> - <option name="name" value="MavenLocal" /> - <option name="url" value="file:$MAVEN_REPOSITORY$/" /> - </remote-repository> - <remote-repository> - <option name="id" value="maven2" /> - <option name="name" value="maven2" /> - <option name="url" value="https://oss.sonatype.org/content/repositories/snapshots" /> - </remote-repository> - <remote-repository> - <option name="id" value="MavenRepo" /> - <option name="name" value="MavenRepo" /> - <option name="url" value="https://repo.maven.apache.org/maven2/" /> - </remote-repository> - <remote-repository> - <option name="id" value="maven" /> - <option name="name" value="maven" /> - <option name="url" value="https://jitpack.io" /> - </remote-repository> - <remote-repository> - <option name="id" value="MavenLocal" /> - <option name="name" value="MavenLocal" /> - <option name="url" value="file:$PROJECT_DIR$/../../maven/repository/" /> - </remote-repository> - </component> -</project> \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml deleted file mode 100644 index e805548..0000000 --- a/.idea/kotlinc.xml +++ /dev/null @@ -1,6 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project version="4"> - <component name="KotlinJpsPluginSettings"> - <option name="version" value="1.9.20" /> - </component> -</project> \ No newline at end of file diff --git a/.idea/libraries/bld.xml b/.idea/libraries/bld.xml new file mode 100644 index 0000000..cf75013 --- /dev/null +++ b/.idea/libraries/bld.xml @@ -0,0 +1,17 @@ +<component name="libraryTable"> + <library name="bld"> + <CLASSES> + <root url="file://$PROJECT_DIR$/lib/bld" /> + <root url="jar://$USER_HOME$/.bld/dist/bld-1.7.5.jar!/" /> + </CLASSES> + <JAVADOC /> + <SOURCES> + <root url="jar://$USER_HOME$/.bld/dist/bld-1.7.5-sources.jar!/" /> + </SOURCES> + <excluded> + <root url="jar://$PROJECT_DIR$/lib/bld/bld-wrapper.jar!/" /> + </excluded> + <jarDirectory url="file://$PROJECT_DIR$/lib/bld" recursive="false" /> + <jarDirectory url="file://$PROJECT_DIR$/lib/bld" recursive="false" type="SOURCES" /> + </library> +</component> \ No newline at end of file diff --git a/.idea/libraries/compile.xml b/.idea/libraries/compile.xml new file mode 100644 index 0000000..9bd86aa --- /dev/null +++ b/.idea/libraries/compile.xml @@ -0,0 +1,13 @@ +<component name="libraryTable"> + <library name="compile"> + <CLASSES> + <root url="file://$PROJECT_DIR$/lib/compile" /> + </CLASSES> + <JAVADOC /> + <SOURCES> + <root url="file://$PROJECT_DIR$/lib/compile" /> + </SOURCES> + <jarDirectory url="file://$PROJECT_DIR$/lib/compile" recursive="false" /> + <jarDirectory url="file://$PROJECT_DIR$/lib/compile" recursive="false" type="SOURCES" /> + </library> +</component> \ No newline at end of file diff --git a/.idea/libraries/runtime.xml b/.idea/libraries/runtime.xml new file mode 100644 index 0000000..2ae5c4b --- /dev/null +++ b/.idea/libraries/runtime.xml @@ -0,0 +1,14 @@ +<component name="libraryTable"> + <library name="runtime"> + <CLASSES> + <root url="file://$PROJECT_DIR$/lib/runtime" /> + <root url="file://$PROJECT_DIR$/src/main/resources" /> + </CLASSES> + <JAVADOC /> + <SOURCES> + <root url="file://$PROJECT_DIR$/lib/runtime" /> + </SOURCES> + <jarDirectory url="file://$PROJECT_DIR$/lib/runtime" recursive="false" /> + <jarDirectory url="file://$PROJECT_DIR$/lib/runtime" recursive="false" type="SOURCES" /> + </library> +</component> \ No newline at end of file diff --git a/.idea/libraries/test.xml b/.idea/libraries/test.xml new file mode 100644 index 0000000..b80486a --- /dev/null +++ b/.idea/libraries/test.xml @@ -0,0 +1,14 @@ +<component name="libraryTable"> + <library name="test"> + <CLASSES> + <root url="file://$PROJECT_DIR$/lib/test" /> + <root url="file://$PROJECT_DIR$/src/test/resources" /> + </CLASSES> + <JAVADOC /> + <SOURCES> + <root url="file://$PROJECT_DIR$/lib/test" /> + </SOURCES> + <jarDirectory url="file://$PROJECT_DIR$/lib/test" recursive="false" /> + <jarDirectory url="file://$PROJECT_DIR$/lib/test" recursive="false" type="SOURCES" /> + </library> +</component> \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index a59e398..e853f87 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,16 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> <project version="4"> - <component name="ExternalStorageConfigurationManager" enabled="true" /> - <component name="FrameworkDetectionExcludesConfiguration"> - <file type="web" url="file://$PROJECT_DIR$" /> + <component name="EntryPointsManager"> + <pattern value="net.thauvin.erik.MobibotBuild" method="deploy" /> + <pattern value="net.thauvin.erik.MobibotBuild" method="jacoco" /> + <pattern value="net.thauvin.erik.MobibotBuild" /> </component> <component name="PDMPlugin"> - <option name="customRuleSets"> - <list> - <option value="K:\java\semver\config\pmd.xml" /> - <option value="$PROJECT_DIR$/../../java/bld-exec/config/pmd.xml" /> - </list> - </option> <option name="skipTestSources" value="false" /> </component> - <component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="19" project-jdk-type="JavaSDK" /> + <component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="17" project-jdk-type="JavaSDK"> + <output url="file://$PROJECT_DIR$/build" /> + </component> </project> \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..55adcb9 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ProjectModuleManager"> + <modules> + <module fileurl="file://$PROJECT_DIR$/.idea/app.iml" filepath="$PROJECT_DIR$/.idea/app.iml" /> + <module fileurl="file://$PROJECT_DIR$/.idea/bld.iml" filepath="$PROJECT_DIR$/.idea/bld.iml" /> + </modules> + </component> +</project> \ No newline at end of file diff --git a/.idea/runConfigurations/Run Tests.xml b/.idea/runConfigurations/Run Tests.xml new file mode 100644 index 0000000..37dc742 --- /dev/null +++ b/.idea/runConfigurations/Run Tests.xml @@ -0,0 +1,9 @@ +<component name="ProjectRunConfigurationManager"> + <configuration default="false" name="Run Tests" type="Application" factoryName="Application" nameIsGenerated="true"> + <option name="MAIN_CLASS_NAME" value="net.thauvin.erik.MobibotTest" /> + <module name="app" /> + <method v="2"> + <option name="Make" enabled="true" /> + </method> + </configuration> +</component> \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..c6500f2 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,11 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "java", + "name": "Run Tests", + "request": "launch", + "mainClass": "net.thauvin.erik.MobibotTest" + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..133aa45 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,15 @@ +{ + "java.project.sourcePaths": [ + "src/main/java", + "src/main/resources", + "src/test/java", + "src/bld/java" + ], + "java.configuration.updateBuildConfiguration": "automatic", + "java.project.referencedLibraries": [ + "${HOME}/.bld/dist/bld-1.7.5.jar", + "lib/compile/*.jar", + "lib/runtime/*.jar", + "lib/test/*.jar" + ] +} diff --git a/README.md b/README.md index 1ecefeb..fbcacc2 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # mobibot [![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) -[![Kotlin](https://img.shields.io/badge/kotlin-1.9.10-7f52ff.svg)](https://kotlinlang.org) +[![Kotlin](https://img.shields.io/badge/kotlin-1.9.20-7f52ff.svg)](https://kotlinlang.org) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ethauvin_mobibot&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=ethauvin_mobibot) [![GitHub CI](https://github.com/ethauvin/mobibot/actions/workflows/gradle.yml/badge.svg)](https://github.com/ethauvin/mobibot/actions/workflows/gradle.yml) [![CircleCI](https://circleci.com/gh/ethauvin/mobibot/tree/master.svg?style=shield)](https://circleci.com/gh/ethauvin/mobibot/tree/master) @@ -14,8 +14,8 @@ Some very basic instructions: cd mobibot - # build with gradle - ./gradlew + # build JAR and deploy + ./bld jar deploy cd deploy diff --git a/bin/main/log4j2.xml b/bin/main/log4j2.xml new file mode 100644 index 0000000..265c88f --- /dev/null +++ b/bin/main/log4j2.xml @@ -0,0 +1,69 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ log4j2.xml + ~ + ~ Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + ~ + ~ Redistribution and use in source and binary forms, with or without + ~ modification, are permitted provided that the following conditions are met: + ~ + ~ Redistributions of source code must retain the above copyright notice, this + ~ list of conditions and the following disclaimer. + ~ + ~ Redistributions in binary form must reproduce the above copyright notice, + ~ this list of conditions and the following disclaimer in the documentation + ~ and/or other materials provided with the distribution. + ~ + ~ Neither the name of this project nor the names of its contributors may be + ~ used to endorse or promote products derived from this software without + ~ specific prior written permission. + ~ + ~ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + ~ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + ~ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + ~ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + ~ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + ~ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + ~ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + ~ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + ~ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + ~ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + --> + +<Configuration status="warn"> + <Appenders> + <Console name="stderr" target="SYSTEM_ERR"> + <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> + </Console> + <Console name="input" target="SYSTEM_OUT"> + <PatternLayout pattern="%d{UNIX_MILLIS} %msg%n"/> + <Filters> + <ThresholdFilter level="warn" onMatch="DENY" onMismatch="NEUTRAL"/> + <ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY"/> + </Filters> + </Console> + <Console name="output" target="SYSTEM_OUT"> + <PatternLayout pattern="%d{UNIX_MILLIS} >>>%msg%n"/> + <Filters> + <ThresholdFilter level="warn" onMatch="DENY" onMismatch="NEUTRAL"/> + <ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY"/> + </Filters> + </Console> + </Appenders> + <Loggers> + <Root level="warn" additivity="false"> + <AppenderRef ref="stderr"/> + </Root> + <logger level="debug" name="org.pircbotx.InputParser" additivity="false"> + <appender-ref ref="input"/> + <appender-ref ref="stderr" level="warn"/> + </logger> + <logger level="debug" name="org.pircbotx.output.OutputRaw" additivity="false"> + <appender-ref ref="output"/> + <appender-ref ref="stderr" level="warn"/> + </logger> + <logger level="trace" name="net.thauvin.erik.mobibot" additivity="false"> + <appender-ref ref="stderr"/> + </logger> + </Loggers> +</Configuration> diff --git a/bin/main/net/thauvin/erik/mobibot/Addons.kt b/bin/main/net/thauvin/erik/mobibot/Addons.kt new file mode 100644 index 0000000..2c5f05d --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/Addons.kt @@ -0,0 +1,190 @@ +/* + * Addons.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot + +import net.thauvin.erik.mobibot.Utils.notContains +import net.thauvin.erik.mobibot.commands.AbstractCommand +import net.thauvin.erik.mobibot.commands.links.LinksManager +import net.thauvin.erik.mobibot.modules.AbstractModule +import org.pircbotx.hooks.events.PrivateMessageEvent +import org.pircbotx.hooks.types.GenericMessageEvent +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import java.util.* + +/** + * Modules and Commands addons. + */ +class Addons(private val props: Properties) { + private val logger: Logger = LoggerFactory.getLogger(Addons::class.java) + private val disabledModules = props.getProperty("disabled-modules", "").split(LinksManager.TAG_MATCH) + private val disableCommands = props.getProperty("disabled-commands", "").split(LinksManager.TAG_MATCH) + + val commands: MutableList<AbstractCommand> = mutableListOf() + val modules: MutableList<AbstractModule> = mutableListOf() + val names = Names + + /** + * Add a module with properties. + */ + fun add(module: AbstractModule): Boolean { + var enabled = false + with(module) { + if (disabledModules.notContains(name, true)) { + if (hasProperties()) { + propertyKeys.forEach { + setProperty(it, props.getProperty(it, "")) + } + } + + if (isEnabled) { + modules.add(this) + names.modules.add(name) + names.commands.addAll(commands) + enabled = true + } else { + if (logger.isDebugEnabled) { + logger.debug("Module $name is disabled.") + } + names.disabledModules.add(name) + } + } else { + names.disabledModules.add(name) + } + } + return enabled + } + + /** + * Add a command with properties. + */ + fun add(command: AbstractCommand): Boolean { + var enabled = false + with(command) { + if (disableCommands.notContains(name, true)) { + if (properties.isNotEmpty()) { + properties.keys.forEach { + setProperty(it, props.getProperty(it, "")) + } + } + if (isEnabled()) { + commands.add(this) + if (isVisible) { + if (isOpOnly) { + names.ops.add(name) + } else { + names.commands.add(name) + } + } + enabled = true + } else { + if (logger.isDebugEnabled) { + logger.debug("Command $name is disabled.") + } + names.disabledCommands.add(name) + } + } else { + names.disabledCommands.add(name) + } + } + return enabled + } + + /** + * Execute a command or module. + */ + fun exec(channel: String, cmd: String, args: String, event: GenericMessageEvent): Boolean { + val cmds = if (event is PrivateMessageEvent) commands else commands.filter { it.isPublic } + for (command in cmds) { + if (command.name.startsWith(cmd)) { + command.commandResponse(channel, args, event) + return true + } + } + val mods = if (event is PrivateMessageEvent) modules.filter { it.isPrivateMsgEnabled } else modules + for (module in mods) { + if (module.commands.contains(cmd)) { + module.commandResponse(channel, cmd, args, event) + return true + } + } + return false + } + + /** + * Match a command. + */ + fun match(channel: String, event: GenericMessageEvent): Boolean { + for (command in commands) { + if (command.matches(event.message)) { + command.commandResponse(channel, event.message, event) + return true + } + } + return false + } + + /** + * Commands and Modules help. + */ + fun help(channel: String, topic: String, event: GenericMessageEvent): Boolean { + for (command in commands) { + if (command.isVisible && command.name.startsWith(topic)) { + return command.helpResponse(channel, topic, event) + } + } + for (module in modules) { + if (module.commands.contains(topic)) { + return module.helpResponse(event) + } + } + return false + } + + /** + * Holds commands and modules names. + */ + object Names { + val modules: MutableList<String> = mutableListOf() + val disabledModules: MutableList<String> = mutableListOf() + val commands: MutableList<String> = mutableListOf() + val disabledCommands: MutableList<String> = mutableListOf() + val ops: MutableList<String> = mutableListOf() + + fun sort() { + modules.sort() + disabledModules.sort() + commands.sort() + disabledCommands.sort() + ops.sort() + } + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/Constants.kt b/bin/main/net/thauvin/erik/mobibot/Constants.kt new file mode 100644 index 0000000..98ef74a --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/Constants.kt @@ -0,0 +1,102 @@ +/* + * Constants.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot + +/** + * The `Constants`. + */ +object Constants { + /** + * The connect/read timeout in ms. + */ + const val CONNECT_TIMEOUT = 5000 + + /** + * Debug command line argument. + */ + const val DEBUG_ARG = "debug" + + /** + * Default IRC Port. + */ + const val DEFAULT_PORT = 6667 + + /** + * Default IRC Server. + */ + const val DEFAULT_SERVER = "irc.libera.chat" + + /** + * CLI command for usage. + */ + const val CLI_CMD = "java -jar ${ReleaseInfo.PROJECT}.jar" + + /** + * User-Agent + */ + const val USER_AGENT = + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36" + + /** + * The help command. + */ + const val HELP_CMD = "help" + + /** + * The link command. + */ + const val LINK_CMD = "L" + + /** + * The empty title string. + */ + const val NO_TITLE = "No Title" + + /** + * Properties command line argument. + */ + const val PROPS_ARG = "properties" + + /** + * The tag command + */ + const val TAG_CMD = "T" + + /** + * The timer delay in minutes. + */ + const val TIMER_DELAY = 10L + + /** + * Properties version line argument. + */ + const val VERSION_ARG = "version" +} diff --git a/bin/main/net/thauvin/erik/mobibot/FeedReader.kt b/bin/main/net/thauvin/erik/mobibot/FeedReader.kt new file mode 100644 index 0000000..d82f011 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/FeedReader.kt @@ -0,0 +1,92 @@ +/* + * FeedReader.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot + +import com.rometools.rome.io.FeedException +import com.rometools.rome.io.SyndFeedInput +import com.rometools.rome.io.XmlReader +import net.thauvin.erik.mobibot.Utils.green +import net.thauvin.erik.mobibot.Utils.helpFormat +import net.thauvin.erik.mobibot.Utils.sendMessage +import net.thauvin.erik.mobibot.entries.FeedsManager +import net.thauvin.erik.mobibot.msg.Message +import net.thauvin.erik.mobibot.msg.NoticeMessage +import org.pircbotx.hooks.types.GenericMessageEvent +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import java.io.IOException +import java.net.URL + +/** + * Reads an RSS feed. + */ +class FeedReader(private val url: String, val event: GenericMessageEvent) : Runnable { + private val logger: Logger = LoggerFactory.getLogger(FeedsManager::class.java) + + /** + * Fetches the Feed's items. + */ + override fun run() { + try { + readFeed(url).forEach { + event.sendMessage("", it) + } + } catch (e: FeedException) { + if (logger.isWarnEnabled) logger.warn("Unable to parse the feed at $url", e) + event.sendMessage("An error has occurred while parsing the feed: ${e.message}") + } catch (e: IOException) { + if (logger.isWarnEnabled) logger.warn("Unable to fetch the feed at $url", e) + event.sendMessage("An IO error has occurred while fetching the feed: ${e.message}") + } + } + + companion object { + @JvmStatic + @Throws(FeedException::class, IOException::class) + fun readFeed(url: String, maxItems: Int = 5): List<Message> { + val messages = mutableListOf<Message>() + val input = SyndFeedInput() + XmlReader(URL(url).openStream()).use { reader -> + val feed = input.build(reader) + val items = feed.entries + if (items.isEmpty()) { + messages.add(NoticeMessage("There is currently nothing to view.")) + } else { + items.take(maxItems).forEach { + messages.add(NoticeMessage(it.title)) + messages.add(NoticeMessage(helpFormat(it.link.green(), false))) + } + } + } + return messages + } + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/Mobibot.kt b/bin/main/net/thauvin/erik/mobibot/Mobibot.kt new file mode 100644 index 0000000..f91c457 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/Mobibot.kt @@ -0,0 +1,421 @@ +/* + * Mobibot.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot + +import kotlinx.cli.ArgParser +import kotlinx.cli.ArgType +import kotlinx.cli.default +import net.thauvin.erik.mobibot.Utils.appendIfMissing +import net.thauvin.erik.mobibot.Utils.bot +import net.thauvin.erik.mobibot.Utils.capitalise +import net.thauvin.erik.mobibot.Utils.getIntProperty +import net.thauvin.erik.mobibot.Utils.helpCmdSyntax +import net.thauvin.erik.mobibot.Utils.helpFormat +import net.thauvin.erik.mobibot.Utils.isChannelOp +import net.thauvin.erik.mobibot.Utils.lastOrEmpty +import net.thauvin.erik.mobibot.Utils.sendList +import net.thauvin.erik.mobibot.Utils.sendMessage +import net.thauvin.erik.mobibot.Utils.toIsoLocalDate +import net.thauvin.erik.mobibot.commands.* +import net.thauvin.erik.mobibot.commands.Recap.Companion.storeRecap +import net.thauvin.erik.mobibot.commands.links.* +import net.thauvin.erik.mobibot.commands.seen.Seen +import net.thauvin.erik.mobibot.commands.tell.Tell +import net.thauvin.erik.mobibot.modules.* +import net.thauvin.erik.semver.Version +import org.pircbotx.Configuration +import org.pircbotx.PircBotX +import org.pircbotx.hooks.ListenerAdapter +import org.pircbotx.hooks.events.* +import org.pircbotx.hooks.types.GenericMessageEvent +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import java.io.* +import java.nio.file.Files +import java.nio.file.Paths +import java.util.* +import java.util.regex.Pattern +import kotlin.system.exitProcess + +@Version(properties = "version.properties", className = "ReleaseInfo", template = "version.mustache", type = "kt") +class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Properties) : ListenerAdapter() { + // The bot configuration. + private val config: Configuration + + // Commands and Modules + private val addons: Addons + + // Seen command + private val seen: Seen + + // Tell command + private val tell: Tell + + /** Logger. */ + val logger: Logger = LoggerFactory.getLogger(Mobibot::class.java) + + /** + * Connects to the server and joins the channel. + */ + fun connect() { + PircBotX(config).startBot() + } + + /** + * Responds with the default help. + */ + private fun helpDefault(event: GenericMessageEvent) { + event.sendMessage("Type a URL on $channel to post it.") + event.sendMessage("For more information on a specific command, type:") + event.sendMessage( + helpFormat( + helpCmdSyntax("%c ${Constants.HELP_CMD} <command>", event.bot().nick, event is PrivateMessageEvent) + ) + ) + event.sendMessage("The commands are:") + event.sendList(addons.names.commands, 8, isBold = true, isIndent = true) + if (event.isChannelOp(channel)) { + if (addons.names.disabledCommands.isNotEmpty()) { + event.sendMessage("The disabled commands are:") + event.sendList(addons.names.disabledCommands, 8, isBold = false, isIndent = true) + } + event.sendMessage("The op commands are:") + event.sendList(addons.names.ops, 8, isBold = true, isIndent = true) + } + } + + /** + * Responds with the default, commands or modules help. + */ + private fun helpResponse(event: GenericMessageEvent, topic: String) { + if (topic.isBlank() || !addons.help(channel, topic.lowercase().trim(), event)) { + helpDefault(event) + } + } + + override fun onAction(event: ActionEvent?) { + event?.channel?.let { + if (channel == it.name) { + event.user?.let { user -> + storeRecap(user.nick, event.action, true) + } + } + } + } + + override fun onDisconnect(event: DisconnectEvent?) { + event?.let { + with(event.getBot<PircBotX>()) { + LinksManager.socialManager.notification("$nick disconnected from $serverHostname") + seen.add(userChannelDao.getChannel(channel).users) + } + } + LinksManager.socialManager.shutdown() + } + + override fun onPrivateMessage(event: PrivateMessageEvent?) { + event?.user?.let { user -> + if (logger.isTraceEnabled) logger.trace("<<< ${user.nick}: ${event.message}") + val cmds = event.message.trim().split(" ".toRegex(), 2) + val cmd = cmds[0].lowercase() + val args = cmds.lastOrEmpty().trim() + if (cmd.startsWith(Constants.HELP_CMD)) { // help + helpResponse(event, args) + } else if (!addons.exec(channel, cmd, args, event)) { // Execute command or module + helpDefault(event) + } + } + } + + override fun onJoin(event: JoinEvent?) { + event?.user?.let { user -> + with(event.getBot<PircBotX>()) { + if (user.nick == nick) { + LinksManager.socialManager.notification( + "$nick has joined ${event.channel.name} on $serverHostname" + ) + seen.add(userChannelDao.getChannel(channel).users) + } else { + tell.send(event) + seen.add(user.nick) + } + } + } + } + + override fun onMessage(event: MessageEvent?) { + event?.user?.let { user -> + tell.send(event) + if (event.message.matches("(?i)${Pattern.quote(event.bot().nick)}:.*".toRegex())) { // mobibot: <command> + if (logger.isTraceEnabled) logger.trace(">>> ${user.nick}: ${event.message}") + val cmds = event.message.substring(event.bot().nick.length + 1).trim().split(" ".toRegex(), 2) + val cmd = cmds[0].lowercase() + val args = cmds.lastOrEmpty().trim() + if (cmd.startsWith(Constants.HELP_CMD)) { // mobibot: help + helpResponse(event, args) + } else { + // Execute module or command + addons.exec(channel, cmd, args, event) + } + } else if (addons.match(channel, event)) { // Links, e.g.: https://www.example.com/ or L1: , etc. + if (logger.isTraceEnabled) logger.trace(">>> ${user.nick}: ${event.message}") + } + storeRecap(user.nick, event.message, false) + seen.add(user.nick) + } + } + + override fun onNickChange(event: NickChangeEvent?) { + event?.let { + tell.send(event) + if (!it.oldNick.equals(it.newNick, true)) { + seen.add(it.oldNick) + } + seen.add(it.newNick) + } + } + + override fun onPart(event: PartEvent?) { + event?.user?.let { user -> + with(event.getBot<PircBotX>()) { + if (user.nick == nick) { + LinksManager.socialManager.notification( + "$nick has left ${event.channel.name} on $serverHostname" + ) + seen.add(userChannelDao.getChannel(channel).users) + } else { + seen.add(user.nick) + } + } + } + } + + override fun onQuit(event: QuitEvent?) { + event?.user?.let { user -> + seen.add(user.nick) + } + } + + companion object { + @JvmStatic + @Throws(Exception::class) + fun main(args: Array<String>) { + // Set up the command line options + val parser = ArgParser(Constants.CLI_CMD) + val debug by parser.option( + ArgType.Boolean, + Constants.DEBUG_ARG, + Constants.DEBUG_ARG.substring(0, 1), + "Print debug & logging data directly to the console" + ).default(false) + val property by parser.option( + ArgType.String, + Constants.PROPS_ARG, + Constants.PROPS_ARG.substring(0, 1), + "Use alternate properties file" + ).default("./${ReleaseInfo.PROJECT}.properties") + val version by parser.option( + ArgType.Boolean, + Constants.VERSION_ARG, + Constants.VERSION_ARG.substring(0, 1), + "Print version info" + ).default(false) + + // Parse the command line + parser.parse(args) + + if (version) { + // Output the version + println( + "${ReleaseInfo.PROJECT.capitalise()} ${ReleaseInfo.VERSION}" + + " (${ReleaseInfo.BUILDDATE.toIsoLocalDate()})" + ) + println(ReleaseInfo.WEBSITE) + } else { + // Load the properties + val p = Properties() + try { + Files.newInputStream( + Paths.get(property) + ).use { fis -> + p.load(fis) + } + } catch (ignore: FileNotFoundException) { + System.err.println("Unable to find properties file.") + exitProcess(1) + } catch (ignore: IOException) { + System.err.println("Unable to open properties file.") + exitProcess(1) + } + val nickname = p.getProperty("nick", Mobibot::class.java.name.lowercase()) + val channel = p.getProperty("channel") + val logsDir = p.getProperty("logs", ".").appendIfMissing(File.separatorChar) + + // Redirect stdout and stderr + if (!debug) { + try { + val stdout = PrintStream( + BufferedOutputStream( + FileOutputStream( + logsDir + channel.substring(1) + '.' + Utils.today() + ".log", true + ) + ), true + ) + System.setOut(stdout) + } catch (ignore: IOException) { + System.err.println("Unable to open output (stdout) log file.") + exitProcess(1) + } + try { + val stderr = PrintStream( + BufferedOutputStream( + FileOutputStream("$logsDir$nickname.err", true) + ), true + ) + System.setErr(stderr) + } catch (ignore: IOException) { + System.err.println("Unable to open error (stderr) log file.") + exitProcess(1) + } + } + + // Start the bot + Mobibot(nickname, channel, logsDir, p).connect() + } + } + } + + /** + * Initialize the bot. + */ + init { + val ircServer = p.getProperty("server", Constants.DEFAULT_SERVER) + config = Configuration.Builder().apply { + name = nickname + login = p.getProperty("login", nickname) + realName = p.getProperty("realname", nickname) + addServer( + ircServer, + p.getIntProperty("port", Constants.DEFAULT_PORT) + ) + addAutoJoinChannel(channel) + addListener(this@Mobibot) + version = "${ReleaseInfo.PROJECT} ${ReleaseInfo.VERSION}" + isAutoNickChange = true + val identPwd = p.getProperty("ident") + if (!identPwd.isNullOrBlank()) { + nickservPassword = identPwd + } + val identNick = p.getProperty("ident-nick") + if (!identNick.isNullOrBlank()) { + nickservNick = identNick + } + val identMsg = p.getProperty("ident-msg") + if (!identMsg.isNullOrBlank()) { + nickservCustomMessage = identMsg + } + isAutoReconnect = true + + //socketConnectTimeout = Constants.CONNECT_TIMEOUT + //socketTimeout = Constants.CONNECT_TIMEOUT + //messageDelay = StaticDelay(500) + }.buildConfiguration() + + // Load the current entries + with(LinksManager) { + entries.channel = channel + entries.ircServer = ircServer + entries.logsDir = logsDirPath + entries.backlogs = p.getProperty("backlogs", "") + entries.load() + + // Set up pinboard + pinboard.setApiToken(p.getProperty("pinboard-api-token", "")) + } + + addons = Addons(p) + + // Load the commands + addons.add(ChannelFeed(channel.removePrefix("#"))) + addons.add(Comment()) + addons.add(Cycle()) + addons.add(Die()) + addons.add(Ignore()) + addons.add(LinksManager()) + addons.add(Me()) + addons.add(Modules(addons.names.modules, addons.names.disabledModules)) + addons.add(Msg()) + addons.add(Nick()) + addons.add(Posting()) + addons.add(Recap()) + addons.add(Say()) + + // Seen command + seen = Seen("${logsDirPath}${nickname}-seen.ser") + addons.add(seen) + + addons.add(Tags()) + + // Tell command + tell = Tell("${logsDirPath}${nickname}.ser") + addons.add(tell) + + addons.add(Users()) + addons.add(Versions()) + addons.add(View()) + + // Load social modules + LinksManager.socialManager.add(addons, Mastodon()) + + // Load the modules + addons.add(Calc()) + addons.add(ChatGpt()) + addons.add(CryptoPrices()) + addons.add(CurrencyConverter()) + addons.add(Dice()) + addons.add(GoogleSearch()) + addons.add(Info(tell, seen)) + addons.add(Joke()) + addons.add(Lookup()) + addons.add(Ping()) + addons.add(RockPaperScissors()) + addons.add(StockQuote()) + addons.add(War()) + addons.add(Weather2()) + addons.add(WolframAlpha()) + addons.add(WorldTime()) + + // Sort the addons + addons.names.sort() + } +} + diff --git a/bin/main/net/thauvin/erik/mobibot/Pinboard.kt b/bin/main/net/thauvin/erik/mobibot/Pinboard.kt new file mode 100644 index 0000000..7cb5aed --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/Pinboard.kt @@ -0,0 +1,113 @@ +/* + * Pinboard.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot + +import net.thauvin.erik.mobibot.entries.EntryLink +import net.thauvin.erik.pinboard.PinboardPoster +import java.time.ZoneId +import java.time.ZonedDateTime +import java.time.format.DateTimeFormatter +import java.time.temporal.ChronoUnit +import java.util.* + +/** + * Handles posts to pinboard.in. + */ +class Pinboard { + private val poster = PinboardPoster() + + /** + * Adds a pin. + */ + fun addPin(ircServer: String, entry: EntryLink) { + if (poster.apiToken.isNotBlank()) { + with(entry) { + poster.addPin(link, title, postedBy(ircServer), formatTags(), date.toTimestamp()) + } + } + } + + /** + * Sets the pinboard API token. + */ + fun setApiToken(apiToken: String) { + poster.apiToken = apiToken + } + + /** + * Deletes a pin. + */ + fun deletePin(entry: EntryLink) { + if (poster.apiToken.isNotBlank()) { + poster.deletePin(entry.link) + } + + } + + /** + * Updates a pin. + */ + fun updatePin(ircServer: String, oldUrl: String, entry: EntryLink) { + if (poster.apiToken.isNotBlank()) { + with(entry) { + if (oldUrl != link) { + poster.deletePin(oldUrl) + } + poster.addPin(link, title, postedBy(ircServer), formatTags(), date.toTimestamp()) + } + } + } + + /** + * Formats a date to a UTC timestamp. + */ + private fun Date.toTimestamp(): String { + return ZonedDateTime.ofInstant( + toInstant().truncatedTo(ChronoUnit.SECONDS), ZoneId.systemDefault() + ).format(DateTimeFormatter.ISO_INSTANT) + } + + /** + * Formats the tags for pinboard. + */ + private fun EntryLink.formatTags(): String { + return nick + formatTags(",", ",") + } + + /** + * Returns the pinboard.in extended attribution line. + */ + private fun EntryLink.postedBy(ircServer: String): String { + return "Posted by $nick on $channel ( $ircServer )" + } +} + diff --git a/bin/main/net/thauvin/erik/mobibot/Utils.kt b/bin/main/net/thauvin/erik/mobibot/Utils.kt new file mode 100644 index 0000000..e4760d2 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/Utils.kt @@ -0,0 +1,439 @@ +/* + * Utils.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot + +import net.thauvin.erik.mobibot.msg.Message +import net.thauvin.erik.mobibot.msg.Message.Companion.DEFAULT_COLOR +import net.thauvin.erik.urlencoder.UrlEncoderUtil +import org.jsoup.Jsoup +import org.pircbotx.Colors +import org.pircbotx.PircBotX +import org.pircbotx.hooks.events.PrivateMessageEvent +import org.pircbotx.hooks.types.GenericMessageEvent +import org.slf4j.Logger +import java.io.* +import java.net.HttpURLConnection +import java.net.URL +import java.nio.file.Files +import java.nio.file.Paths +import java.time.LocalDateTime +import java.time.ZoneId +import java.time.format.DateTimeFormatter +import java.util.* +import kotlin.io.path.exists +import kotlin.io.path.fileSize + +/** + * Miscellaneous utilities. + */ +@Suppress("TooManyFunctions") +object Utils { + private val searchFlags = arrayOf("%c", "%n") + + /** + * Prepends a prefix if not present. + */ + @JvmStatic + fun String.prefixIfMissing(prefix: Char): String { + return if (first() != prefix) { + "$prefix${this}" + } else { + this + } + } + + /** + * Appends a suffix to the end of the String if not present. + */ + @JvmStatic + fun String.appendIfMissing(suffix: Char): String { + return if (last() != suffix) { + "$this${suffix}" + } else { + this + } + } + + /** + * Makes the given int bold. + */ + @JvmStatic + fun Int.bold(): String = toString().bold() + + /** + * Makes the given long bold. + */ + @JvmStatic + fun Long.bold(): String = toString().bold() + + /** + * Makes the given string bold. + */ + @JvmStatic + fun String?.bold(): String = colorize(Colors.BOLD) + + /** + * Returns the [PircBotX] instance. + */ + fun GenericMessageEvent.bot(): PircBotX { + return getBot() as PircBotX + } + + /** + * Capitalize a string. + */ + @JvmStatic + fun String.capitalise(): String = lowercase().replaceFirstChar { it.uppercase() } + + /** + * Capitalize words + */ + @JvmStatic + fun String.capitalizeWords(): String = split(" ").joinToString(" ") { it.capitalise() } + + /** + * Colorize a string. + */ + @JvmStatic + fun String?.colorize(color: String): String { + return when { + isNullOrEmpty() -> { + "" + } + + color == DEFAULT_COLOR -> { + this + } + + Colors.BOLD == color || Colors.REVERSE == color -> { + color + this + color + } + + else -> { + color + this + Colors.NORMAL + } + } + } + + /** + * Makes the given string cyan. + */ + @JvmStatic + fun String?.cyan(): String = colorize(Colors.CYAN) + + /** + * URL encodes the given string. + */ + @JvmStatic + fun String.encodeUrl(): String = UrlEncoderUtil.encode(this) + + /** + * Returns a property as an int. + */ + @JvmStatic + fun Properties.getIntProperty(key: String, defaultValue: Int): Int { + return getProperty(key)?.toIntOrDefault(defaultValue) ?: defaultValue + } + + /** + * Makes the given string green. + */ + @JvmStatic + fun String?.green(): String = colorize(Colors.DARK_GREEN) + + /** + * Build a help command by replacing `%c` with the bot's pub/priv command, and `%n` with the bot's + * nick. + */ + @JvmStatic + fun helpCmdSyntax(text: String, botNick: String, isPrivate: Boolean): String { + val replace = arrayOf(if (isPrivate) "/msg $botNick" else "$botNick:", botNick) + return text.replaceEach(searchFlags, replace) + } + + /** + * Returns a formatted help string. + */ + @JvmStatic + @JvmOverloads + fun helpFormat(help: String, isBold: Boolean = true, isIndent: Boolean = true): String { + val s = if (isBold) help.bold() else help + return if (isIndent) s.prependIndent() else s + } + + /** + * Returns `true` if the specified user is an operator on the [channel]. + */ + @JvmStatic + fun GenericMessageEvent.isChannelOp(channel: String): Boolean { + return this.bot().userChannelDao.getChannel(channel).isOp(this.user) + } + + /** + * Returns `true` if a HTTP status code indicates a successful response. + */ + @JvmStatic + fun Int.isHttpSuccess() = this in 200..399 + + /** + * Returns the last item of a list of strings or empty if none. + */ + @JvmStatic + fun List<String>.lastOrEmpty(): String { + return if (this.size >= 2) { + this.last() + } else + "" + } + + /** + * Load serial data from file. + */ + @JvmStatic + fun loadSerialData(file: String, default: Any, logger: Logger, description: String): Any { + val serialFile = Paths.get(file) + if (serialFile.exists() && serialFile.fileSize() > 0) { + try { + ObjectInputStream( + BufferedInputStream(Files.newInputStream(serialFile)) + ).use { input -> + if (logger.isDebugEnabled) logger.debug("Loading the ${description}.") + return input.readObject() + } + } catch (e: IOException) { + logger.error("An IO error occurred loading the ${description}.", e) + } catch (e: ClassNotFoundException) { + logger.error("An error occurred loading the ${description}.", e) + } + } + return default + } + + /** + * Returns `true` if the list does not contain the given string. + */ + @JvmStatic + fun List<String>.notContains(text: String, ignoreCase: Boolean = false) = this.none { it.equals(text, ignoreCase) } + + /** + * Obfuscates the given string. + */ + @JvmStatic + fun String.obfuscate(): String { + return if (isNotBlank()) { + "x".repeat(length) + } else this + } + + /** + * Returns the plural form of a word, if count > 1. + */ + @JvmStatic + fun String.plural(count: Long): String { + return if (count > 1) "${this}s" else this + } + + /** + * Makes the given string red. + */ + @JvmStatic + fun String?.red(): String = colorize(Colors.RED) + + /** + * Replaces all occurrences of Strings within another String. + */ + @JvmStatic + fun String.replaceEach(search: Array<out String>, replace: Array<out String>): String { + var result = this + if (search.size == replace.size) { + search.forEachIndexed { i, s -> + result = result.replace(s, replace[i]) + } + } + return result + } + + /** + * Makes the given string reverse color. + */ + @JvmStatic + fun String?.reverseColor(): String = colorize(Colors.REVERSE) + + /** + * Save data + */ + @JvmStatic + fun saveSerialData(file: String, data: Any, logger: Logger, description: String) { + try { + BufferedOutputStream(Files.newOutputStream(Paths.get(file))).use { bos -> + ObjectOutputStream(bos).use { output -> + if (logger.isDebugEnabled) logger.debug("Saving the ${description}.") + output.writeObject(data) + } + } + } catch (e: IOException) { + logger.error("Unable to save the ${description}.", e) + } + } + + /** + * Send a formatted commands/modules, etc. list. + */ + @JvmStatic + @JvmOverloads + fun GenericMessageEvent.sendList( + list: List<String>, + maxPerLine: Int, + separator: String = " ", + isBold: Boolean = false, + isIndent: Boolean = false + ) { + var i = 0 + while (i < list.size) { + sendMessage( + helpFormat( + list.subList(i, list.size.coerceAtMost(i + maxPerLine)).joinToString(separator, truncated = ""), + isBold, + isIndent + ), + ) + i += maxPerLine + } + } + + /** + * Sends a [message]. + */ + @JvmStatic + fun GenericMessageEvent.sendMessage(channel: String, message: Message) { + if (message.isNotice) { + bot().sendIRC().notice(user.nick, message.msg.colorize(message.color)) + } else if (message.isPrivate || this is PrivateMessageEvent || channel.isBlank()) { + respondPrivateMessage(message.msg.colorize(message.color)) + } else { + bot().sendIRC().message(channel, message.msg.colorize(message.color)) + } + } + + /** + * Sends a response as a private message or notice. + */ + @JvmStatic + fun GenericMessageEvent.sendMessage(message: String) { + if (this is PrivateMessageEvent) { + respondPrivateMessage(message) + } else { + bot().sendIRC().notice(user.nick, message) + } + } + + /** + * Returns today's date. + */ + @JvmStatic + fun today(): String = LocalDateTime.now().toIsoLocalDate() + + /** + * Converts a string to an int. + */ + @JvmStatic + fun String.toIntOrDefault(defaultValue: Int): Int { + return try { + toInt() + } catch (e: NumberFormatException) { + defaultValue + } + } + + /** + * Returns the specified date as an ISO local date string. + */ + @JvmStatic + fun Date.toIsoLocalDate(): String { + return LocalDateTime.ofInstant(toInstant(), ZoneId.systemDefault()).toIsoLocalDate() + } + + /** + * Returns the specified date as an ISO local date string. + */ + @JvmStatic + fun LocalDateTime.toIsoLocalDate(): String = format(DateTimeFormatter.ISO_LOCAL_DATE) + + /** + * Returns the specified date formatted as `yyyy-MM-dd HH:mm`. + */ + @JvmStatic + fun Date.toUtcDateTime(): String { + return LocalDateTime.ofInstant(toInstant(), ZoneId.systemDefault()).toUtcDateTime() + } + + /** + * Returns the specified date formatted as `yyyy-MM-dd HH:mm`. + */ + @JvmStatic + fun LocalDateTime.toUtcDateTime(): String = format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")) + + /** + * Makes the given string bold. + */ + @JvmStatic + fun String?.underline(): String = colorize(Colors.UNDERLINE) + + + /** + * Converts XML/XHTML entities to plain text. + */ + @JvmStatic + fun String.unescapeXml(): String = Jsoup.parse(this).text() + + /** + * Reads contents of a URL. + */ + @JvmStatic + @Throws(IOException::class) + fun URL.reader(): UrlReaderResponse { + val connection = this.openConnection() as HttpURLConnection + connection.setRequestProperty( + "User-Agent", + "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/109.0" + ) + return if (connection.responseCode.isHttpSuccess()) { + UrlReaderResponse(connection.responseCode, connection.inputStream.bufferedReader().use { it.readText() }) + } else { + UrlReaderResponse(connection.responseCode, connection.errorStream.bufferedReader().use { it.readText() }) + } + } + + /** + * Holds the [URL.reader] response code and body text. + */ + data class UrlReaderResponse(val responseCode: Int, val body: String) +} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/AbstractCommand.kt b/bin/main/net/thauvin/erik/mobibot/commands/AbstractCommand.kt new file mode 100644 index 0000000..5f79472 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/commands/AbstractCommand.kt @@ -0,0 +1,79 @@ +/* + * AbstractCommand.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.commands + +import net.thauvin.erik.mobibot.Utils.bot +import net.thauvin.erik.mobibot.Utils.helpCmdSyntax +import net.thauvin.erik.mobibot.Utils.isChannelOp +import net.thauvin.erik.mobibot.Utils.sendMessage +import org.pircbotx.hooks.events.PrivateMessageEvent +import org.pircbotx.hooks.types.GenericMessageEvent + +abstract class AbstractCommand { + abstract val name: String + abstract val help: List<String> + abstract val isOpOnly: Boolean + abstract val isPublic: Boolean + abstract val isVisible: Boolean + + val properties: MutableMap<String, String> = mutableMapOf() + + abstract fun commandResponse(channel: String, args: String, event: GenericMessageEvent) + + open fun helpResponse(channel: String, topic: String, event: GenericMessageEvent): Boolean { + if (!isOpOnly || isOpOnly == event.isChannelOp(channel)) { + for (h in help) { + event.sendMessage(helpCmdSyntax(h, event.bot().nick, event is PrivateMessageEvent || !isPublic)) + } + return true + } + return false + } + + open fun initProperties(vararg keys: String) { + keys.forEach { + properties[it] = "" + } + } + + open fun isEnabled(): Boolean { + return true + } + + open fun matches(message: String): Boolean { + return false + } + + open fun setProperty(key: String, value: String) { + properties[key] = value + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/ChannelFeed.kt b/bin/main/net/thauvin/erik/mobibot/commands/ChannelFeed.kt new file mode 100644 index 0000000..038e378 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/commands/ChannelFeed.kt @@ -0,0 +1,62 @@ +/* + * ChannelFeed.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.commands + +import net.thauvin.erik.mobibot.FeedReader +import net.thauvin.erik.mobibot.Utils.helpFormat +import org.pircbotx.hooks.types.GenericMessageEvent + +class ChannelFeed(channel: String) : AbstractCommand() { + override val name = channel + override val help = listOf("To list the last 5 posts from the channel's weblog feed:", helpFormat("%c $channel")) + override val isOpOnly = false + override val isPublic = true + override val isVisible = true + + companion object { + const val FEED_PROP = "feed" + } + + init { + initProperties(FEED_PROP) + } + + override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { + if (isEnabled()) { + properties[FEED_PROP]?.let { FeedReader(it, event).run() } + } + } + + override fun isEnabled(): Boolean { + return !properties[FEED_PROP].isNullOrBlank() + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Cycle.kt b/bin/main/net/thauvin/erik/mobibot/commands/Cycle.kt new file mode 100644 index 0000000..9608ca8 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/commands/Cycle.kt @@ -0,0 +1,66 @@ +/* + * Cycle.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.commands + +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import net.thauvin.erik.mobibot.Utils.bot +import net.thauvin.erik.mobibot.Utils.helpFormat +import net.thauvin.erik.mobibot.Utils.isChannelOp +import org.pircbotx.hooks.types.GenericMessageEvent + +class Cycle : AbstractCommand() { + private val wait = 10 + override val name = "cycle" + override val help = listOf("To have the bot leave the channel and come back:", helpFormat("%c $name")) + override val isOpOnly = true + override val isPublic = false + override val isVisible = true + + override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { + with(event.bot()) { + if (event.isChannelOp(channel)) { + runBlocking { + launch { + sendIRC().message(channel, "${event.user.nick} asked me to leave. I'll be back!") + userChannelDao.getChannel(channel).send().part() + delay(wait * 1000L) + sendIRC().joinChannel(channel) + } + } + } else { + helpResponse(channel, args, event) + } + } + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Die.kt b/bin/main/net/thauvin/erik/mobibot/commands/Die.kt new file mode 100644 index 0000000..f271bfa --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/commands/Die.kt @@ -0,0 +1,62 @@ +/* + * Die.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.commands + +import net.thauvin.erik.mobibot.Utils.bot +import net.thauvin.erik.mobibot.Utils.isChannelOp +import org.pircbotx.hooks.types.GenericMessageEvent + +class Die : AbstractCommand() { + override val name = "die" + override val help = emptyList<String>() + override val isOpOnly = true + override val isPublic = false + override val isVisible = false + + override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { + with(event.bot()) { + if (event.isChannelOp(channel) && (properties[DIE_PROP].isNullOrBlank() || args == properties[DIE_PROP])) { + sendIRC().message(channel, "${event.user?.nick} has just signed my death sentence.") + stopBotReconnect() + sendIRC().quitServer("The Bot is Out There!") + } + } + } + + companion object { + const val DIE_PROP = "die" + } + + init { + initProperties(DIE_PROP) + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Ignore.kt b/bin/main/net/thauvin/erik/mobibot/commands/Ignore.kt new file mode 100644 index 0000000..d083c10 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/commands/Ignore.kt @@ -0,0 +1,147 @@ +/* + * Ignore.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.commands + +import net.thauvin.erik.mobibot.Utils.bold +import net.thauvin.erik.mobibot.Utils.bot +import net.thauvin.erik.mobibot.Utils.helpCmdSyntax +import net.thauvin.erik.mobibot.Utils.helpFormat +import net.thauvin.erik.mobibot.Utils.isChannelOp +import net.thauvin.erik.mobibot.Utils.sendList +import net.thauvin.erik.mobibot.Utils.sendMessage +import net.thauvin.erik.mobibot.commands.links.LinksManager +import org.pircbotx.hooks.types.GenericMessageEvent + +class Ignore : AbstractCommand() { + private val me = "me" + + init { + initProperties(IGNORE_PROP) + } + + override val name = IGNORE_CMD + override val help = listOf( + "To ignore a link posted to the channel:", + helpFormat("https://www.foo.bar %n"), + "To check your ignore status:", + helpFormat("%c $name"), + "To toggle your ignore status:", + helpFormat("%c $name $me") + ) + private val helpOp = help.plus( + arrayOf("To add/remove nicks from the ignored list:", helpFormat("%c $name <nick> [<nick> ...]")) + ) + + override val isOpOnly = false + override val isPublic = true + override val isVisible = true + + companion object { + const val IGNORE_CMD = "ignore" + const val IGNORE_PROP = IGNORE_CMD + private val ignored = mutableSetOf<String>() + + @JvmStatic + fun isNotIgnored(nick: String): Boolean { + return !ignored.contains(nick.lowercase()) + } + } + + override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { + val isMe = args.trim().equals(me, true) + if (isMe || !event.isChannelOp(channel)) { + val nick = event.user.nick.lowercase() + ignoreNick(nick, isMe, event) + } else { + ignoreOp(args, event) + } + } + + override fun helpResponse(channel: String, topic: String, event: GenericMessageEvent): Boolean { + return if (event.isChannelOp(channel)) { + for (h in helpOp) { + event.sendMessage(helpCmdSyntax(h, event.bot().nick, true)) + } + true + } else { + super.helpResponse(channel, topic, event) + } + } + + private fun ignoreNick(sender: String, isMe: Boolean, event: GenericMessageEvent) { + if (isMe) { + if (ignored.remove(sender)) { + event.sendMessage("You are no longer ignored.") + } else { + ignored.add(sender) + event.sendMessage("You are now ignored.") + } + } else { + if (ignored.contains(sender)) { + event.sendMessage("You are currently ignored.") + } else { + event.sendMessage("You are not currently ignored.") + } + } + } + + private fun ignoreOp(args: String, event: GenericMessageEvent) { + if (args.isNotEmpty()) { + val nicks = args.lowercase().split(" ") + for (nick in nicks) { + val ignore = if (me == nick) { + nick.lowercase() + } else { + nick + } + if (!ignored.remove(ignore)) { + ignored.add(ignore) + } + } + } + + if (ignored.isNotEmpty()) { + event.sendMessage("The following nicks are ignored:") + event.sendList(ignored.sorted(), 8, isIndent = true) + } else { + event.sendMessage("No one is currently ${"ignored".bold()}.") + } + } + + override fun setProperty(key: String, value: String) { + super.setProperty(key, value) + if (IGNORE_PROP == key) { + ignored.addAll(value.split(LinksManager.TAG_MATCH)) + } + } + +} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Info.kt b/bin/main/net/thauvin/erik/mobibot/commands/Info.kt new file mode 100644 index 0000000..ed0b6ef --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/commands/Info.kt @@ -0,0 +1,124 @@ +/* + * Info.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.commands + +import net.thauvin.erik.mobibot.ReleaseInfo +import net.thauvin.erik.mobibot.Utils.capitalise +import net.thauvin.erik.mobibot.Utils.green +import net.thauvin.erik.mobibot.Utils.helpFormat +import net.thauvin.erik.mobibot.Utils.isChannelOp +import net.thauvin.erik.mobibot.Utils.plural +import net.thauvin.erik.mobibot.Utils.sendList +import net.thauvin.erik.mobibot.Utils.sendMessage +import net.thauvin.erik.mobibot.commands.links.LinksManager +import net.thauvin.erik.mobibot.commands.seen.Seen +import net.thauvin.erik.mobibot.commands.tell.Tell +import org.pircbotx.hooks.types.GenericMessageEvent +import java.lang.management.ManagementFactory +import kotlin.time.DurationUnit +import kotlin.time.toDuration + +class Info(private val tell: Tell, private val seen: Seen) : AbstractCommand() { + private val allVersions = listOf( + "${ReleaseInfo.PROJECT.capitalise()} ${ReleaseInfo.VERSION} (${ReleaseInfo.WEBSITE.green()})", + "Written by ${ReleaseInfo.AUTHOR} (${ReleaseInfo.AUTHOR_URL.green()})" + ) + override val name = "info" + override val help = listOf("To view information about the bot:", helpFormat("%c $name")) + override val isOpOnly = false + override val isPublic = true + override val isVisible = true + + companion object { + /** + * Converts milliseconds to year month week day hour and minutes. + */ + @JvmStatic + fun Long.toUptime(): String { + this.toDuration(DurationUnit.MILLISECONDS).toComponents { wholeDays, hours, minutes, seconds, _ -> + val years = wholeDays / 365 + var days = wholeDays % 365 + val months = days / 30 + days %= 30 + val weeks = days / 7 + days %= 7 + + with(StringBuffer()) { + if (years > 0) { + append(years).append(" year".plural(years)).append(' ') + } + if (months > 0) { + append(months).append(" month".plural(months)).append(' ') + } + if (weeks > 0) { + append(weeks).append(" week".plural(weeks)).append(' ') + } + if (days > 0) { + append(days).append(" day".plural(days)).append(' ') + } + if (hours > 0) { + append(hours).append(" hour".plural(hours.toLong())).append(' ') + } + + if (minutes > 0) { + append(minutes).append(" minute".plural(minutes.toLong())) + } else { + append(seconds).append(" second".plural(seconds.toLong())) + } + + return toString() + } + } + } + } + + override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { + event.sendList(allVersions, 1) + val info = StringBuilder() + info.append("Uptime: ") + .append(ManagementFactory.getRuntimeMXBean().uptime.toUptime()) + .append(" [Entries: ") + .append(LinksManager.entries.links.size) + if (seen.isEnabled()) { + info.append(", Seen: ").append(seen.count()) + } + if (event.isChannelOp(channel)) { + if (tell.isEnabled()) { + info.append(", Messages: ").append(tell.size()) + } + if (LinksManager.socialManager.entriesCount() > 0) { + info.append(", Social: ").append(LinksManager.socialManager.entriesCount()) + } + } + info.append(", Recap: ").append(Recap.recaps.size).append(']') + event.sendMessage(info.toString()) + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Me.kt b/bin/main/net/thauvin/erik/mobibot/commands/Me.kt new file mode 100644 index 0000000..ec7823b --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/commands/Me.kt @@ -0,0 +1,51 @@ +/* + * Me.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.commands + +import net.thauvin.erik.mobibot.Utils.bot +import net.thauvin.erik.mobibot.Utils.helpFormat +import net.thauvin.erik.mobibot.Utils.isChannelOp +import org.pircbotx.hooks.types.GenericMessageEvent + +class Me : AbstractCommand() { + override val name = "me" + override val help = listOf("To have the bot perform an action:", helpFormat("%c $name <action>")) + override val isOpOnly = true + override val isPublic = false + override val isVisible = true + + override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { + if (event.isChannelOp(channel)) { + event.bot().sendIRC().action(channel, args) + } + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Modules.kt b/bin/main/net/thauvin/erik/mobibot/commands/Modules.kt new file mode 100644 index 0000000..b2293b0 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/commands/Modules.kt @@ -0,0 +1,63 @@ +/* + * Modules.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.commands + +import net.thauvin.erik.mobibot.Utils.helpFormat +import net.thauvin.erik.mobibot.Utils.isChannelOp +import net.thauvin.erik.mobibot.Utils.sendList +import org.pircbotx.hooks.types.GenericMessageEvent + +class Modules(private val modules: List<String>, private val disabledModules: List<String>) : AbstractCommand() { + override val name = "modules" + override val help = listOf("To view a list of enabled/disabled modules:", helpFormat("%c $name")) + override val isOpOnly = true + override val isPublic = false + override val isVisible = true + + override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { + if (event.isChannelOp(channel)) { + if (modules.isEmpty()) { + event.respondPrivateMessage("There are no enabled modules.") + } else { + event.respondPrivateMessage("The enabled modules are: ") + event.sendList(modules, 7, isIndent = true) + } + if (disabledModules.isNotEmpty()) { + event.respondPrivateMessage("The disabled modules are: ") + event.sendList(disabledModules, 7, isIndent = true) + } + } else { + helpResponse(channel, args, event) + } + } +} + diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Msg.kt b/bin/main/net/thauvin/erik/mobibot/commands/Msg.kt new file mode 100644 index 0000000..20a6635 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/commands/Msg.kt @@ -0,0 +1,60 @@ +/* + * Msg.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.commands + +import net.thauvin.erik.mobibot.Utils.bot +import net.thauvin.erik.mobibot.Utils.helpFormat +import net.thauvin.erik.mobibot.Utils.isChannelOp +import org.pircbotx.hooks.types.GenericMessageEvent + +class Msg : AbstractCommand() { + override val name = "msg" + override val help = listOf( + "To have the bot send a private message to someone:", + helpFormat("%c $name <nick> <text>") + ) + override val isOpOnly = true + override val isPublic = false + override val isVisible = true + + override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { + if (event.isChannelOp(channel)) { + val msg = args.split(" ", limit = 2) + if (args.length > 2) { + event.bot().sendIRC().message(msg[0], msg[1]) + event.respondPrivateMessage("A message was sent to ${msg[0]}") + } else { + helpResponse(channel, args, event) + } + } + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Nick.kt b/bin/main/net/thauvin/erik/mobibot/commands/Nick.kt new file mode 100644 index 0000000..85a03ab --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/commands/Nick.kt @@ -0,0 +1,51 @@ +/* + * Nick.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.commands + +import net.thauvin.erik.mobibot.Utils.bot +import net.thauvin.erik.mobibot.Utils.helpFormat +import net.thauvin.erik.mobibot.Utils.isChannelOp +import org.pircbotx.hooks.types.GenericMessageEvent + +class Nick : AbstractCommand() { + override val name = "nick" + override val help = listOf("To change the bot's nickname:", helpFormat("%c $name <new_nick>")) + override val isOpOnly = true + override val isPublic = true + override val isVisible = true + + override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { + if (event.isChannelOp(channel)) { + event.bot().sendIRC().changeNick(args) + } + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Recap.kt b/bin/main/net/thauvin/erik/mobibot/commands/Recap.kt new file mode 100644 index 0000000..77154c7 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/commands/Recap.kt @@ -0,0 +1,81 @@ +/* + * Recap.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.commands + +import net.thauvin.erik.mobibot.Utils.helpFormat +import net.thauvin.erik.mobibot.Utils.sendMessage +import net.thauvin.erik.mobibot.Utils.toUtcDateTime +import org.pircbotx.hooks.types.GenericMessageEvent +import java.time.Clock +import java.time.LocalDateTime + +class Recap : AbstractCommand() { + override val name = "recap" + override val help = listOf( + "To list the last 10 public channel messages:", + helpFormat("%c $name") + ) + override val isOpOnly = false + override val isPublic = true + override val isVisible = true + + companion object { + const val MAX_RECAPS = 10 + + @JvmField + val recaps = mutableListOf<String>() + + /** + * Stores the last 10 public messages and actions. + */ + @JvmStatic + fun storeRecap(sender: String, message: String, isAction: Boolean) { + recaps.add( + LocalDateTime.now(Clock.systemUTC()).toUtcDateTime() + + " - $sender" + (if (isAction) " " else ": ") + message + ) + if (recaps.size > MAX_RECAPS) { + recaps.removeFirst() + } + } + } + + override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { + if (recaps.isNotEmpty()) { + for (r in recaps) { + event.sendMessage(r) + } + } else { + event.sendMessage("Sorry, nothing to recap.") + } + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Say.kt b/bin/main/net/thauvin/erik/mobibot/commands/Say.kt new file mode 100644 index 0000000..7f76d35 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/commands/Say.kt @@ -0,0 +1,51 @@ +/* + * Say.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.commands + +import net.thauvin.erik.mobibot.Utils.bot +import net.thauvin.erik.mobibot.Utils.helpFormat +import net.thauvin.erik.mobibot.Utils.isChannelOp +import org.pircbotx.hooks.types.GenericMessageEvent + +class Say : AbstractCommand() { + override val name = "say" + override val help = listOf("To have the bot say something on the channel:", helpFormat("%c $name <text>")) + override val isOpOnly = true + override val isPublic = false + override val isVisible = true + + override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { + if (event.isChannelOp(channel)) { + event.bot().sendIRC().message(channel, args) + } + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Users.kt b/bin/main/net/thauvin/erik/mobibot/commands/Users.kt new file mode 100644 index 0000000..33d6fef --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/commands/Users.kt @@ -0,0 +1,50 @@ +/* + * Users.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.commands + +import net.thauvin.erik.mobibot.Utils.bot +import net.thauvin.erik.mobibot.Utils.helpFormat +import net.thauvin.erik.mobibot.Utils.sendList +import org.pircbotx.hooks.types.GenericMessageEvent + +class Users : AbstractCommand() { + override val name = "users" + override val help = listOf("To list the users present on the channel:", helpFormat("%c $name")) + override val isOpOnly = false + override val isPublic = true + override val isVisible = true + + override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { + val ch = event.bot().userChannelDao.getChannel(channel) + event.sendList(ch.users.map { if (it.channelsOpIn.contains(ch)) "@${it.nick}" else it.nick }, 8) + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Versions.kt b/bin/main/net/thauvin/erik/mobibot/commands/Versions.kt new file mode 100644 index 0000000..896c569 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/commands/Versions.kt @@ -0,0 +1,59 @@ +/* + * Versions.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.commands + +import net.thauvin.erik.mobibot.ReleaseInfo +import net.thauvin.erik.mobibot.Utils.helpFormat +import net.thauvin.erik.mobibot.Utils.isChannelOp +import net.thauvin.erik.mobibot.Utils.sendList +import net.thauvin.erik.mobibot.Utils.toIsoLocalDate +import org.pircbotx.PircBotX +import org.pircbotx.hooks.types.GenericMessageEvent + +class Versions : AbstractCommand() { + private val allVersions = listOf( + "Version: ${ReleaseInfo.VERSION} (${ReleaseInfo.BUILDDATE.toIsoLocalDate()})", + "${System.getProperty("os.name")} ${System.getProperty("os.version")} (${System.getProperty("os.arch")})" + + ", JVM ${System.getProperty("java.runtime.version")}", + "Kotlin ${KotlinVersion.CURRENT}, PircBotX ${PircBotX.VERSION}" + ) + override val name = "versions" + override val help = listOf("To view the versions data (bot, platform, java, etc.):", helpFormat("%c $name")) + override val isOpOnly = true + override val isPublic = false + override val isVisible = true + + override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { + if (event.isChannelOp(channel)) { + event.sendList(allVersions, 1) + } + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/links/Comment.kt b/bin/main/net/thauvin/erik/mobibot/commands/links/Comment.kt new file mode 100644 index 0000000..1443d44 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/commands/links/Comment.kt @@ -0,0 +1,151 @@ +/* + * Comment.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.commands.links + +import net.thauvin.erik.mobibot.Constants +import net.thauvin.erik.mobibot.Utils.bold +import net.thauvin.erik.mobibot.Utils.helpFormat +import net.thauvin.erik.mobibot.Utils.isChannelOp +import net.thauvin.erik.mobibot.Utils.sendMessage +import net.thauvin.erik.mobibot.commands.AbstractCommand +import net.thauvin.erik.mobibot.entries.EntriesUtils.printComment +import net.thauvin.erik.mobibot.entries.EntriesUtils.toLinkLabel +import net.thauvin.erik.mobibot.entries.EntryLink +import org.pircbotx.hooks.types.GenericMessageEvent + +class Comment : AbstractCommand() { + override val name = COMMAND + override val help = listOf( + "To add a comment:", + helpFormat("${Constants.LINK_CMD}1:This is a comment"), + "I will reply with a label, for example: ${Constants.LINK_CMD.bold()}1.1", + "To edit a comment, use its label: ", + helpFormat("${Constants.LINK_CMD}1.1:This is an edited comment"), + "To delete a comment, use its label and a minus sign: ", + helpFormat("${Constants.LINK_CMD}1.1:-") + ) + override val isOpOnly = false + override val isPublic = true + override val isVisible = true + + companion object { + const val COMMAND = "comment" + } + + override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { + val cmds = args.substring(1).split("[.:]".toRegex(), 3) + val entryIndex = cmds[0].toInt() - 1 + + if (entryIndex < LinksManager.entries.links.size && LinksManager.isUpToDate(event)) { + val entry: EntryLink = LinksManager.entries.links[entryIndex] + val commentIndex = cmds[1].toInt() - 1 + if (commentIndex < entry.comments.size) { + when (val cmd = cmds[2].trim()) { + "" -> showComment(entry, entryIndex, commentIndex, event) // L1.1: + "-" -> deleteComment(channel, entry, entryIndex, commentIndex, event) // L1.1:- + else -> { + if (cmd.startsWith('?')) { // L1.1:?<author> + changeAuthor(channel, cmd, entry, entryIndex, commentIndex, event) + } else { // L1.1:<comment> + setComment(cmd, entry, entryIndex, commentIndex, event) + } + } + } + } + } + } + + override fun helpResponse(channel: String, topic: String, event: GenericMessageEvent): Boolean { + if (super.helpResponse(channel, topic, event)) { + if (event.isChannelOp(channel)) { + event.sendMessage("To change a comment's author:") + event.sendMessage(helpFormat("${Constants.LINK_CMD}1.1:?<nick>")) + } + return true + } + return false + } + + override fun matches(message: String): Boolean { + return message.matches("^${Constants.LINK_CMD}\\d+\\.\\d+:.*".toRegex()) + } + + private fun changeAuthor( + channel: String, + cmd: String, + entry: EntryLink, + entryIndex: Int, + commentIndex: Int, + event: GenericMessageEvent + ) { + if (event.isChannelOp(channel) && cmd.length > 1) { + val comment = entry.getComment(commentIndex) + comment.nick = cmd.substring(1) + event.sendMessage(printComment(entryIndex, commentIndex, comment)) + LinksManager.entries.save() + } else { + event.sendMessage("Please ask a channel op to change the author of this comment for you.") + } + } + + private fun deleteComment( + channel: String, + entry: EntryLink, + entryIndex: Int, + commentIndex: Int, + event: GenericMessageEvent + ) { + if (event.isChannelOp(channel) || event.user.nick == entry.getComment(commentIndex).nick) { + entry.deleteComment(commentIndex) + event.sendMessage("Comment ${entryIndex.toLinkLabel()}.${commentIndex + 1} removed.") + LinksManager.entries.save() + } else { + event.sendMessage("Please ask a channel op to delete this comment for you.") + } + } + + private fun setComment( + cmd: String, + entry: EntryLink, + entryIndex: Int, + commentIndex: Int, + event: GenericMessageEvent + ) { + entry.setComment(commentIndex, cmd, event.user.nick) + event.sendMessage(printComment(entryIndex, commentIndex, entry.getComment(commentIndex))) + LinksManager.entries.save() + } + + private fun showComment(entry: EntryLink, entryIndex: Int, commentIndex: Int, event: GenericMessageEvent) { + event.sendMessage(printComment(entryIndex, commentIndex, entry.getComment(commentIndex))) + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/links/LinksManager.kt b/bin/main/net/thauvin/erik/mobibot/commands/links/LinksManager.kt new file mode 100644 index 0000000..fba6b99 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/commands/links/LinksManager.kt @@ -0,0 +1,207 @@ +/* + * LinksManager.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.commands.links + +import net.thauvin.erik.mobibot.Constants +import net.thauvin.erik.mobibot.Pinboard +import net.thauvin.erik.mobibot.Utils.bold +import net.thauvin.erik.mobibot.Utils.bot +import net.thauvin.erik.mobibot.Utils.helpFormat +import net.thauvin.erik.mobibot.Utils.sendMessage +import net.thauvin.erik.mobibot.Utils.today +import net.thauvin.erik.mobibot.commands.AbstractCommand +import net.thauvin.erik.mobibot.commands.Ignore.Companion.isNotIgnored +import net.thauvin.erik.mobibot.entries.Entries +import net.thauvin.erik.mobibot.entries.EntriesUtils.printLink +import net.thauvin.erik.mobibot.entries.EntriesUtils.toLinkLabel +import net.thauvin.erik.mobibot.entries.EntryLink +import net.thauvin.erik.mobibot.social.SocialManager +import org.jsoup.Jsoup +import org.pircbotx.hooks.types.GenericMessageEvent +import java.io.IOException + +class LinksManager : AbstractCommand() { + private val defaultTags: MutableList<String> = mutableListOf() + private val keywords: MutableList<String> = mutableListOf() + + override val name = Constants.LINK_CMD + override val help = emptyList<String>() + override val isOpOnly = false + override val isPublic = false + override val isVisible = false + + init { + initProperties(TAGS_PROP, KEYWORDS_PROP) + } + + companion object { + val LINK_MATCH = "^[hH][tT][tT][pP](|[sS])://.*".toRegex() + const val KEYWORDS_PROP = "tags-keywords" + const val TAGS_PROP = "tags" + val TAG_MATCH = ", *| +".toRegex() + + /** + * Entries array + */ + @JvmField + val entries = Entries() + + /** + * Pinboard handler. + */ + @JvmField + val pinboard = Pinboard() + + /** + * Social Manager handler. + */ + @JvmField + val socialManager = SocialManager() + + /** + * Let the user know if the entries are too old to be modified. + */ + @JvmStatic + fun isUpToDate(event: GenericMessageEvent): Boolean { + if (entries.lastPubDate != today()) { + event.sendMessage("The links are too old to be updated.") + return false + } + return true + } + } + + override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { + val cmds = args.split(" ".toRegex(), 2) + val sender = event.user.nick + val botNick = event.bot().nick + val login = event.user.login + + if (isNotIgnored(sender) && (cmds.size == 1 || !cmds[1].contains(botNick))) { + val link = cmds[0].trim() + if (!isDupEntry(link, event)) { + var title = "" + val tags = ArrayList<String>(defaultTags) + if (cmds.size == 2) { + val data = cmds[1].trim().split("${Tags.COMMAND}:", limit = 2) + title = data[0].trim() + if (data.size > 1) { + tags.addAll(data[1].split(TAG_MATCH)) + } + } + + if (title.isBlank()) { + title = fetchTitle(link) + } + + if (title != Constants.NO_TITLE) { + matchTagKeywords(title, tags) + } + + // Links are old, clear them + if (entries.lastPubDate != today()) { + entries.links.clear() + } + + val entry = EntryLink(link, title, sender, login, channel, tags) + entries.links.add(entry) + val index = entries.links.lastIndexOf(entry) + event.sendMessage(printLink(index, entry)) + + pinboard.addPin(event.bot().serverHostname, entry) + + // Queue link for posting to social media. + socialManager.queueEntry(index) + + entries.save() + + if (Constants.NO_TITLE == entry.title) { + event.sendMessage("Please specify a title, by typing:") + event.sendMessage(helpFormat("${index.toLinkLabel()}:|This is the title")) + } + } + } + } + + override fun helpResponse(channel: String, topic: String, event: GenericMessageEvent): Boolean = false + + override fun matches(message: String): Boolean { + return message.matches(LINK_MATCH) + } + + internal fun fetchTitle(link: String): String { + try { + val html = Jsoup.connect(link) + .userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0") + .get() + val title = html.title() + if (title.isNotBlank()) { + return title + } + } catch (ignore: IOException) { + // Do nothing + } + return Constants.NO_TITLE + } + + private fun isDupEntry(link: String, event: GenericMessageEvent): Boolean { + synchronized(entries) { + return try { + val match = entries.links.single { it.link == link } + event.sendMessage( + "Duplicate".bold() + " >> " + printLink(entries.links.indexOf(match), match) + ) + true + } catch (ignore: NoSuchElementException) { + false + } + } + } + + internal fun matchTagKeywords(title: String, tags: MutableList<String>) { + for (match in keywords) { + val m = Regex.escape(match) + if (title.matches("(?i).*\\b$m\\b.*".toRegex())) { + tags.add(match) + } + } + } + + override fun setProperty(key: String, value: String) { + super.setProperty(key, value) + if (KEYWORDS_PROP == key) { + keywords.addAll(value.split(TAG_MATCH)) + } else if (TAGS_PROP == key) { + defaultTags.addAll(value.split(TAG_MATCH)) + } + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/links/Posting.kt b/bin/main/net/thauvin/erik/mobibot/commands/links/Posting.kt new file mode 100644 index 0000000..ff4278d --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/commands/links/Posting.kt @@ -0,0 +1,164 @@ +/* + * Posting.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.commands.links + +import net.thauvin.erik.mobibot.Constants +import net.thauvin.erik.mobibot.Utils.bold +import net.thauvin.erik.mobibot.Utils.bot +import net.thauvin.erik.mobibot.Utils.helpFormat +import net.thauvin.erik.mobibot.Utils.isChannelOp +import net.thauvin.erik.mobibot.Utils.sendMessage +import net.thauvin.erik.mobibot.commands.AbstractCommand +import net.thauvin.erik.mobibot.commands.links.LinksManager.Companion.entries +import net.thauvin.erik.mobibot.entries.EntriesUtils +import net.thauvin.erik.mobibot.entries.EntriesUtils.toLinkLabel +import net.thauvin.erik.mobibot.entries.EntryLink +import org.pircbotx.hooks.types.GenericMessageEvent + +class Posting : AbstractCommand() { + override val name = "posting" + override val help = listOf( + "Post a URL, by saying it on a line on its own:", + helpFormat("<url> [<title>] ${Tags.COMMAND}: <+tag> [...]]"), + "I will reply with a label, for example: ${Constants.LINK_CMD.bold()}1", + "To add a title, use its label and a pipe:", + helpFormat("${Constants.LINK_CMD}1:|This is the title"), + "To add a comment:", + helpFormat("${Constants.LINK_CMD}1:This is a comment"), + "I will reply with a label, for example: ${Constants.LINK_CMD.bold()}1.1", + "To edit a comment, see: ", + helpFormat("%c ${Constants.HELP_CMD} ${Comment.COMMAND}") + ) + override val isOpOnly = false + override val isPublic = true + override val isVisible = true + + override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { + val cmds = args.substring(1).split(":", limit = 2) + val entryIndex = cmds[0].toInt() - 1 + + if (entryIndex < entries.links.size) { + val cmd = cmds[1].trim() + if (cmd.isBlank()) { + showEntry(entryIndex, event) // L1: + } else if (LinksManager.isUpToDate(event)) { + if (cmd == "-") { + removeEntry(channel, entryIndex, event) // L1:- + } else { + when (cmd[0]) { + '|' -> changeTitle(cmd, entryIndex, event) // L1:|<title> + '=' -> changeUrl(channel, cmd, entryIndex, event) // L1:=<url> + '?' -> changeAuthor(channel, cmd, entryIndex, event) // L1:?<author> + else -> addComment(cmd, entryIndex, event) // L1:<comment> + } + } + } + } + } + + override fun matches(message: String): Boolean { + return message.matches("${Constants.LINK_CMD}\\d+:.*".toRegex()) + } + + private fun addComment(cmd: String, entryIndex: Int, event: GenericMessageEvent) { + val entry: EntryLink = entries.links[entryIndex] + val commentIndex = entry.addComment(cmd, event.user.nick) + val comment = entry.getComment(commentIndex) + event.sendMessage(EntriesUtils.printComment(entryIndex, commentIndex, comment)) + entries.save() + } + + private fun changeTitle(cmd: String, entryIndex: Int, event: GenericMessageEvent) { + if (cmd.length > 1) { + val entry: EntryLink = entries.links[entryIndex] + entry.title = cmd.substring(1).trim() + LinksManager.pinboard.updatePin(event.bot().serverHostname, entry.link, entry) + event.sendMessage(EntriesUtils.printLink(entryIndex, entry)) + entries.save() + } + } + + private fun changeUrl(channel: String, cmd: String, entryIndex: Int, event: GenericMessageEvent) { + val entry: EntryLink = entries.links[entryIndex] + if (entry.login == event.user.login || event.isChannelOp(channel)) { + val link = cmd.substring(1) + if (link.matches(LinksManager.LINK_MATCH)) { + val oldLink = entry.link + entry.link = link + LinksManager.pinboard.updatePin(event.bot().serverHostname, oldLink, entry) + event.sendMessage(EntriesUtils.printLink(entryIndex, entry)) + entries.save() + } + } + } + + private fun changeAuthor(channel: String, cmd: String, index: Int, event: GenericMessageEvent) { + if (event.isChannelOp(channel)) { + if (cmd.length > 1) { + val entry: EntryLink = entries.links[index] + entry.nick = cmd.substring(1) + LinksManager.pinboard.updatePin(event.bot().serverHostname, entry.link, entry) + event.sendMessage(EntriesUtils.printLink(index, entry)) + entries.save() + } + } else { + event.sendMessage("Please ask a channel op to change the author of this link for you.") + } + } + + private fun removeEntry(channel: String, index: Int, event: GenericMessageEvent) { + val entry: EntryLink = entries.links[index] + if (entry.login == event.user.login || event.isChannelOp(channel)) { + LinksManager.pinboard.deletePin(entry) + LinksManager.socialManager.removeEntry(index) + entries.links.removeAt(index) + event.sendMessage("Entry ${index.toLinkLabel()} removed.") + entries.save() + } else { + event.sendMessage("Please ask a channel op to remove this entry for you.") + } + } + + private fun showEntry(index: Int, event: GenericMessageEvent) { + val entry: EntryLink = entries.links[index] + event.sendMessage(EntriesUtils.printLink(index, entry)) + if (entry.tags.isNotEmpty()) { + event.sendMessage(EntriesUtils.printTags(index, entry)) + } + if (entry.comments.isNotEmpty()) { + val comments = entry.comments + for (i in comments.indices) { + event.sendMessage(EntriesUtils.printComment(index, i, comments[i])) + } + } + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/links/Tags.kt b/bin/main/net/thauvin/erik/mobibot/commands/links/Tags.kt new file mode 100644 index 0000000..1662857 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/commands/links/Tags.kt @@ -0,0 +1,87 @@ +/* + * Tags.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.commands.links + +import net.thauvin.erik.mobibot.Constants +import net.thauvin.erik.mobibot.Utils.bot +import net.thauvin.erik.mobibot.Utils.helpFormat +import net.thauvin.erik.mobibot.Utils.isChannelOp +import net.thauvin.erik.mobibot.Utils.sendMessage +import net.thauvin.erik.mobibot.commands.AbstractCommand +import net.thauvin.erik.mobibot.entries.EntriesUtils +import net.thauvin.erik.mobibot.entries.EntryLink +import org.pircbotx.hooks.types.GenericMessageEvent + +class Tags : AbstractCommand() { + override val name = COMMAND + override val help = listOf( + "To categorize or tag a URL, use its label and a ${Constants.TAG_CMD}:", + helpFormat("${Constants.LINK_CMD}1${Constants.TAG_CMD}:<+tag|-tag> [...]") + ) + override val isOpOnly = false + override val isPublic = true + override val isVisible = true + + companion object { + const val COMMAND = "tags" + } + + override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { + val cmds = args.substring(1).split("${Constants.TAG_CMD}:", limit = 2) + val index = cmds[0].toInt() - 1 + + if (index < LinksManager.entries.links.size && LinksManager.isUpToDate(event)) { + val cmd = cmds[1].trim() + val entry: EntryLink = LinksManager.entries.links[index] + if (cmd.isNotEmpty()) { + if (entry.login == event.user.login || event.isChannelOp(channel)) { + entry.setTags(cmd) + LinksManager.pinboard.updatePin(event.bot().serverHostname, entry.link, entry) + event.sendMessage(EntriesUtils.printTags(index, entry)) + LinksManager.entries.save() + } else { + event.sendMessage("Please ask a channel op to change the tags for you.") + } + } else { + if (entry.tags.isNotEmpty()) { + event.sendMessage(EntriesUtils.printTags(index, entry)) + } else { + event.sendMessage("The entry has no tags. Why don't add some?") + } + } + } + } + + override fun matches(message: String): Boolean { + return message.matches("^${Constants.LINK_CMD}\\d+${Constants.TAG_CMD}:.*".toRegex()) + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/links/View.kt b/bin/main/net/thauvin/erik/mobibot/commands/links/View.kt new file mode 100644 index 0000000..825e374 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/commands/links/View.kt @@ -0,0 +1,120 @@ +/* + * View.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.commands.links + +import net.thauvin.erik.mobibot.Utils.bot +import net.thauvin.erik.mobibot.Utils.helpCmdSyntax +import net.thauvin.erik.mobibot.Utils.helpFormat +import net.thauvin.erik.mobibot.Utils.lastOrEmpty +import net.thauvin.erik.mobibot.Utils.sendMessage +import net.thauvin.erik.mobibot.commands.AbstractCommand +import net.thauvin.erik.mobibot.commands.links.LinksManager.Companion.entries +import net.thauvin.erik.mobibot.entries.EntriesUtils +import net.thauvin.erik.mobibot.entries.EntryLink +import org.pircbotx.hooks.events.PrivateMessageEvent +import org.pircbotx.hooks.types.GenericMessageEvent + +class View : AbstractCommand() { + override val name = VIEW_CMD + override val help = listOf( + "To list or search the current URL posts:", + helpFormat("%c $name [<start>] [<query>]") + ) + override val isOpOnly = false + override val isPublic = true + override val isVisible = true + + companion object { + const val MAX_ENTRIES = 6 + const val VIEW_CMD = "view" + } + + override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { + if (entries.links.isNotEmpty()) { + val p = parseArgs(args) + showPosts(p.first, p.second, event) + } else { + event.sendMessage("There is currently nothing to view. Why don't you post something?") + } + } + + internal fun parseArgs(args: String): Pair<Int, String> { + var query = args.lowercase().trim() + var start = 0 + if (query.isEmpty() && entries.links.size > MAX_ENTRIES) { + start = entries.links.size - MAX_ENTRIES + } + if (query.matches("^\\d+(| .*)".toRegex())) { // view [<start>] [<query>] + val split = query.split(" ", limit = 2) + try { + start = split[0].toInt() - 1 + query = split.lastOrEmpty().trim() + if (start > entries.links.size) { + start = 0 + } + } catch (ignore: NumberFormatException) { + // Do nothing + } + } + return Pair(start, query) + } + + private fun showPosts(start: Int, query: String, event: GenericMessageEvent) { + var index = start + var entry: EntryLink + var sent = 0 + while (index < entries.links.size && sent < MAX_ENTRIES) { + entry = entries.links[index] + if (query.isNotBlank()) { + if (entry.matches(query)) { + event.sendMessage(EntriesUtils.printLink(index, entry, true)) + sent++ + } + } else { + event.sendMessage(EntriesUtils.printLink(index, entry, true)) + sent++ + } + index++ + if (sent == MAX_ENTRIES && index < entries.links.size) { + event.sendMessage("To view more, try: ") + event.sendMessage( + helpFormat( + helpCmdSyntax("%c $name ${index + 1} $query", event.bot().nick, event is PrivateMessageEvent) + ) + ) + } + } + if (sent == 0) { + event.sendMessage("No matches. Please try again.") + } + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt b/bin/main/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt new file mode 100644 index 0000000..cfd2c27 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt @@ -0,0 +1,45 @@ +/* + * NickComparator.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.commands.seen + +import java.io.Serializable + +class NickComparator : Comparator<String>, Serializable { + override fun compare(a: String, b: String): Int { + return a.lowercase().compareTo(b.lowercase()) + } + + companion object { + @Suppress("ConstPropertyName") + private const val serialVersionUID = 1L + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/seen/Seen.kt b/bin/main/net/thauvin/erik/mobibot/commands/seen/Seen.kt new file mode 100644 index 0000000..c9ee0f3 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/commands/seen/Seen.kt @@ -0,0 +1,150 @@ +/* + * Seen.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.commands.seen + +import com.google.common.collect.ImmutableSortedSet +import net.thauvin.erik.mobibot.Utils +import net.thauvin.erik.mobibot.Utils.bold +import net.thauvin.erik.mobibot.Utils.bot +import net.thauvin.erik.mobibot.Utils.helpFormat +import net.thauvin.erik.mobibot.Utils.isChannelOp +import net.thauvin.erik.mobibot.Utils.loadSerialData +import net.thauvin.erik.mobibot.Utils.saveSerialData +import net.thauvin.erik.mobibot.Utils.sendList +import net.thauvin.erik.mobibot.Utils.sendMessage +import net.thauvin.erik.mobibot.commands.AbstractCommand +import net.thauvin.erik.mobibot.commands.Info.Companion.toUptime +import org.pircbotx.User +import org.pircbotx.hooks.types.GenericMessageEvent +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import java.util.* + + +class Seen(private val serialObject: String) : AbstractCommand() { + private val logger: Logger = LoggerFactory.getLogger(Seen::class.java) + private val allKeyword = "all" + val seenNicks = TreeMap<String, SeenNick>(NickComparator()) + + override val name = "seen" + override val help = listOf("To view when a nickname was last seen:", helpFormat("%c $name <nick>")) + private val helpOp = help.plus( + arrayOf("To view all ${"seen".bold()} nicks:", helpFormat("%c $name $allKeyword")) + ) + override val isOpOnly = false + override val isPublic = true + override val isVisible = true + + + override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { + if (isEnabled()) { + if (args.isNotBlank() && !args.contains(' ')) { + val ch = event.bot().userChannelDao.getChannel(channel) + if (args == allKeyword && ch.isOp(event.user) && seenNicks.isNotEmpty()) { + event.sendMessage("The ${"seen".bold()} nicks are:") + event.sendList(seenNicks.keys.toList(), 7, separator = ", ", isIndent = true) + return + } + ch.users.forEach { + if (args.equals(it.nick, true)) { + event.sendMessage("${it.nick} is on ${channel}.") + return + } + } + if (seenNicks.containsKey(args)) { + val seenNick = seenNicks.getValue(args) + val lastSeen = System.currentTimeMillis() - seenNick.lastSeen + event.sendMessage("${seenNick.nick} was last seen on $channel ${lastSeen.toUptime()} ago.") + return + } + event.sendMessage("I haven't seen $args on $channel lately.") + } else { + helpResponse(channel, args, event) + } + } + } + + fun add(nick: String) { + if (isEnabled()) { + seenNicks[nick] = SeenNick(nick, System.currentTimeMillis()) + save() + } + } + + fun add(users: ImmutableSortedSet<User>) { + if (isEnabled()) { + users.forEach { + seenNicks[it.nick] = SeenNick(it.nick, System.currentTimeMillis()) + } + save() + } + } + + fun clear() { + seenNicks.clear() + } + + fun count(): Int = seenNicks.size + + override fun helpResponse(channel: String, topic: String, event: GenericMessageEvent): Boolean { + return if (event.isChannelOp(channel)) { + for (h in helpOp) { + event.sendMessage(Utils.helpCmdSyntax(h, event.bot().nick, true)) + } + true + } else { + super.helpResponse(channel, topic, event) + } + } + + fun load() { + if (isEnabled()) { + @Suppress("UNCHECKED_CAST") + seenNicks.putAll( + loadSerialData( + serialObject, + TreeMap<String, SeenNick>(), + logger, + "seen nicknames" + ) as TreeMap<String, SeenNick> + ) + } + } + + fun save() { + saveSerialData(serialObject, seenNicks, logger, "seen nicknames") + } + + init { + load() + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt b/bin/main/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt new file mode 100644 index 0000000..7924977 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt @@ -0,0 +1,41 @@ +/* + * SeenNick.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.commands.seen + +import java.io.Serializable + +data class SeenNick(val nick: String, val lastSeen: Long) : Serializable { + companion object { + @Suppress("ConstPropertyName") + private const val serialVersionUID = 1L + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/tell/Tell.kt b/bin/main/net/thauvin/erik/mobibot/commands/tell/Tell.kt new file mode 100644 index 0000000..061ca6a --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/commands/tell/Tell.kt @@ -0,0 +1,306 @@ +/* + * Tell.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.commands.tell + +import net.thauvin.erik.mobibot.Utils.bold +import net.thauvin.erik.mobibot.Utils.bot +import net.thauvin.erik.mobibot.Utils.helpCmdSyntax +import net.thauvin.erik.mobibot.Utils.helpFormat +import net.thauvin.erik.mobibot.Utils.isChannelOp +import net.thauvin.erik.mobibot.Utils.plural +import net.thauvin.erik.mobibot.Utils.reverseColor +import net.thauvin.erik.mobibot.Utils.sendMessage +import net.thauvin.erik.mobibot.Utils.toIntOrDefault +import net.thauvin.erik.mobibot.Utils.toUtcDateTime +import net.thauvin.erik.mobibot.commands.AbstractCommand +import net.thauvin.erik.mobibot.commands.links.View +import org.pircbotx.PircBotX +import org.pircbotx.hooks.events.MessageEvent +import org.pircbotx.hooks.types.GenericMessageEvent +import org.pircbotx.hooks.types.GenericUserEvent + +/** + * The `Tell` command. + */ +class Tell(private val serialObject: String) : AbstractCommand() { + // Messages queue + private val messages: MutableList<TellMessage> = mutableListOf() + + // Maximum number of days to keep messages + private var maxDays = 7 + + // Message maximum queue size + private var maxSize = 50 + + /** + * The tell command. + */ + override val name = "tell" + + override val help = listOf( + "To send a message to someone when they join the channel:", + helpFormat("%c $name <nick> <message>"), + "To view queued and sent messages:", + helpFormat("%c $name ${View.VIEW_CMD}"), + "Messages are kept for ${maxDays.bold()}" + " day".plural(maxDays.toLong()) + '.' + ) + override val isOpOnly: Boolean = false + override val isPublic: Boolean = isEnabled() + override val isVisible: Boolean = isEnabled() + + /** + * Cleans the messages queue. + */ + private fun clean(): Boolean { + return TellManager.clean(messages, maxDays.toLong()) + } + + override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { + if (isEnabled()) { + when { + args.isBlank() -> { + helpResponse(channel, args, event) + } + + args.startsWith(View.VIEW_CMD) -> { + if (event.isChannelOp(channel) && "${View.VIEW_CMD} $TELL_ALL_KEYWORD" == args) { + viewAll(event) + } else { + viewMessages(event) + } + } + + args.startsWith("$TELL_DEL_KEYWORD ") -> { + deleteMessage(channel, args, event) + } + + else -> { + newMessage(channel, args, event) + } + } + if (clean()) { + save() + } + } + } + + // Delete message. + private fun deleteMessage(channel: String, args: String, event: GenericMessageEvent) { + val split = args.split(" ") + if (split.size == 2) { + val id = split[1] + if (TELL_ALL_KEYWORD.equals(id, ignoreCase = true)) { + if (messages.removeIf { it.sender.equals(event.user.nick, true) && it.isReceived }) { + save() + event.sendMessage("Delivered messages have been deleted.") + } else { + event.sendMessage("No delivered messages were found.") + } + } else { + if (messages.removeIf { + it.id == id && + (it.sender.equals(event.user.nick, true) || event.isChannelOp(channel)) + }) { + save() + event.sendMessage("The message was deleted from the queue.") + } else { + event.sendMessage("The specified message [ID $id] could not be found.") + } + } + } else { + helpResponse(channel, args, event) + } + } + + override fun isEnabled(): Boolean { + return maxSize > 0 && maxDays > 0 + } + + override fun setProperty(key: String, value: String) { + super.setProperty(key, value) + if (MAX_DAYS_PROP == key) { + maxDays = value.toIntOrDefault(maxDays) + } else if (MAX_SIZE_PROP == key) { + maxSize = value.toIntOrDefault(maxSize) + } + } + + // New message. + private fun newMessage(channel: String, args: String, event: GenericMessageEvent) { + val split = args.split(" ".toRegex(), 2) + if (split.size == 2 && split[1].isNotBlank() && split[1].contains(" ")) { + if (messages.size < maxSize) { + val message = TellMessage(event.user.nick, split[0], split[1].trim()) + messages.add(message) + save() + event.sendMessage("Message [ID ${message.id}] was queued for ${message.recipient.bold()}") + } else { + event.sendMessage("Sorry, the messages queue is currently full.") + } + } else { + helpResponse(channel, args, event) + } + } + + /** + * Saves the messages queue. + */ + private fun save() { + TellManager.save(serialObject, messages) + } + + /** + * Checks and sends messages. + */ + fun send(event: GenericUserEvent) { + val nickname = event.user.nick + if (isEnabled() && nickname != event.getBot<PircBotX>().nick) { + messages.filter { it.isMatch(nickname) }.forEach { message -> + if (message.recipient.equals(nickname, ignoreCase = true) && !message.isReceived) { + if (message.sender == nickname) { + if (event !is MessageEvent) { + event.user.send().message( + "${"You".bold()} wanted me to remind you: ${message.message.reverseColor()}" + ) + message.isReceived = true + message.isNotified = true + save() + } + } else { + event.user.send().message( + "${message.sender} wanted me to tell you: ${message.message.reverseColor()}" + ) + message.isReceived = true + save() + } + } else if (message.sender.equals(nickname, ignoreCase = true) && message.isReceived + && !message.isNotified + ) { + event.user.send().message( + "Your message ${"[ID ${message.id}]".reverseColor()} was sent to " + + "${message.recipient.bold()} on ${message.receptionDate}" + ) + message.isNotified = true + save() + } + } + } + } + + /** + * Returns the messages queue size. + * + * @return The size. + */ + fun size(): Int = messages.size + + // View all messages. + private fun viewAll(event: GenericMessageEvent) { + if (messages.isNotEmpty()) { + for (message in messages) { + event.sendMessage( + "${message.sender.bold()}$ARROW${message.recipient.bold()} [ID: ${message.id}, " + + (if (message.isReceived) "DELIVERED]" else "QUEUED]") + ) + } + } else { + event.sendMessage("There are no messages in the queue.") + } + } + + // View messages. + private fun viewMessages(event: GenericMessageEvent) { + var hasMessage = false + for (message in messages.filter { it.isMatch(event.user.nick) }) { + if (!hasMessage) { + hasMessage = true + event.sendMessage("Here are your messages: ") + } + if (message.isReceived) { + event.sendMessage( + message.sender.bold() + ARROW + message.recipient.bold() + + " [${message.receptionDate.toUtcDateTime()}, ID: ${message.id.bold()}, DELIVERED]" + ) + } else { + event.sendMessage( + message.sender.bold() + ARROW + message.recipient.bold() + + " [${message.queued.toUtcDateTime()}, ID: ${message.id.bold()}, QUEUED]" + ) + } + event.sendMessage(helpFormat(message.message)) + } + if (!hasMessage) { + event.sendMessage("You have no messages in the queue.") + } else { + event.sendMessage("To delete one or all delivered messages:") + event.sendMessage( + helpFormat( + helpCmdSyntax("%c $name $TELL_DEL_KEYWORD <id|$TELL_ALL_KEYWORD>", event.bot().nick, true) + ) + ) + event.sendMessage(help.last()) + } + } + + companion object { + /** + * Max days property. + */ + const val MAX_DAYS_PROP = "tell-max-days" + + /** + * Max size property. + */ + const val MAX_SIZE_PROP = "tell-max-size" + + // Arrow + private const val ARROW = " --> " + + // All keyword + private const val TELL_ALL_KEYWORD = "all" + + //T he delete command. + private const val TELL_DEL_KEYWORD = "del" + } + + /** + * Creates a new instance. + */ + init { + initProperties(MAX_DAYS_PROP, MAX_SIZE_PROP) + + // Load the message queue + messages.addAll(TellManager.load(serialObject)) + if (clean()) { + save() + } + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/tell/TellManager.kt b/bin/main/net/thauvin/erik/mobibot/commands/tell/TellManager.kt new file mode 100644 index 0000000..b65a4da --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/commands/tell/TellManager.kt @@ -0,0 +1,74 @@ +/* + * TellManager.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.commands.tell + +import net.thauvin.erik.mobibot.Utils.loadSerialData +import net.thauvin.erik.mobibot.Utils.saveSerialData +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import java.time.Clock +import java.time.LocalDateTime + +/** + * The Tell Messages Manager. + */ +object TellManager { + private val logger: Logger = LoggerFactory.getLogger(TellManager::class.java) + + /** + * Cleans the messages queue. + */ + @JvmStatic + fun clean(tellMessages: MutableList<TellMessage>, tellMaxDays: Long): Boolean { + if (logger.isDebugEnabled) logger.debug("Cleaning the messages.") + val today = LocalDateTime.now(Clock.systemUTC()) + return tellMessages.removeIf { o: TellMessage -> o.queued.plusDays(tellMaxDays).isBefore(today) } + } + + /** + * Loads the messages. + */ + @JvmStatic + fun load(file: String): List<TellMessage> { + @Suppress("UNCHECKED_CAST") + return loadSerialData(file, emptyList<TellMessage>(), logger, "message queue") as List<TellMessage> + } + + /** + * Saves the messages. + */ + @JvmStatic + fun save(file: String, messages: List<TellMessage?>?) { + if (messages != null) { + saveSerialData(file, messages, logger, "messages") + } + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt b/bin/main/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt new file mode 100644 index 0000000..d17fbb5 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt @@ -0,0 +1,104 @@ +/* + * TellMessage.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.commands.tell + +import java.io.Serializable +import java.time.Clock +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter + +/** + * Tell Message. + */ +class TellMessage( + /** + * Returns the message's sender. + */ + val sender: String, + + /** + * Returns the message's recipient. + */ + val recipient: String, + + /** + * Returns the message text. + */ + val message: String +) : Serializable { + /** + * Returns the queued date/time. + */ + var queued: LocalDateTime = LocalDateTime.now(Clock.systemUTC()) + + /** + * Returns the message id. + */ + var id: String = queued.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + + /** + * Returns `true` if a notification was sent. + */ + var isNotified = false + + /** + * Returns `true` if the message was received. + */ + var isReceived = false + set(value) { + if (value) { + receptionDate = LocalDateTime.now(Clock.systemUTC()) + } + field = value + } + + /** + * Returns the message creating date. + */ + var receptionDate: LocalDateTime = LocalDateTime.MIN + + /** + * Matches the message sender or recipient. + */ + fun isMatch(nick: String?): Boolean { + return sender.equals(nick, ignoreCase = true) || recipient.equals(nick, ignoreCase = true) + } + + override fun toString(): String { + return ("TellMessage{id='$id', isNotified=$isNotified, isReceived=$isReceived, message='$message', " + + "queued=$queued, received=$receptionDate, recipient='$recipient', sender='$sender'}") + } + + companion object { + @Suppress("ConstPropertyName") + private const val serialVersionUID = 2L + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/entries/Entries.kt b/bin/main/net/thauvin/erik/mobibot/entries/Entries.kt new file mode 100644 index 0000000..e8676ec --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/entries/Entries.kt @@ -0,0 +1,54 @@ +/* + * Entries.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.entries + +import net.thauvin.erik.mobibot.Utils.today + +class Entries( + var channel: String = "", + var ircServer: String = "", + var logsDir: String = "", + var backlogs: String = "" +) { + val links = mutableListOf<EntryLink>() + + var lastPubDate = today() + + fun load() { + lastPubDate = FeedsManager.loadFeed(this) + } + + fun save() { + lastPubDate = today() + FeedsManager.saveFeed(this) + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/entries/EntriesUtils.kt b/bin/main/net/thauvin/erik/mobibot/entries/EntriesUtils.kt new file mode 100644 index 0000000..9c09626 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/entries/EntriesUtils.kt @@ -0,0 +1,83 @@ +/* + * EntriesUtils.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.entries + +import net.thauvin.erik.mobibot.Constants +import net.thauvin.erik.mobibot.Utils.bold +import net.thauvin.erik.mobibot.Utils.green + +/** + * Entries utilities. + */ +object EntriesUtils { + /** + * Prints an entry's comment for display on the channel. + */ + @JvmStatic + fun printComment(entryIndex: Int, commentIndex: Int, comment: EntryComment): String = + ("${entryIndex.toLinkLabel()}.${commentIndex + 1}: [${comment.nick}] ${comment.comment}") + + /** + * Prints an entry's link for display on the channel. + */ + @JvmStatic + @JvmOverloads + fun printLink(entryIndex: Int, entry: EntryLink, isView: Boolean = false): String { + val buff = StringBuilder().append(entryIndex.toLinkLabel()).append(": ") + .append('[').append(entry.nick).append(']') + if (isView && entry.comments.isNotEmpty()) { + buff.append("[+").append(entry.comments.size).append(']') + } + buff.append(' ') + with(entry) { + if (Constants.NO_TITLE == title) { + buff.append(title) + } else { + buff.append(title.bold()) + } + buff.append(" ( ").append(link.green()).append(" )") + } + return buff.toString() + } + + /** + * Prints an entry's tags/categories for display on the channel. e.g. L1T: tag1, tag2 + */ + @JvmStatic + fun printTags(entryIndex: Int, entry: EntryLink): String = + entryIndex.toLinkLabel() + "${Constants.TAG_CMD}: " + entry.formatTags(", ") + + /** + * Builds link label based on its index. e.g: L1 + */ + @JvmStatic + fun Int.toLinkLabel(): String = Constants.LINK_CMD + (this + 1) +} diff --git a/bin/main/net/thauvin/erik/mobibot/entries/EntryComment.kt b/bin/main/net/thauvin/erik/mobibot/entries/EntryComment.kt new file mode 100644 index 0000000..e18d692 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/entries/EntryComment.kt @@ -0,0 +1,52 @@ +/* + * EntryComment.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.entries + +import java.io.Serializable +import java.time.LocalDateTime + +/** + * Entry comments data class. + */ +data class EntryComment(var comment: String, var nick: String) : Serializable { + /** + * Creation date. + */ + val date: LocalDateTime = LocalDateTime.now() + + override fun toString(): String = "EntryComment{comment='$comment', date=$date, nick='$nick'}" + + companion object { + // Serial version UID + @Suppress("ConstPropertyName") + private const val serialVersionUID: Long = 1L + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/entries/EntryLink.kt b/bin/main/net/thauvin/erik/mobibot/entries/EntryLink.kt new file mode 100644 index 0000000..4a69446 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/entries/EntryLink.kt @@ -0,0 +1,213 @@ +/* + * EntryLink.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.entries + +import com.rometools.rome.feed.synd.SyndCategory +import com.rometools.rome.feed.synd.SyndCategoryImpl +import net.thauvin.erik.mobibot.commands.links.LinksManager +import java.io.Serializable +import java.util.* + +/** + * The class used to store link entries. + */ +class EntryLink( + // Link's comments + val comments: MutableList<EntryComment> = mutableListOf(), + + // Tags/categories + val tags: MutableList<SyndCategory> = mutableListOf(), + + // Channel + var channel: String, + + // Creation date + var date: Date = Calendar.getInstance().time, + + // Link's URL + var link: String, + + // Author's login + var login: String = "", + + // Author's nickname + var nick: String, + + // Link's title + var title: String +) : Serializable { + /** + * Creates a new entry. + */ + constructor( + link: String, + title: String, + nick: String, + login: String, + channel: String, + tags: List<String?> + ) : this(link = link, title = title, nick = nick, login = login, channel = channel) { + setTags(tags) + } + + /** + * Creates a new entry. + */ + constructor( + link: String, + title: String, + nick: String, + channel: String, + date: Date, + tags: List<SyndCategory> + ) : this(link = link, title = title, nick = nick, channel = channel, date = Date(date.time)) { + this.tags.addAll(tags) + } + + /** + * Adds a new comment + */ + fun addComment(comment: EntryComment): Int { + comments.add(comment) + return comments.lastIndex + } + + /** + * Adds a new comment. + */ + fun addComment(comment: String, nick: String): Int { + return addComment(EntryComment(comment, nick)) + } + + /** + * Deletes a specific comment. + */ + fun deleteComment(index: Int): Boolean { + if (index < comments.size) { + comments.removeAt(index) + return true + } + return false + } + + /** + * Deletes a comment. + */ + fun deleteComment(entryComment: EntryComment): Boolean { + return comments.remove(entryComment) + } + + /** + * Formats the tags. + */ + fun formatTags(sep: String, prefix: String = ""): String { + return tags.joinToString(separator = sep, prefix = prefix) { it.name } + } + + /** + * Returns a comment. + */ + fun getComment(index: Int): EntryComment = comments[index] + + /** + * Returns true if a string is contained in the link, title, or nick. + */ + fun matches(match: String?): Boolean { + return if (match.isNullOrEmpty()) { + false + } else { + link.contains(match, true) || title.contains(match, true) || nick.contains(match, true) + } + } + + /** + * Sets a comment. + */ + fun setComment(index: Int, comment: String?, nick: String?) { + if (index < comments.size && !comment.isNullOrBlank() && !nick.isNullOrBlank()) { + comments[index] = EntryComment(comment, nick) + } + } + + /** + * Sets the tags. + */ + fun setTags(tags: String) { + setTags(tags.split(LinksManager.TAG_MATCH)) + } + + /** + * Sets the tags. + */ + private fun setTags(tags: List<String?>) { + if (tags.isNotEmpty()) { + var category: SyndCategoryImpl + for (tag in tags) { + if (!tag.isNullOrBlank()) { + val t = tag.lowercase() + val mod = t[0] + if (mod == '-') { + // Don't remove the channel tag + if (channel.substring(1) != t.substring(1)) { + category = SyndCategoryImpl() + category.name = t.substring(1) + this.tags.remove(category) + } + } else { + category = SyndCategoryImpl() + if (mod == '+') { + category.name = t.substring(1) + } else { + category.name = t + } + if (!this.tags.contains(category)) { + this.tags.add(category) + } + } + } + } + } + } + + /** + * Returns a string representation of the object. + */ + override fun toString(): String { + return ("EntryLink{channel='$channel', comments=$comments, date=$date, link='$link', login='$login'," + + "nick='$nick', tags=$tags, title='$title'}") + } + + companion object { + // Serial version UID + @Suppress("ConstPropertyName") + private const val serialVersionUID: Long = 1L + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/entries/FeedsManager.kt b/bin/main/net/thauvin/erik/mobibot/entries/FeedsManager.kt new file mode 100644 index 0000000..f786cb2 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/entries/FeedsManager.kt @@ -0,0 +1,187 @@ +/* + * FeedsManager.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.entries + +import com.rometools.rome.feed.synd.* +import com.rometools.rome.io.FeedException +import com.rometools.rome.io.SyndFeedInput +import com.rometools.rome.io.SyndFeedOutput +import net.thauvin.erik.mobibot.Utils.toIsoLocalDate +import net.thauvin.erik.mobibot.Utils.today +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import java.io.IOException +import java.io.InputStreamReader +import java.io.OutputStreamWriter +import java.nio.charset.StandardCharsets +import java.nio.file.Files +import java.nio.file.Paths +import java.util.* +import kotlin.io.path.exists + +/** + * Manages the RSS feeds. + */ +class FeedsManager private constructor() { + companion object { + private val logger: Logger = LoggerFactory.getLogger(FeedsManager::class.java) + + // The file containing the current entries. + private const val CURRENT_XML = "current.xml" + + // The .xml extension. + private const val DOT_XML = ".xml" + + /** + * Loads the current feed. + */ + @JvmStatic + @Throws(IOException::class, FeedException::class) + fun loadFeed(entries: Entries, currentFile: String = CURRENT_XML): String { + entries.links.clear() + val xml = Paths.get("${entries.logsDir}${currentFile}") + var pubDate = today() + if (xml.exists()) { + val input = SyndFeedInput() + InputStreamReader( + Files.newInputStream(xml), StandardCharsets.UTF_8 + ).use { reader -> + val feed = input.build(reader) + pubDate = feed.publishedDate.toIsoLocalDate() + val items = feed.entries + var entry: EntryLink + for (i in items.indices.reversed()) { + with(items[i]) { + entry = EntryLink( + link, + title, + author.substring(author.lastIndexOf('(') + 1, author.length - 1), + entries.channel, + publishedDate, + categories + ) + var split: List<String> + for (comment in description.value.split("<br/>")) { + split = comment.split(": ".toRegex(), 2) + if (split.size == 2) { + entry.addComment(comment = split[1].trim(), nick = split[0].trim()) + } + } + } + entries.links.add(entry) + } + } + } else { + // Create an empty feed. + saveFeed(entries) + } + return pubDate + } + + /** + * Saves the feeds. + */ + @JvmStatic + fun saveFeed(entries: Entries, currentFile: String = CURRENT_XML) { + if (logger.isDebugEnabled) logger.debug("Saving the feeds...") + if (entries.logsDir.isNotBlank()) { + try { + val output = SyndFeedOutput() + val rss: SyndFeed = SyndFeedImpl() + val items: MutableList<SyndEntry> = mutableListOf() + var item: SyndEntry + OutputStreamWriter( + Files.newOutputStream(Paths.get("${entries.logsDir}${currentFile}")), StandardCharsets.UTF_8 + ).use { fw -> + with(rss) { + feedType = "rss_2.0" + title = "${entries.channel} IRC Links" + description = "Links from ${entries.ircServer} on ${entries.channel}" + if (entries.backlogs.isNotBlank()) link = entries.backlogs + publishedDate = Calendar.getInstance().time + language = "en" + } + val buff: StringBuilder = StringBuilder() + for (i in entries.links.indices.reversed()) { + with(entries.links[i]) { + buff.setLength(0) + buff.append("Posted by <b>") + .append(nick) + .append("</b> on <a href=\"irc://") + .append(entries.ircServer).append('/') + .append(channel) + .append("\"><b>") + .append(channel) + .append("</b></a>") + if (comments.isNotEmpty()) { + buff.append(" <br/><br/>") + for (j in comments.indices) { + if (j > 0) { + buff.append(" <br/>") + } + buff.append(comments[j].nick).append(": ").append(comments[j].comment) + } + } + item = SyndEntryImpl() + item.link = link + item.description = SyndContentImpl().apply { value = buff.toString() } + item.title = title + item.publishedDate = date + item.author = "${channel.removePrefix("#")}@${entries.ircServer} ($nick)" + item.categories = tags + items.add(item) + } + } + rss.entries = items + if (logger.isDebugEnabled) logger.debug("Writing the entries feed.") + output.output(rss, fw) + } + OutputStreamWriter( + Files.newOutputStream( + Paths.get( + entries.logsDir + today() + DOT_XML + ) + ), StandardCharsets.UTF_8 + ).use { fw -> output.output(rss, fw) } + } catch (e: FeedException) { + if (logger.isWarnEnabled) logger.warn("Unable to generate the entries feed.", e) + } catch (e: IOException) { + if (logger.isWarnEnabled) + logger.warn("An IO error occurred while generating the entries feed.", e) + } + } else { + if (logger.isWarnEnabled) { + logger.warn("Unable to generate the entries feed. A required property is missing.") + } + } + } + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/AbstractModule.kt b/bin/main/net/thauvin/erik/mobibot/modules/AbstractModule.kt new file mode 100644 index 0000000..8c8e736 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/modules/AbstractModule.kt @@ -0,0 +1,131 @@ +/* + * AbstractModule.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.modules + +import net.thauvin.erik.mobibot.Utils.bot +import net.thauvin.erik.mobibot.Utils.helpCmdSyntax +import net.thauvin.erik.mobibot.Utils.sendMessage +import org.pircbotx.hooks.events.PrivateMessageEvent +import org.pircbotx.hooks.types.GenericMessageEvent + +/** + * The `Module` abstract class. + */ +abstract class AbstractModule { + /** + * The module name. + */ + abstract val name: String + + /** + * The module's commands, if any. + */ + @JvmField + val commands: MutableList<String> = mutableListOf() + + @JvmField + val help: MutableList<String> = mutableListOf() + val properties: MutableMap<String, String> = mutableMapOf() + + /** + * Responds to a command. + */ + abstract fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) + + /** + * Returns the module's property keys. + */ + val propertyKeys: Set<String> + get() = properties.keys + + /** + * Returns `true` if the module has properties. + */ + fun hasProperties(): Boolean { + return properties.isNotEmpty() + } + + /** + * Responds with the module's help. + */ + open fun helpResponse(event: GenericMessageEvent): Boolean { + for (h in help) { + event.sendMessage(helpCmdSyntax(h, event.bot().nick, isPrivateMsgEnabled && event is PrivateMessageEvent)) + } + return true + } + + /** + * Initializes the properties. + */ + fun initProperties(vararg keys: String) { + for (key in keys) { + properties[key] = "" + } + } + + /** + * Returns `true` if the module is enabled. + */ + val isEnabled: Boolean + get() = if (hasProperties()) { + isValidProperties + } else { + true + } + + /** + * Returns `true` if the module responds to private messages. + */ + open val isPrivateMsgEnabled: Boolean = false + + /** + * Ensures that all properties have values. + */ + open val isValidProperties: Boolean + get() { + for (s in properties.keys) { + if (properties[s].isNullOrBlank()) { + return false + } + } + return true + } + + /** + * Sets a property key and value. + */ + fun setProperty(key: String, value: String) { + if (key.isNotBlank()) { + properties[key] = value + } + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/Calc.kt b/bin/main/net/thauvin/erik/mobibot/modules/Calc.kt new file mode 100644 index 0000000..b7aae28 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/modules/Calc.kt @@ -0,0 +1,87 @@ +/* + * Calc.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.modules + +import net.objecthunter.exp4j.ExpressionBuilder +import net.objecthunter.exp4j.tokenizer.UnknownFunctionOrVariableException +import net.thauvin.erik.mobibot.Utils.bold +import net.thauvin.erik.mobibot.Utils.helpFormat +import org.pircbotx.hooks.types.GenericMessageEvent +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import java.text.DecimalFormat + +/** + * The Calc module. + */ +class Calc : AbstractModule() { + private val logger: Logger = LoggerFactory.getLogger(Calc::class.java) + + override val name = "Calc" + + override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { + if (args.isNotBlank()) { + try { + event.respond(calculate(args)) + } catch (e: IllegalArgumentException) { + if (logger.isWarnEnabled) logger.warn("Failed to calculate: $args", e) + event.respond("No idea. This is the kind of math I don't get.") + } catch (e: UnknownFunctionOrVariableException) { + if (logger.isWarnEnabled) logger.warn("Unable to calculate: $args", e) + event.respond("No idea. I must've some form of Dyscalculia.") + } + } else { + helpResponse(event) + } + } + + companion object { + // Calc command + private const val CALC_CMD = "calc" + + /** + * Performs a calculation. e.g.: 1 + 1 * 2 + */ + @JvmStatic + @Throws(IllegalArgumentException::class) + fun calculate(query: String): String { + val decimalFormat = DecimalFormat("#.##") + val calc = ExpressionBuilder(query).build() + return query.replace(" ", "") + " = " + decimalFormat.format(calc.evaluate()).bold() + } + } + + init { + commands.add(CALC_CMD) + help.add("To solve a mathematical calculation:") + help.add(helpFormat("%c $CALC_CMD <calculation>")) + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/ChatGpt.kt b/bin/main/net/thauvin/erik/mobibot/modules/ChatGpt.kt new file mode 100644 index 0000000..bd92332 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/modules/ChatGpt.kt @@ -0,0 +1,176 @@ +/* + * ChatGpt.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.modules + +import net.thauvin.erik.mobibot.Constants +import net.thauvin.erik.mobibot.Utils +import net.thauvin.erik.mobibot.Utils.sendMessage +import org.apache.commons.text.WordUtils +import org.json.JSONException +import org.json.JSONObject +import org.json.JSONWriter +import org.pircbotx.hooks.types.GenericMessageEvent +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import java.io.IOException +import java.net.URI +import java.net.http.HttpClient +import java.net.http.HttpRequest +import java.net.http.HttpResponse + +class ChatGpt : AbstractModule() { + private val logger: Logger = LoggerFactory.getLogger(ChatGpt::class.java) + + override val name = CHATGPT_NAME + + override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { + if (args.isNotBlank()) { + try { + val answer = chat( + args.trim(), properties[API_KEY_PROP], + properties.getOrDefault(MAX_TOKENS_PROP, "1024").toInt() + ) + if (answer.isNotBlank()) { + event.sendMessage(WordUtils.wrap(answer, 400)) + } else { + event.respond("$name is stumped.") + } + } catch (e: ModuleException) { + if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) + e.message?.let { + event.respond(it) + } + } catch (e: NumberFormatException) { + if (logger.isErrorEnabled) logger.error("Invalid $MAX_TOKENS_PROP property.", e) + event.respond("The $name module is misconfigured.") + } + } else { + helpResponse(event) + } + } + + companion object { + /** + * The service name. + */ + const val CHATGPT_NAME = "ChatGPT" + + /** + * The API Key property. + */ + const val API_KEY_PROP = "chatgpt-api-key" + + /** + * The max tokens property. + */ + const val MAX_TOKENS_PROP = "chatgpt-max-tokens" + + // ChatGPT API URL + private const val API_URL = "https://api.openai.com/v1/completions" + + // ChatGPT command + private const val CHATGPT_CMD = "chatgpt" + + + @JvmStatic + @Throws(ModuleException::class) + fun chat(query: String, apiKey: String?, maxTokens: Int): String { + if (!apiKey.isNullOrEmpty()) { + val prompt = JSONWriter.valueToString("Q:$query\nA:") + val request = HttpRequest.newBuilder() + .uri(URI.create(API_URL)) + .header("Content-Type", "application/json") + .header("Authorization", "Bearer $apiKey") + .header("User-Agent", Constants.USER_AGENT) + .POST( + HttpRequest.BodyPublishers.ofString( + """{ + "model": "text-davinci-003", + "prompt": $prompt, + "temperature": 0, + "max_tokens": $maxTokens, + "top_p": 1, + "frequency_penalty": 0, + "presence_penalty": 0 + }""".trimIndent() + ) + ) + .build() + try { + val response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString()) + if (response.statusCode() == 200) { + try { + val jsonResponse = JSONObject(response.body()) + val choices = jsonResponse.getJSONArray("choices") + return choices.getJSONObject(0).getString("text").trim() + } catch (e: JSONException) { + throw ModuleException( + "$CHATGPT_CMD($query): JSON", + "A JSON error has occurred while conversing with $CHATGPT_NAME.", + e + ) + } + } else { + if (response.statusCode() == 429) { + throw ModuleException( + "$CHATGPT_CMD($query): Rate limit reached", + "Rate limit reached. Please try again later." + ) + } else { + throw IOException("HTTP Status Code: " + response.statusCode()) + } + } + } catch (e: IOException) { + throw ModuleException( + "$CHATGPT_CMD($query): IO", + "An IO error has occurred while conversing with $CHATGPT_NAME.", + e + ) + } + } else { + throw ModuleException("$CHATGPT_CMD($query)", "No $CHATGPT_NAME API key specified.") + } + } + } + + init { + commands.add(CHATGPT_CMD) + with(help) { + add("To get answers from $name:") + add(Utils.helpFormat("%c $CHATGPT_CMD <query>")) + add("For example:") + add(Utils.helpFormat("%c $CHATGPT_CMD explain quantum computing in simple terms")) + add(Utils.helpFormat("%c $CHATGPT_CMD how do I make an HTTP request in Javascript?")) + } + initProperties(API_KEY_PROP, MAX_TOKENS_PROP) + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/CryptoPrices.kt b/bin/main/net/thauvin/erik/mobibot/modules/CryptoPrices.kt new file mode 100644 index 0000000..d14056e --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/modules/CryptoPrices.kt @@ -0,0 +1,159 @@ +/* + * CryptoPrices.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.modules + +import net.thauvin.erik.crypto.CryptoException +import net.thauvin.erik.crypto.CryptoPrice +import net.thauvin.erik.crypto.CryptoPrice.Companion.spotPrice +import net.thauvin.erik.mobibot.Utils.helpFormat +import net.thauvin.erik.mobibot.Utils.sendList +import net.thauvin.erik.mobibot.Utils.sendMessage +import org.json.JSONObject +import org.pircbotx.hooks.types.GenericMessageEvent +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import java.io.IOException + +/** + * The Cryptocurrency Prices module. + */ +class CryptoPrices : AbstractModule() { + private val logger: Logger = LoggerFactory.getLogger(CryptoPrices::class.java) + + override val name = "CryptoPrices" + + /** + * Returns the cryptocurrency market price from + * [Coinbase](https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-prices#get-spot-price). + */ + override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { + if (CURRENCIES.isEmpty()) { + try { + loadCurrencies() + } catch (e: ModuleException) { + if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) + } + } + + val debugMessage = "crypto($cmd $args)" + if (args == CODES_KEYWORD) { + event.sendMessage("The supported currencies are:") + event.sendList(ArrayList(CURRENCIES.keys), 10, isIndent = true) + } else if (args.matches("\\w+( [a-zA-Z]{3}+)?".toRegex())) { + try { + val price = currentPrice(args.split(' ')) + val amount = try { + price.toCurrency() + } catch (ignore: IllegalArgumentException) { + price.amount + } + event.respond("${price.base} current price is $amount [${CURRENCIES[price.currency]}]") + } catch (e: CryptoException) { + if (logger.isWarnEnabled) logger.warn("$debugMessage => ${e.statusCode}", e) + e.message?.let { + event.respond(it) + } + } catch (e: IOException) { + if (logger.isErrorEnabled) logger.error(debugMessage, e) + event.respond("An IO error has occurred while retrieving the cryptocurrency market price.") + } + } else { + helpResponse(event) + } + + } + + companion object { + // Crypto command + private const val CRYPTO_CMD = "crypto" + + // Fiat Currencies + private val CURRENCIES: MutableMap<String, String> = mutableMapOf() + + // Currency codes keyword + private const val CODES_KEYWORD = "codes" + + /** + * Get current market price. + */ + @JvmStatic + fun currentPrice(args: List<String>): CryptoPrice { + return if (args.size == 2) + spotPrice(args[0], args[1]) + else + spotPrice(args[0]) + } + + /** + * For testing purposes. + */ + fun getCurrencyName(code: String): String? { + return CURRENCIES[code] + } + + /** + * Loads the Fiat currencies.. + */ + @JvmStatic + @Throws(ModuleException::class) + fun loadCurrencies() { + try { + val json = JSONObject(CryptoPrice.apiCall(listOf("currencies"))) + val data = json.getJSONArray("data") + for (i in 0 until data.length()) { + val d = data.getJSONObject(i) + CURRENCIES[d.getString("id")] = d.getString("name") + } + } catch (e: CryptoException) { + throw ModuleException( + "loadCurrencies(): CE", + "An error has occurred while retrieving the currencies table.", + e + ) + } + } + } + + init { + commands.add(CRYPTO_CMD) + with(help) { + add("To retrieve a cryptocurrency's market price:") + add(helpFormat("%c $CRYPTO_CMD <symbol> [<currency>]")) + add("For example:") + add(helpFormat("%c $CRYPTO_CMD BTC")) + add(helpFormat("%c $CRYPTO_CMD ETH EUR")) + add(helpFormat("%c $CRYPTO_CMD ETH2 GPB")) + add("To list the supported currencies:") + add(helpFormat("%c $CRYPTO_CMD $CODES_KEYWORD")) + } + loadCurrencies() + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt b/bin/main/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt new file mode 100644 index 0000000..da0efd8 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt @@ -0,0 +1,222 @@ +/* + * CurrencyConverter.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.modules + +import net.thauvin.erik.mobibot.Utils.bot +import net.thauvin.erik.mobibot.Utils.helpCmdSyntax +import net.thauvin.erik.mobibot.Utils.helpFormat +import net.thauvin.erik.mobibot.Utils.reader +import net.thauvin.erik.mobibot.Utils.sendList +import net.thauvin.erik.mobibot.Utils.sendMessage +import net.thauvin.erik.mobibot.msg.ErrorMessage +import net.thauvin.erik.mobibot.msg.Message +import net.thauvin.erik.mobibot.msg.PublicMessage +import org.json.JSONObject +import org.pircbotx.hooks.types.GenericMessageEvent +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import java.io.IOException +import java.net.URL +import java.text.DecimalFormat +import java.util.* + + +/** + * The CurrencyConverter module. + */ +class CurrencyConverter : AbstractModule() { + private val logger: Logger = LoggerFactory.getLogger(CurrencyConverter::class.java) + + override val name = "CurrencyConverter" + + // Reload currency codes + private fun reload(apiKey: String?) { + if (!apiKey.isNullOrEmpty() && SYMBOLS.isEmpty()) { + try { + loadSymbols(apiKey) + } catch (e: ModuleException) { + if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) + } + } + } + + /** + * Converts the specified currencies. + */ + override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { + reload(properties[API_KEY_PROP]) + + when { + SYMBOLS.isEmpty() -> { + event.respond(EMPTY_SYMBOLS_TABLE) + } + + args.matches("\\d+([,\\d]+)?(\\.\\d+)? [a-zA-Z]{3}+ (to|in) [a-zA-Z]{3}+".toRegex()) -> { + val msg = convertCurrency(properties[API_KEY_PROP], args) + event.respond(msg.msg) + if (msg.isError) { + helpResponse(event) + } + } + + args.contains(CODES_KEYWORD) -> { + event.sendMessage("The supported currency codes are:") + event.sendList(SYMBOLS.keys.toList(), 11, isIndent = true) + } + + else -> { + helpResponse(event) + } + } + } + + override fun helpResponse(event: GenericMessageEvent): Boolean { + reload(properties[API_KEY_PROP]) + + if (SYMBOLS.isEmpty()) { + event.sendMessage(EMPTY_SYMBOLS_TABLE) + } else { + val nick = event.bot().nick + event.sendMessage("To convert from one currency to another:") + event.sendMessage(helpFormat(helpCmdSyntax("%c $CURRENCY_CMD 100 USD to EUR", nick, isPrivateMsgEnabled))) + event.sendMessage( + helpFormat( + helpCmdSyntax("%c $CURRENCY_CMD 50,000 GBP to USD", nick, isPrivateMsgEnabled) + ) + ) + event.sendMessage("To list the supported currency codes:") + event.sendMessage( + helpFormat( + helpCmdSyntax("%c $CURRENCY_CMD $CODES_KEYWORD", nick, isPrivateMsgEnabled) + ) + ) + } + return true + } + + companion object { + /** + * The API Key property. + */ + const val API_KEY_PROP = "exchangerate-api-key" + + // Currency command + private const val CURRENCY_CMD = "currency" + + // Currency codes keyword + private const val CODES_KEYWORD = "codes" + + // Empty symbols table. + private const val EMPTY_SYMBOLS_TABLE = "Sorry, but the currency table is empty." + + // Currency symbols + private val SYMBOLS: TreeMap<String, String> = TreeMap() + + // Decimal format + private val DECIMAL_FORMAT = DecimalFormat("0.00#") + + /** + * Converts from a currency to another. + */ + @JvmStatic + fun convertCurrency(apiKey: String?, query: String): Message { + if (apiKey.isNullOrEmpty()) { + throw ModuleException("${CURRENCY_CMD}($query)", "No Exchange Rate API key specified.") + } + + val cmds = query.split(" ") + return if (cmds.size == 4) { + if (cmds[3] == cmds[1] || "0" == cmds[0]) { + PublicMessage("You're kidding, right?") + } else { + val to = cmds[1].uppercase() + val from = cmds[3].uppercase() + if (SYMBOLS.contains(to) && SYMBOLS.contains(from)) { + try { + val amt = cmds[0].replace(",", "") + val url = URL("https://v6.exchangerate-api.com/v6/$apiKey/pair/$to/$from/$amt") + val body = url.reader().body + val json = JSONObject(body) + + if (json.getString("result") == "success") { + val result = DECIMAL_FORMAT.format(json.getDouble("conversion_result")) + PublicMessage( + "${cmds[0]} ${SYMBOLS[to]} = $result ${SYMBOLS[from]}" + ) + } else { + ErrorMessage("Sorry, an error occurred while converting the currencies.") + } + } catch (ignore: IOException) { + ErrorMessage("Sorry, an IO error occurred while converting the currencies.") + } + } else { + ErrorMessage("Sounds like monopoly money to me!") + } + } + } else { + ErrorMessage("Invalid query. Let's try again.") + } + } + + /** + * Loads the currency ISO symbols. + */ + @JvmStatic + @Throws(ModuleException::class) + fun loadSymbols(apiKey: String?) { + if (!apiKey.isNullOrEmpty()) { + try { + val url = URL("https://v6.exchangerate-api.com/v6/$apiKey/codes") + val json = JSONObject(url.reader().body) + if (json.getString("result") == "success") { + val codes = json.getJSONArray("supported_codes") + for (i in 0 until codes.length()) { + val code = codes.getJSONArray(i) + SYMBOLS[code.getString(0)] = code.getString(1) + } + } + } catch (e: IOException) { + throw ModuleException( + "loadCodes(): IOE", + "An IO error has occurred while retrieving the currencies.", + e + ) + } + } + } + } + + init { + commands.add(CURRENCY_CMD) + initProperties(API_KEY_PROP) + loadSymbols(properties[ChatGpt.API_KEY_PROP]) + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/Dice.kt b/bin/main/net/thauvin/erik/mobibot/modules/Dice.kt new file mode 100644 index 0000000..8420fb1 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/modules/Dice.kt @@ -0,0 +1,87 @@ +/* + * Dice.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.modules + +import net.thauvin.erik.mobibot.Utils.bold +import net.thauvin.erik.mobibot.Utils.helpFormat +import org.pircbotx.hooks.types.GenericMessageEvent + +/** + * The Dice module. + */ +class Dice : AbstractModule() { + override val name = "Dice" + + override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { + val arg = if (args.isBlank()) "2d6" else args.trim() + val match = Regex("^([1-9]|[12]\\d|3[0-2])[dD]([1-9]|[12]\\d|3[0-2])$").find(arg) + if (match != null) { + val (dice, sides) = match.destructured + event.respond("you rolled " + roll(dice.toInt(), sides.toInt())) + } else { + helpResponse(event) + } + } + + companion object { + // Dice command + private const val DICE_CMD = "dice" + + @JvmStatic + fun roll(dice: Int, sides: Int): String { + val result = StringBuilder() + var total = 0 + + repeat(dice) { + val roll = (1..sides).random() + total += roll + + if (result.isNotEmpty()) { + result.append(" + ") + } + + result.append(roll.bold()) + } + + if (dice != 1) { + result.append(" = ${total.bold()}") + } + + return result.toString() + } + } + + init { + commands.add(DICE_CMD) + help.add("To roll 2 dice with 6 sides:") + help.add(helpFormat("%c $DICE_CMD [2d6]")) + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/GoogleSearch.kt b/bin/main/net/thauvin/erik/mobibot/modules/GoogleSearch.kt new file mode 100644 index 0000000..f426d1e --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/modules/GoogleSearch.kt @@ -0,0 +1,162 @@ +/* + * GoogleSearch.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.modules + +import net.thauvin.erik.mobibot.ReleaseInfo +import net.thauvin.erik.mobibot.Utils.capitalise +import net.thauvin.erik.mobibot.Utils.colorize +import net.thauvin.erik.mobibot.Utils.encodeUrl +import net.thauvin.erik.mobibot.Utils.helpFormat +import net.thauvin.erik.mobibot.Utils.reader +import net.thauvin.erik.mobibot.Utils.sendMessage +import net.thauvin.erik.mobibot.Utils.unescapeXml +import net.thauvin.erik.mobibot.msg.ErrorMessage +import net.thauvin.erik.mobibot.msg.Message +import net.thauvin.erik.mobibot.msg.NoticeMessage +import org.json.JSONException +import org.json.JSONObject +import org.pircbotx.Colors +import org.pircbotx.hooks.types.GenericMessageEvent +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import java.io.IOException +import java.net.URL + +/** + * The GoogleSearch module. + */ +class GoogleSearch : AbstractModule() { + private val logger: Logger = LoggerFactory.getLogger(GoogleSearch::class.java) + + override val name = "GoogleSearch" + + /** + * Searches Google. + */ + override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { + if (args.isNotBlank()) { + try { + val results = searchGoogle( + args, + properties[API_KEY_PROP], + properties[CSE_KEY_PROP], + event.user.nick + ) + for (msg in results) { + if (msg.isError) { + event.respond(msg.msg.colorize(msg.color)) + } else { + event.sendMessage(channel, msg) + } + } + } catch (e: ModuleException) { + if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) + e.message?.let { + event.respond(it) + } + } + } else { + helpResponse(event) + } + } + + companion object { + // Google API Key property + const val API_KEY_PROP = "google-api-key" + + // Google Custom Search Engine ID property + const val CSE_KEY_PROP = "google-cse-cx" + + // Google command + private const val GOOGLE_CMD = "google" + + /** + * Performs a search on Google. + */ + @JvmStatic + @Throws(ModuleException::class) + fun searchGoogle( + query: String, + apiKey: String?, + cseKey: String?, + quotaUser: String = ReleaseInfo.PROJECT + ): List<Message> { + if (apiKey.isNullOrBlank() || cseKey.isNullOrBlank()) { + throw ModuleException( + "${GoogleSearch::class.java.name} is disabled.", + "${GOOGLE_CMD.capitalise()} is disabled. The API keys are missing." + ) + } + val results = mutableListOf<Message>() + if (query.isNotBlank()) { + try { + val url = URL( + "https://www.googleapis.com/customsearch/v1?key=$apiKey&cx=$cseKey" + + ""aUser=${quotaUser}&q=${query.encodeUrl()}&filter=1&num=5&alt=json" + ) + val json = JSONObject(url.reader().body) + if (json.has("items")) { + val ja = json.getJSONArray("items") + for (i in 0 until ja.length()) { + val j = ja.getJSONObject(i) + results.add(NoticeMessage(j.getString("title").unescapeXml())) + results.add(NoticeMessage(helpFormat(j.getString("link"), false), Colors.DARK_GREEN)) + } + } else if (json.has("error")) { + val error = json.getJSONObject("error") + val message = error.getString("message") + throw ModuleException("searchGoogle($query): ${error.getInt("code")} : $message", message) + } else { + results.add(ErrorMessage("No results found.", Colors.RED)) + } + } catch (e: IOException) { + throw ModuleException("searchGoogle($query): IOE", "An IO error has occurred searching Google.", e) + } catch (e: JSONException) { + throw ModuleException( + "searchGoogle($query): JSON", + "A JSON error has occurred searching Google.", + e + ) + } + } else { + results.add(ErrorMessage("Invalid query. Please try again.")) + } + return results + } + } + + init { + commands.add(GOOGLE_CMD) + help.add("To search Google:") + help.add(helpFormat("%c $GOOGLE_CMD <query>")) + initProperties(API_KEY_PROP, CSE_KEY_PROP) + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/Joke.kt b/bin/main/net/thauvin/erik/mobibot/modules/Joke.kt new file mode 100644 index 0000000..2760fa7 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/modules/Joke.kt @@ -0,0 +1,105 @@ +/* + * Joke.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.modules + +import net.thauvin.erik.jokeapi.exceptions.HttpErrorException +import net.thauvin.erik.jokeapi.exceptions.JokeException +import net.thauvin.erik.jokeapi.joke +import net.thauvin.erik.jokeapi.models.Type +import net.thauvin.erik.mobibot.Utils.bot +import net.thauvin.erik.mobibot.Utils.colorize +import net.thauvin.erik.mobibot.Utils.helpFormat +import net.thauvin.erik.mobibot.msg.Message +import net.thauvin.erik.mobibot.msg.PublicMessage +import org.json.JSONException +import org.pircbotx.Colors +import org.pircbotx.hooks.types.GenericMessageEvent +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import java.io.IOException + +/** + * The Joke module. + */ +class Joke : AbstractModule() { + private val logger: Logger = LoggerFactory.getLogger(Joke::class.java) + + override val name = "Joke" + + /** + * Returns a random joke from [JokeAPI](https://v2.jokeapi.dev/). + */ + override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { + with(event.bot()) { + try { + randomJoke().forEach { + sendIRC().notice(channel, it.msg.colorize(it.color)) + } + } catch (e: ModuleException) { + if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) + e.message?.let { + event.respond(it) + } + } + } + } + + companion object { + // Joke command + private const val JOKE_CMD = "joke" + + /** + * Retrieves a random joke. + */ + @JvmStatic + @Throws(ModuleException::class) + fun randomJoke(): List<Message> { + return try { + val joke = joke(safe = true, type = Type.SINGLE, splitNewLine = true) + joke.joke.map { PublicMessage(it, Colors.CYAN) } + } catch (e: JokeException) { + throw ModuleException("randomJoke(): ${e.additionalInfo}", e.message, e) + } catch (e: HttpErrorException) { + throw ModuleException("randomJoke(): HTTP: ${e.statusCode}", e.message, e) + } catch (e: IOException) { + throw ModuleException("randomJoke(): IOE", "An IO error has occurred retrieving a random joke.", e) + } catch (e: JSONException) { + throw ModuleException("randomJoke(): JSON", "A parsing error has occurred retrieving a random joke.", e) + } + } + } + + init { + commands.add(JOKE_CMD) + help.add("To display a random joke:") + help.add(helpFormat("%c $JOKE_CMD")) + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/Lookup.kt b/bin/main/net/thauvin/erik/mobibot/modules/Lookup.kt new file mode 100644 index 0000000..9ab2ead --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/modules/Lookup.kt @@ -0,0 +1,171 @@ +/* + * Lookup.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.modules + +import net.thauvin.erik.mobibot.Constants +import net.thauvin.erik.mobibot.Utils.bot +import net.thauvin.erik.mobibot.Utils.helpFormat +import org.apache.commons.net.whois.WhoisClient +import org.pircbotx.hooks.types.GenericMessageEvent +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import java.io.IOException +import java.net.InetAddress +import java.net.UnknownHostException + +/** + * The Lookup module. + */ +class Lookup : AbstractModule() { + private val logger: Logger = LoggerFactory.getLogger(Lookup::class.java) + + override val name = "Lookup" + + override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { + if (args.matches("(\\S.)+(\\S)+".toRegex())) { + try { + event.respondWith(nslookup(args).prependIndent()) + } catch (ignore: UnknownHostException) { + if (args.matches( + ("(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)") + .toRegex() + ) + ) { + try { + val lines = whois(args) + if (lines.isNotEmpty()) { + var line: String + var hasData = false + for (rawLine in lines) { + line = rawLine.trim() + if (line.matches("^\\b(?!\\b[Cc]omment\\b)\\w+\\b: .*$".toRegex())) { + if (!hasData) { + event.respondWith(line) + hasData = true + } else { + event.bot().sendIRC().notice(event.user.nick, line) + } + } + } + } else { + event.respond("Unknown host.") + } + } catch (ioe: IOException) { + if (logger.isWarnEnabled) { + logger.warn("Unable to perform whois IP lookup: $args", ioe) + } + event.respond("Unable to perform whois IP lookup: ${ioe.message}") + } + } else { + event.respond("Unknown host.") + } + } + } else { + helpResponse(event) + } + } + + companion object { + /** + * The whois default host. + */ + const val WHOIS_HOST = "whois.arin.net" + + // Lookup command + private const val LOOKUP_CMD = "lookup" + + /** + * Performs a DNS lookup on the specified query. + */ + @JvmStatic + @Throws(UnknownHostException::class) + fun nslookup(query: String): String { + val buffer = StringBuilder() + val results = InetAddress.getAllByName(query) + var hostInfo: String + for (result in results) { + if (result.hostAddress == query) { + hostInfo = result.hostName + if (hostInfo == query) { + throw UnknownHostException() + } + } else { + hostInfo = result.hostAddress + } + if (buffer.isNotEmpty()) { + buffer.append(", ") + } + buffer.append(hostInfo) + } + return buffer.toString() + } + + /** + * Performs a whois IP query. + */ + @Throws(IOException::class) + private fun whois(query: String): List<String> { + return whois(query, WHOIS_HOST) + } + + /** + * Performs a whois IP query. + */ + @JvmStatic + @Throws(IOException::class) + fun whois(query: String, host: String): List<String> { + val whoisClient = WhoisClient() + val lines: List<String> + with(whoisClient) { + try { + defaultTimeout = Constants.CONNECT_TIMEOUT + connect(host) + soTimeout = Constants.CONNECT_TIMEOUT + setSoLinger(false, 0) + lines = if (WHOIS_HOST == host) { + query("n - $query").split("\n") + } else { + query(query).split("\n") + } + } finally { + disconnect() + } + } + return lines + } + } + + init { + commands.add(LOOKUP_CMD) + help.add("To perform a DNS lookup query:") + help.add(helpFormat("%c $LOOKUP_CMD <ip address or hostname>")) + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/Mastodon.kt b/bin/main/net/thauvin/erik/mobibot/modules/Mastodon.kt new file mode 100644 index 0000000..3be3a5f --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/modules/Mastodon.kt @@ -0,0 +1,149 @@ +/* + * Mastodon.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.modules + +import net.thauvin.erik.mobibot.Utils +import net.thauvin.erik.mobibot.Utils.prefixIfMissing +import net.thauvin.erik.mobibot.entries.EntryLink +import net.thauvin.erik.mobibot.social.SocialModule +import org.json.JSONException +import org.json.JSONObject +import org.json.JSONWriter +import java.io.IOException +import java.net.URI +import java.net.http.HttpClient +import java.net.http.HttpRequest +import java.net.http.HttpResponse + +class Mastodon : SocialModule() { + override val name = "Mastodon" + + override val handle: String? + get() = properties[HANDLE_PROP] + + override val isAutoPost: Boolean + get() = isEnabled && properties[AUTO_POST_PROP].toBoolean() + + override val isValidProperties: Boolean + get() = !(properties[INSTANCE_PROP].isNullOrBlank() || properties[ACCESS_TOKEN_PROP].isNullOrBlank()) + + /** + * Formats the entry for posting. + */ + override fun formatEntry(entry: EntryLink): String { + return "${entry.title} (via ${entry.nick} on ${entry.channel})${formatTags(entry)}\n\n${entry.link}" + } + + private fun formatTags(entry: EntryLink): String { + return entry.tags.filter { !it.name.equals(entry.channel.removePrefix("#"), true) } + .joinToString(separator = " ", prefix = "\n\n") { "#${it.name}" } + } + + /** + * Posts on Mastodon. + */ + @Throws(ModuleException::class) + override fun post(message: String, isDm: Boolean): String { + return toot( + apiKey = properties[ACCESS_TOKEN_PROP], + instance = properties[INSTANCE_PROP], + handle = handle, + message = message, + isDm = isDm + ) + } + + companion object { + // Property keys + const val ACCESS_TOKEN_PROP = "mastodon-access-token" + const val AUTO_POST_PROP = "mastodon-auto-post" + const val HANDLE_PROP = "mastodon-handle" + const val INSTANCE_PROP = "mastodon-instance" + + private const val MASTODON_CMD = "mastodon" + private const val TOOT_CMD = "toot" + + /** + * Post on Mastodon. + */ + @JvmStatic + @Throws(ModuleException::class) + fun toot(apiKey: String?, instance: String?, handle: String?, message: String, isDm: Boolean): String { + val request = HttpRequest.newBuilder() + .uri(URI.create("https://$instance/api/v1/statuses")) + .header("Content-Type", "application/json") + .header("Authorization", "Bearer $apiKey") + .POST( + HttpRequest.BodyPublishers.ofString( + JSONWriter.valueToString( + if (isDm) { + mapOf("status" to "${handle?.prefixIfMissing('@')} $message", "visibility" to "direct") + } else { + mapOf("status" to message) + } + ) + ) + ) + .build() + try { + val response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString()) + if (response.statusCode() == 200) { + return try { + val jsonResponse = JSONObject(response.body()) + if (isDm) { + jsonResponse.getString("content") + } else { + "Your message was posted to ${jsonResponse.getString("url")}" + } + } catch (e: JSONException) { + throw ModuleException("mastodonPost($message)", "A JSON error has occurred: ${e.message}", e) + } + } else { + throw IOException("Status Code: " + response.statusCode()) + } + } catch (e: IOException) { + throw ModuleException("mastodonPost($message)", "An IO error has occurred: ${e.message}", e) + } catch (e: InterruptedException) { + throw ModuleException("mastodonPost($message)", "An error has occurred: ${e.message}", e) + } + } + } + + init { + commands.add(MASTODON_CMD) + commands.add(TOOT_CMD) + help.add("To toot on Mastodon:") + help.add(Utils.helpFormat("%c $TOOT_CMD <message>")) + properties[AUTO_POST_PROP] = "false" + initProperties(ACCESS_TOKEN_PROP, HANDLE_PROP, INSTANCE_PROP) + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/ModuleException.kt b/bin/main/net/thauvin/erik/mobibot/modules/ModuleException.kt new file mode 100644 index 0000000..a7416c2 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/modules/ModuleException.kt @@ -0,0 +1,45 @@ +/* + * ModuleException.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.modules + +/** + * The `ModuleException` class. + */ +class ModuleException @JvmOverloads constructor( + val debugMessage: String, + message: String? = null, + cause: Throwable? = null +) : Exception(message, cause) { + companion object { + @Suppress("ConstPropertyName") + private const val serialVersionUID = 1L + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/Ping.kt b/bin/main/net/thauvin/erik/mobibot/modules/Ping.kt new file mode 100644 index 0000000..944dbc1 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/modules/Ping.kt @@ -0,0 +1,83 @@ +/* + * Ping.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.modules + +import net.thauvin.erik.mobibot.Utils.bot +import net.thauvin.erik.mobibot.Utils.helpFormat +import org.pircbotx.hooks.types.GenericMessageEvent + +/** + * The Ping module. + */ +class Ping : AbstractModule() { + override val name = "Ping" + + override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { + event.bot().sendIRC().action(channel, randomPing()) + } + + companion object { + /** + * The ping responses. + */ + @JvmField + val PINGS = listOf( + "is barely alive.", + "is trying to stay awake.", + "has gone fishing.", + "is somewhere over the rainbow.", + "has fallen and can't get up.", + "is running. You better go chase it.", + "has just spontaneously combusted.", + "is talking to itself... don't interrupt. That's rude.", + "is bartending at an AA meeting.", + "is hibernating.", + "is saving energy: apathetic mode activated.", + "is busy. Go away!" + ) + + @JvmStatic + fun randomPing(): String { + return PINGS[PINGS.indices.random()] + } + + /** + * The ping command. + */ + private const val PING_CMD = "ping" + } + + init { + commands.add(PING_CMD) + help.add("To ping the bot:") + help.add(helpFormat("%c $PING_CMD")) + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt b/bin/main/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt new file mode 100644 index 0000000..a299d8d --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt @@ -0,0 +1,114 @@ +/* + * RockPaperScissors.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.modules + +import net.thauvin.erik.mobibot.Utils.bold +import net.thauvin.erik.mobibot.Utils.helpFormat +import org.pircbotx.hooks.types.GenericMessageEvent + + +/** + * Simple module example in Kotlin. + */ +class RockPaperScissors : AbstractModule() { + override val name = "RockPaperScissors" + + init { + with(commands) { + add(Hands.ROCK.name.lowercase()) + add(Hands.PAPER.name.lowercase()) + add(Hands.SCISSORS.name.lowercase()) + } + + with(help) { + add("To play Rock Paper Scissors:") + add( + helpFormat( + "%c ${Hands.ROCK.name.lowercase()} | ${Hands.PAPER.name.lowercase()}" + + " | ${Hands.SCISSORS.name.lowercase()}" + ) + ) + } + } + + enum class Hands(val action: String) { + ROCK("crushes") { + override fun beats(hand: Hands): Boolean { + return hand == SCISSORS + } + }, + PAPER("covers") { + override fun beats(hand: Hands): Boolean { + return hand == ROCK + } + }, + SCISSORS("cuts") { + override fun beats(hand: Hands): Boolean { + return hand == PAPER + } + }; + + abstract fun beats(hand: Hands): Boolean + } + + companion object { + // For testing. + fun winLoseOrDraw(player: String, bot: String): String { + val hand = Hands.valueOf(player.uppercase()) + val botHand = Hands.valueOf(bot.uppercase()) + + return when { + hand == botHand -> "draw" + hand.beats(botHand) -> "win" + else -> "lose" + } + } + } + + override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { + val hand = Hands.valueOf(cmd.uppercase()) + val botHand = Hands.entries[(0..Hands.entries.size).random()] + when { + hand == botHand -> { + event.respond("${hand.name} vs. ${botHand.name} » You ${"tie".bold()}.") + } + + hand.beats(botHand) -> { + event.respond("${hand.name.bold()} ${hand.action} ${botHand.name} » You ${"win".bold()}!") + } + + else -> { + event.respond("${botHand.name.bold()} ${botHand.action} ${hand.name} » You ${"lose".bold()}!") + } + } + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/StockQuote.kt b/bin/main/net/thauvin/erik/mobibot/modules/StockQuote.kt new file mode 100644 index 0000000..dcae5e7 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/modules/StockQuote.kt @@ -0,0 +1,236 @@ +/* + * StockQuote.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.modules + +import net.thauvin.erik.mobibot.Utils.capitalise +import net.thauvin.erik.mobibot.Utils.encodeUrl +import net.thauvin.erik.mobibot.Utils.helpFormat +import net.thauvin.erik.mobibot.Utils.reader +import net.thauvin.erik.mobibot.Utils.sendMessage +import net.thauvin.erik.mobibot.Utils.unescapeXml +import net.thauvin.erik.mobibot.msg.ErrorMessage +import net.thauvin.erik.mobibot.msg.Message +import net.thauvin.erik.mobibot.msg.NoticeMessage +import net.thauvin.erik.mobibot.msg.PublicMessage +import org.json.JSONException +import org.json.JSONObject +import org.pircbotx.hooks.types.GenericMessageEvent +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import java.io.IOException +import java.net.URL + +/** + * The StockQuote module. + */ +class StockQuote : AbstractModule() { + private val logger: Logger = LoggerFactory.getLogger(StockQuote::class.java) + + override val name = "StockQuote" + + /** + * Returns the specified stock quote from Alpha Vantage. + */ + override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { + if (args.isNotBlank()) { + try { + val messages = getQuote(args, properties[API_KEY_PROP]) + for (msg in messages) { + event.sendMessage(channel, msg) + } + } catch (e: ModuleException) { + if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) + e.message?.let { + event.respond(it) + } + } + } else { + helpResponse(event) + } + } + + companion object { + /** + * The API property key. + */ + const val API_KEY_PROP = "alphavantage-api-key" + + /** + * The Invalid Symbol error string. + */ + const val INVALID_SYMBOL = "Invalid symbol." + + // API URL + private const val API_URL = "https://www.alphavantage.co/query?function=" + + // Quote command + private const val STOCK_CMD = "stock" + + @Throws(ModuleException::class) + private fun getJsonResponse(response: String, debugMessage: String): JSONObject { + return if (response.isNotBlank()) { + val json = JSONObject(response) + try { + val info = json.getString("Information") + if (info.isNotEmpty()) { + throw ModuleException(debugMessage, info.unescapeXml()) + } + } catch (ignore: JSONException) { + // Do nothing + } + try { + var error = json.getString("Note") + if (error.isNotEmpty()) { + throw ModuleException(debugMessage, error.unescapeXml()) + } + error = json.getString("Error Message") + if (error.isNotEmpty()) { + throw ModuleException(debugMessage, error.unescapeXml()) + } + } catch (ignore: JSONException) { + // Do nothing + } + json + } else { + throw ModuleException(debugMessage, "Empty Response.") + } + } + + /** + * Retrieves a stock quote. + */ + @JvmStatic + @Throws(ModuleException::class) + fun getQuote(symbol: String, apiKey: String?): List<Message> { + if (apiKey.isNullOrBlank()) { + throw ModuleException( + "${StockQuote::class.java.name} is disabled.", + "${STOCK_CMD.capitalise()} is disabled. The API key is missing." + ) + } + val messages = mutableListOf<Message>() + if (symbol.isNotBlank()) { + val debugMessage = "getQuote($symbol)" + var response: String + try { + with(messages) { + // Search for symbol/keywords + response = URL( + "${API_URL}SYMBOL_SEARCH&keywords=" + symbol.encodeUrl() + "&apikey=" + + apiKey.encodeUrl() + ).reader().body + var json = getJsonResponse(response, debugMessage) + val symbols = json.getJSONArray("bestMatches") + if (symbols.isEmpty) { + messages.add(ErrorMessage(INVALID_SYMBOL)) + } else { + val symbolInfo = symbols.getJSONObject(0) + + // Get quote for symbol + response = URL( + "${API_URL}GLOBAL_QUOTE&symbol=" + + symbolInfo.getString("1. symbol").encodeUrl() + "&apikey=" + + apiKey.encodeUrl() + ).reader().body + json = getJsonResponse(response, debugMessage) + val quote = json.getJSONObject("Global Quote") + if (quote.isEmpty) { + add(ErrorMessage(INVALID_SYMBOL)) + } else { + + add( + PublicMessage( + "Symbol: " + quote.getString("01. symbol").unescapeXml() + + " [" + symbolInfo.getString("2. name").unescapeXml() + ']' + ) + ) + + val pad = 10 + + add( + PublicMessage( + "Price:".padEnd(pad).prependIndent() + + quote.getString("05. price").unescapeXml() + ) + ) + add( + PublicMessage( + "Previous:".padEnd(pad).prependIndent() + + quote.getString("08. previous close").unescapeXml() + ) + ) + + val data = arrayOf( + "Open" to "02. open", + "High" to "03. high", + "Low" to "04. low", + "Volume" to "06. volume", + "Latest" to "07. latest trading day" + ) + + data.forEach { + add( + NoticeMessage( + "${it.first}:".padEnd(pad).prependIndent() + + quote.getString(it.second).unescapeXml() + ) + ) + } + + add( + NoticeMessage( + "Change:".padEnd(pad).prependIndent() + + quote.getString("09. change").unescapeXml() + + " [" + quote.getString("10. change percent").unescapeXml() + ']' + ) + ) + } + } + } + } catch (e: IOException) { + throw ModuleException("$debugMessage: IOE", "An IO error has occurred retrieving a stock quote.", e) + } catch (e: NullPointerException) { + throw ModuleException("$debugMessage: NPE", "An error has occurred retrieving a stock quote.", e) + } + } else { + messages.add(ErrorMessage(INVALID_SYMBOL)) + } + return messages + } + } + + init { + commands.add(STOCK_CMD) + help.add("To retrieve a stock quote:") + help.add(helpFormat("%c $STOCK_CMD <symbol|keywords>")) + initProperties(API_KEY_PROP) + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/War.class b/bin/main/net/thauvin/erik/mobibot/modules/War.class new file mode 100644 index 0000000000000000000000000000000000000000..6c36e541b639c5b04b624194b3b2df6b3d11ba55 GIT binary patch literal 2452 zcmeHJUvm>T5MMb??6`r@5CVjMYDuZxQXf#BNMXjcP07@D7&{5m;i02DE4IR&<VrfX zdE`?u)6T$qzXso<)79MtNOEL4Q<&*PAFN&Jw7b7u?N9QbfBpUv0Pe%LB`6SBliYfC z%;Kq#9@pZT7b#!(%Ay>`AvfL=rb|#HaAuE9nHMrS@;3cF9#{gi&Cd4s0|IBCcHVv* zSS{peoj|#@(dcgWTDW2EQM=LKa!S9^Yi)K3Tuv<v4`MCszBh0R?=v}65!%iT9yeNT zG$^*(%^wLYKg|tMdeZ3s-0ZdpEaf3M)l|}0ChZOjV_t?O0yDodjqbk_QrHJLt=4uh zNK*}Y3C<H(e49sGYo*I@krZBUOU;c6r+i2Q6-`9QtWc6pwDLn9nR~P{zcuDmL=&Yg z#fsLmiq>64>sdwX+g5~z224t2sn6+w(|>E-@Qu|hu-)Xuasp7RD5G|N!YlKbK!jD! z$1&#NB*(ro|K1NL=M-@}Rzo`Cw#On~tx>g`z@XSvG>VO-YRa`1Lr#@;^}}*<X%Vc6 zCtN$kH1(0zDD#))(C21?2h6K!%iW|$<qurq0R&xc3>)$G6kUHP2)+u3S=<^GhQ@Np zcZI|b*~LsOc0&Rl^E`z7KWkQj6}YqjXW=q|bJgQyax_`&V1m6k^10q(*!hliDq!Ib z)56WO#iAVxL*Pc|pIj}-^-|Uz$nt9Kcw_>X`mwYk;u~@*jKDw*$Do9R80UIN>5;d` zt*@Do#!Kjxe)M|E_Tn&HFT)K2zno0t0~UY4o+WVYDD*9C=|k`rk2EuZQBL`fmnCP# z)nOuZfVcN=-dL$;#&b<*yc`~^y8~T2itaJf$WzPpI}poolaS{p*Y3>~_&-5MAL%+E zP#LIL2mGOM%q!!~Qg@FP(se@ycnu0;@qT+GxMn&S@0Z{<fzyYd1_BFRVGKUct_=;` z27CeW&p-)QVHW04TSYyU<xI{)C0YL@n=inrWPTbJ(fSPP1^5)b;J*M^#_=4k+)d^H zl|NwRr=<%oVD(k9?+T7{xCh{KxQgRKqF3M=P@EC?4A*DiI_hrM8p`9|zR2;`&GGgn zT9<(=L*j=(6>8}FD_p%;%$%no-W?CZ&EmEc{MR|*w%-%(Dil}H5OJ?yj!qO(fi-r? U%)mD|7N8CuN`O1~b69Tu4Ue7BiU0rr literal 0 HcmV?d00001 diff --git a/bin/main/net/thauvin/erik/mobibot/modules/Weather2.kt b/bin/main/net/thauvin/erik/mobibot/modules/Weather2.kt new file mode 100644 index 0000000..80a06fa --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/modules/Weather2.kt @@ -0,0 +1,250 @@ +/* + * Weather2.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.modules + +import net.aksingh.owmjapis.api.APIException +import net.aksingh.owmjapis.core.OWM +import net.aksingh.owmjapis.core.OWM.Country +import net.aksingh.owmjapis.model.CurrentWeather +import net.thauvin.erik.mobibot.Utils.bold +import net.thauvin.erik.mobibot.Utils.capitalise +import net.thauvin.erik.mobibot.Utils.capitalizeWords +import net.thauvin.erik.mobibot.Utils.encodeUrl +import net.thauvin.erik.mobibot.Utils.helpFormat +import net.thauvin.erik.mobibot.Utils.sendMessage +import net.thauvin.erik.mobibot.msg.ErrorMessage +import net.thauvin.erik.mobibot.msg.Message +import net.thauvin.erik.mobibot.msg.NoticeMessage +import net.thauvin.erik.mobibot.msg.PublicMessage +import org.pircbotx.Colors +import org.pircbotx.hooks.types.GenericMessageEvent +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import kotlin.math.roundToInt + +/** + * The `Weather2` module. + */ +class Weather2 : AbstractModule() { + private val logger: Logger = LoggerFactory.getLogger(Weather2::class.java) + + override val name = "Weather" + + /** + * Fetches the weather data from a specific city. + */ + override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { + if (args.isNotBlank()) { + try { + val messages = getWeather(args, properties[API_KEY_PROP]) + if (messages[0].isError) { + helpResponse(event) + } else { + for (msg in messages) { + event.sendMessage(channel, msg) + } + } + } catch (e: ModuleException) { + if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) + e.message?.let { + event.respond(it) + } + } + } else { + helpResponse(event) + } + } + + companion object { + /** + * The OpenWeatherMap API Key property. + */ + const val API_KEY_PROP = "owm-api-key" + + // Weather command + private const val WEATHER_CMD = "weather" + + /** + * Converts and rounds temperature from °F to °C. + */ + fun ftoC(d: Double): Pair<Int, Int> { + val c = (d - 32) * 5 / 9 + return d.roundToInt() to c.roundToInt() + } + + /** + * Returns a country based on its country code. Defaults to [Country.UNITED_STATES] if not found. + */ + fun getCountry(countryCode: String): Country { + for (c in Country.entries) { + if (c.value.equals(countryCode, ignoreCase = true)) { + return c + } + } + return Country.UNITED_STATES + } + + /** + * Retrieves the weather data. + */ + @JvmStatic + @Throws(ModuleException::class) + fun getWeather(query: String, apiKey: String?): List<Message> { + if (apiKey.isNullOrBlank()) { + throw ModuleException( + "${Weather2::class.java.name} is disabled.", + "${WEATHER_CMD.capitalise()} is disabled. The API key is missing." + ) + } + val owm = OWM(apiKey) + val messages = mutableListOf<Message>() + owm.unit = OWM.Unit.IMPERIAL + if (query.isNotBlank()) { + val argv = query.split(",") + if (argv.size in 1..2) { + val city = argv[0].trim() + val code: String = if (argv.size > 1 && argv[1].isNotBlank()) { + argv[1].trim() + } else { + "US" + } + try { + val country = getCountry(code) + val cwd: CurrentWeather = if (city.matches("\\d+".toRegex())) { + owm.currentWeatherByZipCode(city.toInt(), country) + } else { + owm.currentWeatherByCityName(city, country) + } + if (cwd.hasCityName()) { + messages.add( + PublicMessage( + "City: ${cwd.cityName}, " + + country.name.replace('_', ' ').capitalizeWords() + " [${country.value}]" + ) + ) + cwd.mainData?.let { + with(it) { + if (hasTemp()) { + temp?.let { t -> + val (f, c) = ftoC(t) + messages.add(PublicMessage("Temperature: ${f}°F, ${c}°C")) + } + } + if (hasHumidity()) { + humidity?.let { h -> + messages.add(NoticeMessage("Humidity: ${h.roundToInt()}%")) + } + } + } + } + if (cwd.hasWindData()) { + cwd.windData?.let { + if (it.hasSpeed()) { + it.speed?.let { s -> + val w = mphToKmh(s) + messages.add(NoticeMessage("Wind: ${w.first} mph, ${w.second} km/h")) + } + } + } + } + if (cwd.hasWeatherList()) { + val condition = StringBuilder("Condition:") + cwd.weatherList?.let { + for (w in it) { + w?.let { + condition.append(' ') + .append(w.getDescription().capitalise()) + .append('.') + } + } + messages.add(NoticeMessage(condition.toString())) + } + } + if (cwd.hasCityId()) { + cwd.cityId?.let { + if (it > 0) { + messages.add( + NoticeMessage("https://openweathermap.org/city/$it", Colors.GREEN) + ) + } else { + messages.add( + NoticeMessage( + "https://openweathermap.org/find?q=" + + "$city,${code.uppercase()}".encodeUrl(), + Colors.GREEN + ) + ) + } + } + } + } + } catch (e: APIException) { + if (e.code == 404) { + throw ModuleException( + "getWeather($query): API ${e.code}", + "The requested city was not found.", + e + ) + } else { + throw ModuleException("getWeather($query): API ${e.code}", e.message, e) + } + } catch (e: NullPointerException) { + throw ModuleException("getWeather($query): NPE", "Unable to perform weather lookup.", e) + } + } + } + if (messages.isEmpty()) { + messages.add(ErrorMessage("Invalid syntax.")) + } + return messages + } + + /** + * Converts and rounds temperature from mph to km/h. + */ + fun mphToKmh(w: Double): Pair<Int, Int> { + val kmh = w * 1.60934 + return w.roundToInt() to kmh.roundToInt() + } + } + + init { + commands.add(WEATHER_CMD) + with(help) { + add("To display weather information:") + add(helpFormat("%c $WEATHER_CMD <city> [, <country code>]")) + add("For example:") + add(helpFormat("%c $WEATHER_CMD paris, fr")) + add("The default ISO 3166 country code is ${"US".bold()}. Zip codes supported in most countries.") + } + initProperties(API_KEY_PROP) + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/WolframAlpha.kt b/bin/main/net/thauvin/erik/mobibot/modules/WolframAlpha.kt new file mode 100644 index 0000000..a72efab --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/modules/WolframAlpha.kt @@ -0,0 +1,142 @@ +/* + * WolframAlpha.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.modules + +import net.thauvin.erik.mobibot.Utils +import net.thauvin.erik.mobibot.Utils.encodeUrl +import net.thauvin.erik.mobibot.Utils.isHttpSuccess +import net.thauvin.erik.mobibot.Utils.reader +import net.thauvin.erik.mobibot.Utils.sendMessage +import org.pircbotx.hooks.types.GenericMessageEvent +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import java.io.IOException +import java.net.URL + +class WolframAlpha : AbstractModule() { + private val logger: Logger = LoggerFactory.getLogger(WolframAlpha::class.java) + + override val name = "WolframAlpha" + + private fun getUnits(unit: String?): String { + return if (unit?.lowercase() == METRIC) { + METRIC + } else { + IMPERIAL + } + } + + override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { + if (args.isNotBlank()) { + try { + val query = args.trim().split("units=", limit = 2, ignoreCase = true) + event.sendMessage( + queryWolfram( + query[0].trim(), + units = if (query.size == 2) { + getUnits(query[1].trim()) + } else { + getUnits(properties[UNITS_PROP]) + }, + appId = properties[APPID_KEY_PROP] + ) + ) + } catch (e: ModuleException) { + if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) + e.message?.let { + event.respond(it) + } + } + } else { + helpResponse(event) + } + } + + companion object { + /** + * The Wolfram Alpha API Key property. + */ + const val APPID_KEY_PROP = "wolfram-appid" + + /** + * The Wolfram units properties + */ + const val UNITS_PROP = "wolfram-units" + + const val METRIC = "metric" + const val IMPERIAL = "imperial" + + // Wolfram command + private const val WOLFRAM_CMD = "wolfram" + + // Wolfram Alpha API URL + private const val API_URL = "http://api.wolframalpha.com/v1/spoken?appid=" + + @JvmStatic + @Throws(ModuleException::class) + fun queryWolfram(query: String, units: String = IMPERIAL, appId: String?): String { + if (!appId.isNullOrEmpty()) { + try { + val urlReader = URL("${API_URL}${appId}&units=${units}&i=" + query.encodeUrl()).reader() + if (urlReader.responseCode.isHttpSuccess()) { + return urlReader.body + } else { + throw ModuleException( + "wolfram($query): ${urlReader.responseCode} : ${urlReader.body} ", + urlReader.body.ifEmpty { + "Looks like Wolfram Alpha isn't able to answer that. (${urlReader.responseCode})" + } + ) + } + } catch (ioe: IOException) { + throw ModuleException( + "wolfram($query): IOE", "An IO Error occurred while querying Wolfram Alpha.", ioe + ) + } + } else { + throw ModuleException("wolfram($query): No API Key", "No Wolfram Alpha API key specified.") + } + } + } + + init { + commands.add(WOLFRAM_CMD) + with(help) { + add("To get answers from Wolfram Alpha:") + add(Utils.helpFormat("%c $WOLFRAM_CMD <query> [units=(${METRIC}|${IMPERIAL})]")) + add("For example:") + add(Utils.helpFormat("%c $WOLFRAM_CMD days until christmas")) + add(Utils.helpFormat("%c $WOLFRAM_CMD distance earth moon units=metric")) + } + initProperties(APPID_KEY_PROP, UNITS_PROP) + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/WorldTime.kt b/bin/main/net/thauvin/erik/mobibot/modules/WorldTime.kt new file mode 100644 index 0000000..18072bc --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/modules/WorldTime.kt @@ -0,0 +1,390 @@ +/* + * WorldTime.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.modules + +import net.thauvin.erik.mobibot.Utils.bold +import net.thauvin.erik.mobibot.Utils.helpFormat +import net.thauvin.erik.mobibot.Utils.sendList +import net.thauvin.erik.mobibot.Utils.sendMessage +import org.pircbotx.hooks.types.GenericMessageEvent +import java.time.ZoneId +import java.time.ZonedDateTime +import java.time.format.DateTimeFormatter +import java.time.temporal.ChronoField + +/** + * The WorldTime module. + */ +class WorldTime : AbstractModule() { + override val name = "WorldTime" + + companion object { + /** + * Beats (Internet Time) keyword + */ + const val BEATS_KEYWORD = ".beats" + + /** + * Supported countries + */ + val COUNTRIES_MAP = buildMap<String, String> { + put("AG", "America/Antigua") + put("AI", "America/Anguilla") + put("AE", "Asia/Dubai") + put("AD", "Europe/Andorra") + put("AKDT", "America/Anchorage") + put("AF", "Asia/Kabul") + put("AKST", "America/Anchorage") + put("AL", "Europe/Tirane") + put("AM", "Asia/Yerevan") + put("AO", "Africa/Luanda") + put("AQ", "Antarctica/South_Pole") + put("AR", "America/Argentina/Buenos_Aires") + put("AS", "Pacific/Pago_Pago") + put("AT", "Europe/Vienna") + put("AU", "Australia/Sydney") + put("AW", "America/Aruba") + put("AX", "Europe/Mariehamn") + put("AZ", "Asia/Baku") + put("BA", "Europe/Sarajevo") + put("BB", "America/Barbados") + put("BD", "Asia/Dhaka") + put("BE", "Europe/Brussels") + put("BEAT", BEATS_KEYWORD) + put("BF", "Africa/Ouagadougou") + put("BG", "Europe/Sofia") + put("BH", "Asia/Bahrain") + put("BI", "Africa/Bujumbura") + put("BJ", "Africa/Porto-Novo") + put("BL", "America/St_Barthelemy") + put("BM", "Atlantic/Bermuda") + put("BMT", BEATS_KEYWORD) + put("BN", "Asia/Brunei") + put("BO", "America/La_Paz") + put("BQ", "America/Kralendijk") + put("BR", "America/Sao_Paulo") + put("BS", "America/Nassau") + put("BT", "Asia/Thimphu") + put("BW", "Africa/Gaborone") + put("BY", "Europe/Minsk") + put("BZ", "America/Belize") + put("CA", "America/Montreal") + put("CC", "Indian/Cocos") + put("CD", "Africa/Kinshasa") + put("CDT", "America/Chicago") + put("CET", "CET") + put("CF", "Africa/Bangui") + put("CG", "Africa/Brazzaville") + put("CH", "Europe/Zurich") + put("CI", "Africa/Abidjan") + put("CK", "Pacific/Rarotonga") + put("CL", "America/Santiago") + put("CM", "Africa/Douala") + put("CN", "Asia/Shanghai") + put("CO", "America/Bogota") + put("CR", "America/Costa_Rica") + put("CST", "America/Chicago") + put("CU", "Cuba") + put("CV", "Atlantic/Cape_Verde") + put("CW", "America/Curacao") + put("CX", "Indian/Christmas") + put("CY", "Asia/Nicosia") + put("CZ", "Europe/Prague") + put("DE", "Europe/Berlin") + put("DJ", "Africa/Djibouti") + put("DK", "Europe/Copenhagen") + put("DM", "America/Dominica") + put("DO", "America/Santo_Domingo") + put("DZ", "Africa/Algiers") + put("EC", "Pacific/Galapagos") + put("EDT", "America/New_York") + put("EE", "Europe/Tallinn") + put("EG", "Africa/Cairo") + put("EH", "Africa/El_Aaiun") + put("ER", "Africa/Asmara") + put("ES", "Europe/Madrid") + put("EST", "America/New_York") + put("ET", "Africa/Addis_Ababa") + put("FI", "Europe/Helsinki") + put("FJ", "Pacific/Fiji") + put("FK", "Atlantic/Stanley") + put("FM", "Pacific/Yap") + put("FO", "Atlantic/Faroe") + put("FR", "Europe/Paris") + put("GA", "Africa/Libreville") + put("GB", "Europe/London") + put("GD", "America/Grenada") + put("GE", "Asia/Tbilisi") + put("GF", "America/Cayenne") + put("GG", "Europe/Guernsey") + put("GH", "Africa/Accra") + put("GI", "Europe/Gibraltar") + put("GL", "America/Thule") + put("GM", "Africa/Banjul") + put("GMT", "GMT") + put("GN", "Africa/Conakry") + put("GP", "America/Guadeloupe") + put("GQ", "Africa/Malabo") + put("GR", "Europe/Athens") + put("GS", "Atlantic/South_Georgia") + put("GT", "America/Guatemala") + put("GU", "Pacific/Guam") + put("GW", "Africa/Bissau") + put("GY", "America/Guyana") + put("HK", "Asia/Hong_Kong") + put("HN", "America/Tegucigalpa") + put("HR", "Europe/Zagreb") + put("HST", "Pacific/Honolulu") + put("HT", "America/Port-au-Prince") + put("HU", "Europe/Budapest") + put("ID", "Asia/Jakarta") + put("IE", "Europe/Dublin") + put("IL", "Asia/Tel_Aviv") + put("IM", "Europe/Isle_of_Man") + put("IN", "Asia/Kolkata") + put("IO", "Indian/Chagos") + put("IQ", "Asia/Baghdad") + put("IR", "Asia/Tehran") + put("IS", "Atlantic/Reykjavik") + put("IT", "Europe/Rome") + put("JE", "Europe/Jersey") + put("JM", "Jamaica") + put("JO", "Asia/Amman") + put("JP", "Asia/Tokyo") + put("KE", "Africa/Nairobi") + put("KG", "Asia/Bishkek") + put("KH", "Asia/Phnom_Penh") + put("KI", "Pacific/Tarawa") + put("KM", "Indian/Comoro") + put("KN", "America/St_Kitts") + put("KP", "Asia/Pyongyang") + put("KR", "Asia/Seoul") + put("KW", "Asia/Riyadh") + put("KY", "America/Cayman") + put("KZ", "Asia/Oral") + put("LA", "Asia/Vientiane") + put("LB", "Asia/Beirut") + put("LC", "America/St_Lucia") + put("LI", "Europe/Vaduz") + put("LK", "Asia/Colombo") + put("LR", "Africa/Monrovia") + put("LS", "Africa/Maseru") + put("LT", "Europe/Vilnius") + put("LU", "Europe/Luxembourg") + put("LV", "Europe/Riga") + put("LY", "Africa/Tripoli") + put("MA", "Africa/Casablanca") + put("MC", "Europe/Monaco") + put("MD", "Europe/Chisinau") + put("MDT", "America/Denver") + put("ME", "Europe/Podgorica") + put("MF", "America/Marigot") + put("MG", "Indian/Antananarivo") + put("MH", "Pacific/Majuro") + put("MK", "Europe/Skopje") + put("ML", "Africa/Timbuktu") + put("MM", "Asia/Yangon") + put("MN", "Asia/Ulaanbaatar") + put("MO", "Asia/Macau") + put("MP", "Pacific/Saipan") + put("MQ", "America/Martinique") + put("MR", "Africa/Nouakchott") + put("MS", "America/Montserrat") + put("MST", "America/Denver") + put("MT", "Europe/Malta") + put("MU", "Indian/Mauritius") + put("MV", "Indian/Maldives") + put("MW", "Africa/Blantyre") + put("MX", "America/Mexico_City") + put("MY", "Asia/Kuala_Lumpur") + put("MZ", "Africa/Maputo") + put("NA", "Africa/Windhoek") + put("NC", "Pacific/Noumea") + put("NE", "Africa/Niamey") + put("NF", "Pacific/Norfolk") + put("NG", "Africa/Lagos") + put("NI", "America/Managua") + put("NL", "Europe/Amsterdam") + put("NO", "Europe/Oslo") + put("NP", "Asia/Kathmandu") + put("NR", "Pacific/Nauru") + put("NU", "Pacific/Niue") + put("NZ", "Pacific/Auckland") + put("OM", "Asia/Muscat") + put("PA", "America/Panama") + put("PDT", "America/Los_Angeles") + put("PE", "America/Lima") + put("PF", "Pacific/Tahiti") + put("PG", "Pacific/Port_Moresby") + put("PH", "Asia/Manila") + put("PK", "Asia/Karachi") + put("PL", "Europe/Warsaw") + put("PM", "America/Miquelon") + put("PN", "Pacific/Pitcairn") + put("PR", "America/Puerto_Rico") + put("PS", "Asia/Gaza") + put("PST", "America/Los_Angeles") + put("PT", "Europe/Lisbon") + put("PW", "Pacific/Palau") + put("PY", "America/Asuncion") + put("QA", "Asia/Qatar") + put("RE", "Indian/Reunion") + put("RO", "Europe/Bucharest") + put("RS", "Europe/Belgrade") + put("RU", "Europe/Moscow") + put("RW", "Africa/Kigali") + put("SA", "Asia/Riyadh") + put("SB", "Pacific/Guadalcanal") + put("SC", "Indian/Mahe") + put("SD", "Africa/Khartoum") + put("SE", "Europe/Stockholm") + put("SG", "Asia/Singapore") + put("SH", "Atlantic/St_Helena") + put("SI", "Europe/Ljubljana") + put("SJ", "Atlantic/Jan_Mayen") + put("SK", "Europe/Bratislava") + put("SL", "Africa/Freetown") + put("SM", "Europe/San_Marino") + put("SN", "Africa/Dakar") + put("SO", "Africa/Mogadishu") + put("SR", "America/Paramaribo") + put("SS", "Africa/Juba") + put("ST", "Africa/Sao_Tome") + put("SV", "America/El_Salvador") + put("SX", "America/Lower_Princes") + put("SY", "Asia/Damascus") + put("SZ", "Africa/Mbabane") + put("TC", "America/Grand_Turk") + put("TD", "Africa/Ndjamena") + put("TF", "Indian/Kerguelen") + put("TG", "Africa/Lome") + put("TH", "Asia/Bangkok") + put("TJ", "Asia/Dushanbe") + put("TK", "Pacific/Fakaofo") + put("TL", "Asia/Dili") + put("TM", "Asia/Ashgabat") + put("TN", "Africa/Tunis") + put("TO", "Pacific/Tongatapu") + put("TR", "Europe/Istanbul") + put("TT", "America/Port_of_Spain") + put("TV", "Pacific/Funafuti") + put("TW", "Asia/Taipei") + put("TZ", "Africa/Dar_es_Salaam") + put("UA", "Europe/Kiev") + put("UG", "Africa/Kampala") + put("UK", "Europe/London") + put("UM", "Pacific/Wake") + put("US", "America/New_York") + put("UTC", "UTC") + put("UY", "America/Montevideo") + put("UZ", "Asia/Tashkent") + put("VA", "Europe/Vatican") + put("VC", "America/St_Vincent") + put("VE", "America/Caracas") + put("VG", "America/Tortola") + put("VI", "America/St_Thomas") + put("VN", "Asia/Ho_Chi_Minh") + put("VU", "Pacific/Efate") + put("WF", "Pacific/Wallis") + put("WS", "Pacific/Apia") + put("YE", "Asia/Aden") + put("YT", "Indian/Mayotte") + put("ZA", "Africa/Johannesburg") + put("ZM", "Africa/Lusaka") + put("ZULU", "Zulu") + put("ZW", "Africa/Harare") + ZoneId.getAvailableZoneIds().filter { it.length <= 3 && !containsKey(it) } + .forEach { tz -> put(tz, tz) } + } + + // The Time command + private const val TIME_CMD = "time" + + // The zones arguments + private const val ZONES_ARGS = "zones" + + // The default zone + private const val DEFAULT_ZONE = "PST" + + // Date/Time Format + private var dtf = + DateTimeFormatter.ofPattern("'The time is ${"'HH:mm'".bold()} on ${"'EEEE, d MMMM yyyy'".bold()} in '") + + /** + * Returns the current Internet (beat) Time. + */ + private fun internetTime(): String { + val zdt = ZonedDateTime.now(ZoneId.of("UTC+01:00")) + val beats = ((zdt[ChronoField.SECOND_OF_MINUTE] + zdt[ChronoField.MINUTE_OF_HOUR] * 60 + + zdt[ChronoField.HOUR_OF_DAY] * 3600) / 86.4).toInt() + return "%c%03d".format('@', beats) + } + + /** + * Returns the time for the given timezone/city. + */ + @JvmStatic + fun time(query: String = DEFAULT_ZONE): String { + val tz = COUNTRIES_MAP[(if (query.isNotBlank()) query.trim().uppercase() else DEFAULT_ZONE)] + return if (tz != null) { + if (BEATS_KEYWORD == tz) { + "The current Internet Time is ${internetTime().bold()} $BEATS_KEYWORD" + } else { + (ZonedDateTime.now().withZoneSameInstant(ZoneId.of(tz)).format(dtf) + + tz.substring(tz.lastIndexOf('/') + 1).replace('_', ' ').bold()) + } + } else { + "Unsupported country/zone. Please try again." + } + } + } + + override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { + if (args.equals(ZONES_ARGS, true)) { + event.sendMessage("The supported countries/zones are: ") + event.sendList(COUNTRIES_MAP.keys.sorted().map { it.padEnd(4) }, 14, isIndent = true) + } else { + event.respond(time(args)) + } + } + + override val isPrivateMsgEnabled = true + + init { + with(help) { + add("To display a country's current date/time:") + add(helpFormat("%c $TIME_CMD [<country code or zone>]")) + add("For a listing of the supported countries/zones:") + add(helpFormat("%c $TIME_CMD $ZONES_ARGS")) + } + commands.add(TIME_CMD) + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/msg/ErrorMessage.kt b/bin/main/net/thauvin/erik/mobibot/msg/ErrorMessage.kt new file mode 100644 index 0000000..0607936 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/msg/ErrorMessage.kt @@ -0,0 +1,37 @@ +/* + * ErrorMessage.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.msg + +/** + * The `ErrorMessage` class. + */ +class ErrorMessage @JvmOverloads constructor(msg: String, color: String = DEFAULT_COLOR) : + Message(msg, color, isError = true) diff --git a/bin/main/net/thauvin/erik/mobibot/msg/Message.kt b/bin/main/net/thauvin/erik/mobibot/msg/Message.kt new file mode 100644 index 0000000..23a33b9 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/msg/Message.kt @@ -0,0 +1,65 @@ +/* + * Message.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.msg + +import net.thauvin.erik.semver.Constants + +/** + * The `Message` class. + */ +open class Message @JvmOverloads constructor( + var msg: String, + var color: String = DEFAULT_COLOR, + var isNotice: Boolean = false, + isError: Boolean = false, + var isPrivate: Boolean = false +) { + companion object { + var DEFAULT_COLOR = Constants.EMPTY + } + + init { + if (isError) { + isNotice = true + } + } + + /** Error flag. */ + var isError = isError + set(value) { + if (value) isNotice = true + field = value + } + + override fun toString(): String { + return "Message(color='$color', isError=$isError, isNotice=$isNotice, isPrivate=$isPrivate, msg='$msg')" + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/msg/NoticeMessage.kt b/bin/main/net/thauvin/erik/mobibot/msg/NoticeMessage.kt new file mode 100644 index 0000000..037d504 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/msg/NoticeMessage.kt @@ -0,0 +1,38 @@ +/* + * NoticeMessage.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.msg + +/** + * The `NoticeMessage` class. + */ +class NoticeMessage @JvmOverloads constructor(msg: String, color: String = DEFAULT_COLOR) : + Message(msg, color, isNotice = true) + diff --git a/bin/main/net/thauvin/erik/mobibot/msg/PrivateMessage.kt b/bin/main/net/thauvin/erik/mobibot/msg/PrivateMessage.kt new file mode 100644 index 0000000..b424fdf --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/msg/PrivateMessage.kt @@ -0,0 +1,37 @@ +/* + * PrivateMessage.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.msg + +/** + * The `PrivateMessage` class. + */ +class PrivateMessage @JvmOverloads constructor(msg: String, color: String = DEFAULT_COLOR) : + Message(msg, color, isPrivate = true) diff --git a/bin/main/net/thauvin/erik/mobibot/msg/PublicMessage.kt b/bin/main/net/thauvin/erik/mobibot/msg/PublicMessage.kt new file mode 100644 index 0000000..9c5e088 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/msg/PublicMessage.kt @@ -0,0 +1,36 @@ +/* + * PublicMessage.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.msg + +/** + * The `PublicMessage` class. + */ +class PublicMessage @JvmOverloads constructor(msg: String, color: String = DEFAULT_COLOR) : Message(msg, color) diff --git a/bin/main/net/thauvin/erik/mobibot/social/SocialManager.kt b/bin/main/net/thauvin/erik/mobibot/social/SocialManager.kt new file mode 100644 index 0000000..91f2dd9 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/social/SocialManager.kt @@ -0,0 +1,116 @@ +/* + * SocialManager.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.social + +import net.thauvin.erik.mobibot.Addons +import net.thauvin.erik.mobibot.Constants +import net.thauvin.erik.mobibot.entries.EntriesUtils.toLinkLabel +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import java.util.* + +/** + * Social Manager. + */ +class SocialManager { + private val entries: MutableSet<Int> = HashSet() + private val logger: Logger = LoggerFactory.getLogger(SocialManager::class.java) + private val modules = ArrayList<SocialModule>() + private val timer = Timer(true) + + /** + * Adds social modules. + */ + fun add(addons: Addons, vararg modules: SocialModule) { + modules.forEach { + if (addons.add(it)) { + this.modules.add(it) + } + } + } + + /** + * Returns the number of entries. + */ + fun entriesCount(): Int = entries.size + + /** + * Sends a social notification (dm, etc.) + */ + fun notification(msg: String) { + modules.forEach { + it.notification(msg) + } + } + + /** + * Posts to social media. + */ + fun postEntry(index: Int) { + if (entries.contains(index)) { + modules.forEach { + it.postEntry(index) + } + entries.remove(index) + } + } + + /** + * Queues an entry for posting to social media. + */ + fun queueEntry(index: Int) { + if (modules.isNotEmpty()) { + entries.add(index) + if (logger.isDebugEnabled) { + logger.debug("Scheduling {} for posting on social media.", index.toLinkLabel()) + } + timer.schedule(SocialTimer(this, index), Constants.TIMER_DELAY * 60L * 1000L) + } + } + + /** + * Removes entries from queue. + */ + fun removeEntry(index: Int) { + entries.remove(index) + } + + /** + * Posts all entries on shutdown. + */ + fun shutdown() { + timer.cancel() + entries.forEach { + postEntry(it) + } + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/social/SocialModule.kt b/bin/main/net/thauvin/erik/mobibot/social/SocialModule.kt new file mode 100644 index 0000000..b594670 --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/social/SocialModule.kt @@ -0,0 +1,96 @@ +/* + * SocialModule.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.social + +import net.thauvin.erik.mobibot.commands.links.LinksManager +import net.thauvin.erik.mobibot.entries.EntriesUtils.toLinkLabel +import net.thauvin.erik.mobibot.entries.EntryLink +import net.thauvin.erik.mobibot.modules.AbstractModule +import net.thauvin.erik.mobibot.modules.ModuleException +import org.pircbotx.hooks.types.GenericMessageEvent +import org.slf4j.Logger +import org.slf4j.LoggerFactory + +abstract class SocialModule : AbstractModule() { + private val logger: Logger = LoggerFactory.getLogger(SocialManager::class.java) + + abstract val handle: String? + abstract val isAutoPost: Boolean + + abstract fun formatEntry(entry: EntryLink): String + + /** + * Sends a DM. + */ + fun notification(msg: String) { + if (isEnabled && !handle.isNullOrBlank()) { + try { + post(message = msg, isDm = true) + if (logger.isDebugEnabled) logger.debug("Notified $handle on $name: $msg") + } catch (e: ModuleException) { + if (logger.isWarnEnabled) logger.warn("Failed to notify $handle on $name: $msg", e) + } + } + } + + abstract fun post(message: String, isDm: Boolean): String + + /** + * Post entry to social media. + */ + fun postEntry(index: Int) { + if (isAutoPost && LinksManager.entries.links.size >= index) { + try { + if (logger.isDebugEnabled) { + logger.debug("Posting {} to $name.", index.toLinkLabel()) + } + post(message = formatEntry(LinksManager.entries.links[index]), isDm = false) + } catch (e: ModuleException) { + if (logger.isWarnEnabled) logger.warn( + "Failed to post entry ${index.toLinkLabel()} on $name.", + e + ) + } + } + } + + override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { + try { + event.respond(post("$args (by ${event.user.nick} on $channel)", false)) + } catch (e: ModuleException) { + if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) + e.message?.let { + event.respond(it) + } + } + } +} diff --git a/bin/main/net/thauvin/erik/mobibot/social/SocialTimer.kt b/bin/main/net/thauvin/erik/mobibot/social/SocialTimer.kt new file mode 100644 index 0000000..3fd315e --- /dev/null +++ b/bin/main/net/thauvin/erik/mobibot/social/SocialTimer.kt @@ -0,0 +1,40 @@ +/* + * SocialTimer.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.social + +import java.util.* + +class SocialTimer(private var socialManager: SocialManager, private var index: Int) : TimerTask() { + override fun run() { + socialManager.postEntry(index) + } +} diff --git a/bin/test/current.xml b/bin/test/current.xml new file mode 100644 index 0000000..535a400 --- /dev/null +++ b/bin/test/current.xml @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ current.xml + ~ + ~ Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + ~ + ~ Redistribution and use in source and binary forms, with or without + ~ modification, are permitted provided that the following conditions are met: + ~ + ~ Redistributions of source code must retain the above copyright notice, this + ~ list of conditions and the following disclaimer. + ~ + ~ Redistributions in binary form must reproduce the above copyright notice, + ~ this list of conditions and the following disclaimer in the documentation + ~ and/or other materials provided with the distribution. + ~ + ~ Neither the name of this project nor the names of its contributors may be + ~ used to endorse or promote products derived from this software without + ~ specific prior written permission. + ~ + ~ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + ~ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + ~ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + ~ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + ~ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + ~ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + ~ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + ~ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + ~ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + ~ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + --> + +<rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"> + <channel> + <title>#mobibot IRC Links + https://www.mobitopia.org/mobibot/logs + Links from irc.example.com on #mobibot + en + Sun, 31 Oct 2021 21:45:11 GMT + 2021-10-31T21:45:11Z + en + + Example 2 + https://www.example.com/2 + Posted by <b>Skynx</b> on <a href="irc://irc.libera.chat/#mobibot"><b>#mobibot</b></a> + tag2-1 + tag2-2 + Sun, 31 Oct 2021 21:45:11 GMT + https://www.foo.com + mobibot@irc.libera.chat (Skynx) + 2021-10-31T00:01:00Z + + + Example 1 + https://www.example.com/1 + Posted by <b>ErikT</b> on <a href="irc://irc.libera.chat/#mobibot"><b>#mobibot</b></a> + <br/><br/>ErikT: This is comment 1. <br/>Skynx: This is comment 2. + + tag1-1 + tag1-2 + Sun, 31 Oct 2021 21:43:15 GMT + https://www.example.com/ + mobibot@irc.libera.chat (ErikT) + 2021-10-31T00:00:00Z + + + diff --git a/bin/test/net/thauvin/erik/mobibot/AddonsTest.kt b/bin/test/net/thauvin/erik/mobibot/AddonsTest.kt new file mode 100644 index 0000000..afb8ce6 --- /dev/null +++ b/bin/test/net/thauvin/erik/mobibot/AddonsTest.kt @@ -0,0 +1,86 @@ +/* + * AddonsTest.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot + +import assertk.assertThat +import assertk.assertions.containsExactly +import assertk.assertions.isEqualTo +import assertk.assertions.size +import net.thauvin.erik.mobibot.commands.ChannelFeed +import net.thauvin.erik.mobibot.commands.Cycle +import net.thauvin.erik.mobibot.commands.Die +import net.thauvin.erik.mobibot.commands.Ignore +import net.thauvin.erik.mobibot.commands.links.Comment +import net.thauvin.erik.mobibot.commands.links.View +import net.thauvin.erik.mobibot.modules.* +import kotlin.test.Test +import java.util.* + +class AddonsTest { + private val p = Properties().apply { + put("disabled-modules", "war,dice Lookup") + put("disabled-commands", "View | comment") + } + private val addons = Addons(p) + + @Test + fun addTest() { + // Modules + addons.add(Joke()) + addons.add(RockPaperScissors()) + addons.add(War()) + addons.add(Dice()) + addons.add(Lookup()) + assertThat(addons::modules).size().isEqualTo(2) + assertThat(addons.names.modules, "names.modules").containsExactly("Joke", "RockPaperScissors") + + // Commands + addons.add(View()) + addons.add(Comment()) + addons.add(Cycle()) + addons.add(Die()) // invisible + addons.add(ChannelFeed("channel")) // no properties, disabled + p[Ignore.IGNORE_PROP] = "nick" + addons.add(Ignore()) + assertThat(addons::commands).size().isEqualTo(3) + + assertThat(addons.names.ops, "names.ops").containsExactly("cycle") + + assertThat(addons.names.commands, "names.command").containsExactly( + "joke", + "rock", + "paper", + "scissors", + "ignore" + ) + } +} diff --git a/bin/test/net/thauvin/erik/mobibot/ExceptionSanitizer.kt b/bin/test/net/thauvin/erik/mobibot/ExceptionSanitizer.kt new file mode 100644 index 0000000..a3994ec --- /dev/null +++ b/bin/test/net/thauvin/erik/mobibot/ExceptionSanitizer.kt @@ -0,0 +1,60 @@ +/* + * ExceptionSanitizer.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot + +import net.thauvin.erik.mobibot.Utils.obfuscate +import net.thauvin.erik.mobibot.Utils.replaceEach +import net.thauvin.erik.mobibot.modules.ModuleException + +object ExceptionSanitizer { + /** + * Returns a sanitized exception to avoid displaying api keys, etc. in CI logs. + */ + fun ModuleException.sanitize(vararg sanitize: String): ModuleException { + val search = sanitize.filter { it.isNotBlank() }.toTypedArray() + if (search.isNotEmpty()) { + val obfuscate = search.map { it.obfuscate() }.toTypedArray() + with(this) { + if (!cause?.message.isNullOrBlank()) { + return ModuleException( + debugMessage, + cause?.javaClass?.name + ": " + cause?.message?.replaceEach(search, obfuscate), + this + ) + } else if (!message.isNullOrBlank()) { + return ModuleException(debugMessage, message?.replaceEach(search, obfuscate), this) + } + } + } + return this + } +} diff --git a/bin/test/net/thauvin/erik/mobibot/FeedReaderTest.kt b/bin/test/net/thauvin/erik/mobibot/FeedReaderTest.kt new file mode 100644 index 0000000..6e5fa8f --- /dev/null +++ b/bin/test/net/thauvin/erik/mobibot/FeedReaderTest.kt @@ -0,0 +1,78 @@ +/* + * FeedReaderTest.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot + +import assertk.all +import assertk.assertFailure +import assertk.assertThat +import assertk.assertions.* +import com.rometools.rome.io.FeedException +import net.thauvin.erik.mobibot.FeedReader.Companion.readFeed +import net.thauvin.erik.mobibot.msg.Message +import kotlin.test.Test +import java.io.IOException +import java.net.MalformedURLException +import java.net.UnknownHostException + +/** + * The `FeedReader Test` class. + */ +class FeedReaderTest { + @Test + fun readFeedTest() { + var messages = readFeed("https://feeds.thauvin.net/ethauvin") + assertThat(messages, "messages").all { + size().isEqualTo(10) + index(1).prop(Message::msg).contains("erik.thauvin.net") + } + + messages = readFeed("https://lorem-rss.herokuapp.com/feed?length=0") + assertThat(messages, "messages").index(0).prop(Message::msg).contains("nothing") + + messages = readFeed("https://lorem-rss.herokuapp.com/feed?length=84", 42) + assertThat(messages, "messages").size().isEqualTo(84) + messages.forEachIndexed { i, m -> + if (i % 2 == 0) { + assertThat(m, "messages($i)").prop(Message::msg).startsWith("Lorem ipsum") + } else { + assertThat(m, "messages($i)").prop(Message::msg).contains("http://example.com/test/") + } + } + + assertFailure { readFeed("blah") }.isInstanceOf(MalformedURLException::class.java) + + assertFailure { readFeed("https://www.example.com") }.isInstanceOf(FeedException::class.java) + + assertFailure { readFeed("https://www.thauvin.net/foo") }.isInstanceOf(IOException::class.java) + + assertFailure { readFeed("https://www.examplesfoo.com/") }.isInstanceOf(UnknownHostException::class.java) + } +} diff --git a/bin/test/net/thauvin/erik/mobibot/LocalProperties.kt b/bin/test/net/thauvin/erik/mobibot/LocalProperties.kt new file mode 100644 index 0000000..1384a72 --- /dev/null +++ b/bin/test/net/thauvin/erik/mobibot/LocalProperties.kt @@ -0,0 +1,85 @@ +/* + * LocalProperties.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot + +import org.testng.annotations.BeforeSuite +import java.io.IOException +import java.net.InetAddress +import java.net.UnknownHostException +import java.nio.file.Files +import java.nio.file.Paths +import java.util.* + +/** + * Access to `local.properties`. + */ +open class LocalProperties { + @BeforeSuite(alwaysRun = true) + fun loadProperties() { + val localPath = Paths.get("local.properties") + if (Files.exists(localPath)) { + try { + Files.newInputStream(localPath).use { stream -> localProps.load(stream) } + } catch (ignore: IOException) { + // Do nothing + } + } + } + + companion object { + private val localProps = Properties() + + fun getHostName(): String { + val ciName = System.getenv("CI_NAME") + return ciName ?: try { + InetAddress.getLocalHost().hostName + } catch (ignore: UnknownHostException) { + "Unknown Host" + } + } + + fun getProperty(key: String): String { + return if (localProps.containsKey(key)) { + localProps.getProperty(key) + } else { + val env = System.getenv(keyToEnv(key)) + env?.let { + localProps.setProperty(key, env) + } + env + } + } + + private fun keyToEnv(key: String): String { + return key.replace('-', '_').uppercase() + } + } +} diff --git a/bin/test/net/thauvin/erik/mobibot/PinboardTest.kt b/bin/test/net/thauvin/erik/mobibot/PinboardTest.kt new file mode 100644 index 0000000..b527fc5 --- /dev/null +++ b/bin/test/net/thauvin/erik/mobibot/PinboardTest.kt @@ -0,0 +1,81 @@ +/* + * PinboardTest.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot + +import net.thauvin.erik.mobibot.Utils.encodeUrl +import net.thauvin.erik.mobibot.Utils.reader +import net.thauvin.erik.mobibot.entries.EntryLink +import org.testng.Assert.assertFalse +import org.testng.Assert.assertTrue +import kotlin.test.Test +import java.net.URL + +class PinboardTest : LocalProperties() { + private val pinboard = Pinboard() + + @Test + fun testPinboard() { + val apiToken = getProperty("pinboard-api-token") + val url = "https://www.example.com/${(1000..5000).random()}" + val ircServer = "irc.test.com" + val entry = EntryLink(url, "Test Example", "ErikT", "", "#mobitopia", listOf("test")) + + pinboard.setApiToken(apiToken) + + pinboard.addPin(ircServer, entry) + assertTrue(validatePin(apiToken, url = entry.link, entry.title, entry.nick, entry.channel), "addPin") + + entry.link = "https://www.example.com/${(5001..9999).random()}" + pinboard.updatePin(ircServer, url, entry) + assertTrue(validatePin(apiToken, url = entry.link, ircServer), "updatePin") + + entry.title = "Foo Title" + pinboard.updatePin(ircServer, entry.link, entry) + assertTrue(validatePin(apiToken, url = entry.link, entry.title), "updatePin(${entry.title}") + + pinboard.deletePin(entry) + assertFalse(validatePin(apiToken, url = entry.link), "deletePin") + } + + private fun validatePin(apiToken: String, url: String, vararg matches: String): Boolean { + val response = + URL("https://api.pinboard.in/v1/posts/get?auth_token=${apiToken}&tag=test&" + url.encodeUrl()).reader().body + + matches.forEach { + if (!response.contains(it)) { + return false + } + } + + return response.contains(url) + } +} diff --git a/bin/test/net/thauvin/erik/mobibot/UtilsTest.kt b/bin/test/net/thauvin/erik/mobibot/UtilsTest.kt new file mode 100644 index 0000000..7b7ba8c --- /dev/null +++ b/bin/test/net/thauvin/erik/mobibot/UtilsTest.kt @@ -0,0 +1,278 @@ +/* + * UtilsTest.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot + +import assertk.all +import assertk.assertThat +import assertk.assertions.isEqualTo +import assertk.assertions.length +import net.thauvin.erik.mobibot.Utils.appendIfMissing +import net.thauvin.erik.mobibot.Utils.bold +import net.thauvin.erik.mobibot.Utils.capitalise +import net.thauvin.erik.mobibot.Utils.capitalizeWords +import net.thauvin.erik.mobibot.Utils.colorize +import net.thauvin.erik.mobibot.Utils.cyan +import net.thauvin.erik.mobibot.Utils.encodeUrl +import net.thauvin.erik.mobibot.Utils.getIntProperty +import net.thauvin.erik.mobibot.Utils.green +import net.thauvin.erik.mobibot.Utils.helpCmdSyntax +import net.thauvin.erik.mobibot.Utils.helpFormat +import net.thauvin.erik.mobibot.Utils.lastOrEmpty +import net.thauvin.erik.mobibot.Utils.obfuscate +import net.thauvin.erik.mobibot.Utils.plural +import net.thauvin.erik.mobibot.Utils.reader +import net.thauvin.erik.mobibot.Utils.red +import net.thauvin.erik.mobibot.Utils.replaceEach +import net.thauvin.erik.mobibot.Utils.reverseColor +import net.thauvin.erik.mobibot.Utils.toIntOrDefault +import net.thauvin.erik.mobibot.Utils.toIsoLocalDate +import net.thauvin.erik.mobibot.Utils.toUtcDateTime +import net.thauvin.erik.mobibot.Utils.today +import net.thauvin.erik.mobibot.Utils.underline +import net.thauvin.erik.mobibot.Utils.unescapeXml +import net.thauvin.erik.mobibot.msg.Message.Companion.DEFAULT_COLOR +import org.pircbotx.Colors +import org.testng.annotations.BeforeClass +import kotlin.test.Test +import java.io.File +import java.io.IOException +import java.net.URL +import java.time.LocalDateTime +import java.util.* + +/** + * The `Utils Test` class. + */ +class UtilsTest { + private val ascii = + " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" + private val cal = Calendar.getInstance() + private val localDateTime = LocalDateTime.of(1952, 2, 17, 12, 30, 0) + private val test = "This is a test." + + @BeforeClass + fun setUp() { + cal[1952, Calendar.FEBRUARY, 17, 12, 30] = 0 + } + + @Test + fun testAppendIfMissing() { + val dir = "dir" + val sep = '/' + val url = "https://erik.thauvin.net" + assertThat(dir.appendIfMissing(File.separatorChar), "appendIfMissing(dir)") + .isEqualTo(dir + File.separatorChar) + assertThat(url.appendIfMissing(sep), "appendIfMissing(url)").isEqualTo("$url$sep") + assertThat("$url$sep".appendIfMissing(sep), "appendIfMissing($url$sep)").isEqualTo("$url$sep") + } + + @Test + fun testBold() { + assertThat(1.bold(), "bold(1)").isEqualTo(Colors.BOLD + "1" + Colors.BOLD) + assertThat(2L.bold(), "bold(2L)").isEqualTo(Colors.BOLD + "2" + Colors.BOLD) + assertThat(ascii.bold(), "ascii.bold()").isEqualTo(Colors.BOLD + ascii + Colors.BOLD) + assertThat("test".bold(), "test.bold()").isEqualTo(Colors.BOLD + "test" + Colors.BOLD) + } + + + @Test + fun testCapitalise() { + assertThat("test".capitalise(), "capitalize(test)").isEqualTo("Test") + assertThat("Test".capitalise(), "capitalize(Test)").isEqualTo("Test") + assertThat(test.capitalise(), "capitalize($test)").isEqualTo(test) + assertThat("".capitalise(), "capitalize()").isEqualTo("") + } + + @Test + fun textCapitaliseWords() { + assertThat(test.capitalizeWords(), "captiatlizeWords(test)").isEqualTo("This Is A Test.") + assertThat("Already Capitalized".capitalizeWords(), "already capitalized") + .isEqualTo("Already Capitalized") + assertThat(" a test ".capitalizeWords(), "with spaces").isEqualTo(" A Test ") + } + + @Test + fun testColorize() { + assertThat(ascii.colorize(Colors.REVERSE), "reverse.colorize()").isEqualTo( + Colors.REVERSE + ascii + Colors.REVERSE + ) + assertThat(ascii.colorize(Colors.RED), "red.colorize()") + .isEqualTo(Colors.RED + ascii + Colors.NORMAL) + assertThat(ascii.colorize(Colors.BOLD), "colorized(bold)") + .isEqualTo(Colors.BOLD + ascii + Colors.BOLD) + assertThat(null.colorize(Colors.RED), "null.colorize()").isEqualTo("") + assertThat("".colorize(Colors.RED), "colorize()").isEqualTo("") + assertThat(ascii.colorize(DEFAULT_COLOR), "ascii.colorize()").isEqualTo(ascii) + assertThat(" ".colorize(Colors.NORMAL), "blank.colorize()") + .isEqualTo(Colors.NORMAL + " " + Colors.NORMAL) + } + + @Test + fun testCyan() { + assertThat(ascii.cyan()).isEqualTo(Colors.CYAN + ascii + Colors.NORMAL) + } + + @Test + fun testEncodeUrl() { + assertThat("Hello Günter".encodeUrl()).isEqualTo("Hello%20G%C3%BCnter") + } + + @Test + fun testGetIntProperty() { + val p = Properties() + p["one"] = "1" + p["two"] = "two" + assertThat(p.getIntProperty("one", 9), "getIntProperty(one)").isEqualTo(1) + assertThat(p.getIntProperty("two", 2), "getIntProperty(two)").isEqualTo(2) + assertThat(p.getIntProperty("foo", 3), "getIntProperty(foo)").isEqualTo(3) + } + + @Test + fun testGreen() { + assertThat(ascii.green()).isEqualTo(Colors.DARK_GREEN + ascii + Colors.NORMAL) + } + + @Test + fun testHelpCmdSyntax() { + val bot = "mobibot" + assertThat(helpCmdSyntax("%c $test %n $test", bot, false), "helpCmdSyntax(private)") + .isEqualTo("$bot: $test $bot $test") + assertThat(helpCmdSyntax("%c %n $test %c $test %n", bot, true), "helpCmdSyntax(public)") + .isEqualTo("/msg $bot $bot $test /msg $bot $test $bot") + } + + @Test + fun testHelpFormat() { + assertThat(helpFormat(test, isBold = true, isIndent = false), "helpFormat(bold)") + .isEqualTo("${Colors.BOLD}$test${Colors.BOLD}") + assertThat(helpFormat(test, isBold = false, isIndent = true), "helpFormat(indent)") + .isEqualTo(test.prependIndent()) + assertThat(helpFormat(test, isBold = true, isIndent = true), "helpFormat(bold,indent)") + .isEqualTo(test.colorize(Colors.BOLD).prependIndent()) + + } + + @Test + fun testIsoLocalDate() { + assertThat(cal.time.toIsoLocalDate(), "isoLocalDate(date)").isEqualTo("1952-02-17") + assertThat(localDateTime.toIsoLocalDate(), "isoLocalDate(localDate)").isEqualTo("1952-02-17") + } + + @Test + fun testLastOrEmpty() { + val two = listOf("1", "2") + assertThat(two.lastOrEmpty(), "lastOrEmpty(1,2)").isEqualTo("2") + val one = listOf("1") + assertThat(one.lastOrEmpty(), "lastOrEmpty(1)").isEqualTo("") + } + + @Test + fun testObfuscate() { + assertThat(ascii.obfuscate(), "obfuscate()").all { + length().isEqualTo(ascii.length) + isEqualTo(("x".repeat(ascii.length))) + } + assertThat(" ".obfuscate(), "obfuscate(blank)").isEqualTo(" ") + } + + @Test + fun testPlural() { + val week = "week" + val weeks = "weeks" + + for (i in -1..3) { + assertThat(week.plural(i.toLong()), "plural($i)").isEqualTo(if (i > 1) weeks else week) + } + } + + @Test + fun testReplaceEach() { + val search = arrayOf("one", "two", "three") + val replace = arrayOf("1", "2", "3") + assertThat(search.joinToString(",").replaceEach(search, replace), "replaceEach(1,2,3") + .isEqualTo(replace.joinToString(",")) + + assertThat(test.replaceEach(search, replace), "replaceEach(nothing)").isEqualTo(test) + + assertThat(test.replaceEach(arrayOf("t", "e"), arrayOf("", "E")), "replaceEach($test)") + .isEqualTo(test.replace("t", "").replace("e", "E")) + + assertThat(test.replaceEach(search, emptyArray()), "replaceEach(search, empty)") + .isEqualTo(test) + } + + @Test + fun testRed() { + assertThat(ascii.red()).isEqualTo(ascii.colorize(Colors.RED)) + } + + @Test + fun testReverseColor() { + assertThat(ascii.reverseColor()).isEqualTo(Colors.REVERSE + ascii + Colors.REVERSE) + } + + @Test + fun testToday() { + assertThat(today()).isEqualTo(LocalDateTime.now().toIsoLocalDate()) + } + + @Test + fun testToIntOrDefault() { + assertThat("10".toIntOrDefault(1), "toIntOrDefault(10, 1)").isEqualTo(10) + assertThat("a".toIntOrDefault(2), "toIntOrDefault(a, 2)").isEqualTo(2) + } + + @Test + fun testUnderline() { + assertThat(ascii.underline()).isEqualTo(ascii.colorize(Colors.UNDERLINE)) + } + + @Test + fun testUnescapeXml() { + assertThat("<a name="test & ''">".unescapeXml()).isEqualTo( + "" + ) + } + + @Test + @Throws(IOException::class) + fun testUrlReader() { + val reader = URL("https://postman-echo.com/status/200").reader() + assertThat(reader.body).isEqualTo("{\n \"status\": 200\n}") + assertThat(reader.responseCode).isEqualTo(200) + } + + @Test + fun testUtcDateTime() { + assertThat(cal.time.toUtcDateTime(), "utcDateTime(date)").isEqualTo("1952-02-17 12:30") + assertThat(localDateTime.toUtcDateTime(), "utcDateTime(localDate)").isEqualTo("1952-02-17 12:30") + } +} diff --git a/bin/test/net/thauvin/erik/mobibot/commands/InfoTest.kt b/bin/test/net/thauvin/erik/mobibot/commands/InfoTest.kt new file mode 100644 index 0000000..99ba951 --- /dev/null +++ b/bin/test/net/thauvin/erik/mobibot/commands/InfoTest.kt @@ -0,0 +1,58 @@ +/* + * InfoTest.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.commands + +import assertk.assertThat +import assertk.assertions.isEqualTo +import net.thauvin.erik.mobibot.commands.Info.Companion.toUptime +import kotlin.test.Test + +class InfoTest { + @Test + fun testToUptime() { + assertThat( + 547800300076L.toUptime(), + "upTime(full)" + ).isEqualTo("17 years 4 months 2 weeks 1 day 6 hours 45 minutes") + assertThat(24300000L.toUptime(), "upTime(hours minutes)").isEqualTo("6 hours 45 minutes") + assertThat(110700000L.toUptime(), "upTime(days hours minutes)").isEqualTo("1 day 6 hours 45 minutes") + assertThat( + 1320300000L.toUptime(), + "upTime(weeks days hours minutes)" + ).isEqualTo("2 weeks 1 day 6 hours 45 minutes") + assertThat(2700000L.toUptime(), "upTime(45 minutes)").isEqualTo("45 minutes") + assertThat(60000L.toUptime(), "upTime(1 minute)").isEqualTo("1 minute") + assertThat(59000L.toUptime(), "upTime(59 seconds)").isEqualTo("59 seconds") + assertThat(0L.toUptime(), "upTime(0 second)").isEqualTo("0 second") + + } +} diff --git a/bin/test/net/thauvin/erik/mobibot/commands/RecapTest.kt b/bin/test/net/thauvin/erik/mobibot/commands/RecapTest.kt new file mode 100644 index 0000000..b6fbbff --- /dev/null +++ b/bin/test/net/thauvin/erik/mobibot/commands/RecapTest.kt @@ -0,0 +1,60 @@ +/* + * RecapTest.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.commands + +import assertk.all +import assertk.assertThat +import assertk.assertions.isEqualTo +import assertk.assertions.matches +import assertk.assertions.prop +import assertk.assertions.size +import kotlin.test.Test + +class RecapTest { + @Test + fun storeRecapTest() { + for (i in 1..20) { + Recap.storeRecap("sender$i", "test $i", false) + } + assertThat(Recap.recaps, "Recap.recaps").all { + size().isEqualTo(Recap.MAX_RECAPS) + prop(MutableList::first) + .matches("[1-2]\\d{3}-[01]\\d-[0-3]\\d [0-2]\\d:[0-6]\\d - sender11: test 11".toRegex()) + prop(MutableList::last) + .matches("[1-2]\\d{3}-[01]\\d-[0-3]\\d [0-2]\\d:[0-6]\\d - sender20: test 20".toRegex()) + } + + Recap.storeRecap("sender", "test action", true) + assertThat(Recap.recaps.last()) + .matches("[1-2]\\d{3}-[01]\\d-[0-3]\\d [0-2]\\d:[0-6]\\d - sender test action".toRegex()) + } +} diff --git a/bin/test/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt b/bin/test/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt new file mode 100644 index 0000000..fa2bb70 --- /dev/null +++ b/bin/test/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt @@ -0,0 +1,77 @@ +/* + * LinksManagerTest.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.commands.links + +import assertk.all +import assertk.assertThat +import assertk.assertions.contains +import assertk.assertions.isEqualTo +import assertk.assertions.isTrue +import assertk.assertions.size +import net.thauvin.erik.mobibot.Constants +import kotlin.test.Test + +class LinksManagerTest { + private val linksManager = LinksManager() + + @Test + fun fetchTitle() { + assertThat(linksManager.fetchTitle("https://erik.thauvin.net/"), "fetchTitle(Erik)").contains("Erik's Weblog") + assertThat( + linksManager.fetchTitle("https://www.google.com/foo"), + "fetchTitle(Foo)" + ).isEqualTo(Constants.NO_TITLE) + } + + @Test + fun testMatches() { + assertThat(linksManager.matches("https://www.example.com/"), "matches(url)").isTrue() + assertThat(linksManager.matches("HTTP://erik.thauvin.net/blog/ Erik's Weblog"), "matches(HTTP)").isTrue() + } + + @Test + fun matchTagKeywordsTest() { + linksManager.setProperty(LinksManager.KEYWORDS_PROP, "key1 key2,key3") + val tags = mutableListOf() + + linksManager.matchTagKeywords("Test title with key2", tags) + assertThat(tags, "tags").contains("key2") + tags.clear() + + linksManager.matchTagKeywords("Test key3 title with key1", tags) + assertThat(tags, "tags(key1, key3)").all { + contains("key1") + contains("key3") + size().isEqualTo(2) + } + } +} diff --git a/bin/test/net/thauvin/erik/mobibot/commands/links/ViewTest.kt b/bin/test/net/thauvin/erik/mobibot/commands/links/ViewTest.kt new file mode 100644 index 0000000..e315891 --- /dev/null +++ b/bin/test/net/thauvin/erik/mobibot/commands/links/ViewTest.kt @@ -0,0 +1,111 @@ +/* + * ViewTest.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.commands.links + +import assertk.all +import assertk.assertThat +import assertk.assertions.isEqualTo +import assertk.assertions.prop +import net.thauvin.erik.mobibot.entries.EntryLink +import kotlin.test.Test + +class ViewTest { + @Test + fun testParseArgs() { + val view = View() + + for (i in 1..10) { + LinksManager.entries.links.add( + EntryLink( + "https://www.example.com/$i", + "Example $i", + "nick$i", + "login$i", + "#channel", + emptyList() + ) + ) + } + + assertThat(view.parseArgs("1"), "parseArgs(1)").all { + prop(Pair::first).isEqualTo(0) + prop(Pair::second).isEqualTo("") + } + + assertThat(view.parseArgs("2 foo"), "parseArgs(2, foo)").all { + prop(Pair::first).isEqualTo(1) + prop(Pair::second).isEqualTo("foo") + } + + assertThat(view.parseArgs("3 FOO"), "parseArgs(3, FOO)").all { + prop(Pair::first).isEqualTo(2) + prop(Pair::second).isEqualTo("foo") + } + + assertThat(view.parseArgs(" 4 foo bar "), "parseArgs( 4 foo bar )").all { + prop(Pair::first).isEqualTo(3) + prop(Pair::second).isEqualTo("foo bar") + } + + assertThat(view.parseArgs("foo bar"), "parseArgs(foo bar)").all { + prop(Pair::first).isEqualTo(0) + prop(Pair::second).isEqualTo("foo bar") + } + + assertThat(view.parseArgs("${Int.MAX_VALUE}1"), "parseArgs(overflow)").all { + prop(Pair::first).isEqualTo(0) + prop(Pair::second).isEqualTo("${Int.MAX_VALUE}1") + } + + assertThat(view.parseArgs("1a"), "parseArgs(1a)").all { + prop(Pair::first).isEqualTo(0) + prop(Pair::second).isEqualTo("1a") + } + + assertThat(view.parseArgs("20"), "parseArgs(20)").all { + prop(Pair::first).isEqualTo(0) + prop(Pair::second).isEqualTo("") + } + + assertThat(view.parseArgs(""), "parseArgs()").all { + prop(Pair::first).isEqualTo(LinksManager.entries.links.size - View.MAX_ENTRIES) + prop(Pair::second).isEqualTo("") + } + + LinksManager.entries.links.clear() + + assertThat(view.parseArgs("4"), "parseArgs(4)").all { + prop(Pair::first).isEqualTo(0) + prop(Pair::second).isEqualTo("") + } + } +} diff --git a/bin/test/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt b/bin/test/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt new file mode 100644 index 0000000..37b884b --- /dev/null +++ b/bin/test/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt @@ -0,0 +1,85 @@ +/* + * SeenTest.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.commands.seen + +import assertk.all +import assertk.assertThat +import assertk.assertions.* +import org.testng.annotations.AfterClass +import org.testng.annotations.BeforeClass +import kotlin.test.Test +import kotlin.io.path.deleteIfExists +import kotlin.io.path.fileSize + +class SeenTest { + private val tmpFile = kotlin.io.path.createTempFile(suffix = ".ser") + private val seen = Seen(tmpFile.toAbsolutePath().toString()) + private val nick = "ErikT" + + @BeforeClass + fun saveTest() { + seen.add("ErikT") + assertThat(tmpFile.fileSize(), "tmpFile.size").isGreaterThan(0) + } + + @AfterClass(alwaysRun = true) + fun afterClass() { + tmpFile.deleteIfExists() + } + + @Test(priority = 1, groups = ["commands"]) + fun loadTest() { + seen.clear() + assertThat(seen::seenNicks).isEmpty() + seen.load() + assertThat(seen::seenNicks).key(nick).isNotNull() + } + + @Test + fun addTest() { + val last = seen.seenNicks[nick]?.lastSeen + seen.add(nick.lowercase()) + assertThat(seen).all { + prop(Seen::seenNicks).size().isEqualTo(1) + prop(Seen::seenNicks).key(nick).isNotNull().prop(SeenNick::lastSeen).isNotEqualTo(last) + prop(Seen::seenNicks).key(nick).isNotNull().prop(SeenNick::nick).isNotNull().isEqualTo(nick.lowercase()) + } + } + + @Test(priority = 10, groups = ["commands"]) + fun clearTest() { + seen.clear() + seen.save() + seen.load() + assertThat(seen::seenNicks).size().isEqualTo(0) + } +} diff --git a/bin/test/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt b/bin/test/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt new file mode 100644 index 0000000..cc09237 --- /dev/null +++ b/bin/test/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt @@ -0,0 +1,72 @@ +/* + * TellMessageTest.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.commands.tell + +import assertk.all +import assertk.assertThat +import assertk.assertions.isEqualTo +import assertk.assertions.isFalse +import assertk.assertions.isTrue +import assertk.assertions.prop +import kotlin.test.Test +import java.time.Duration +import java.time.LocalDateTime +import java.time.temporal.Temporal + +/** + * The `TellMessageTest` class. + */ +class TellMessageTest { + private fun isValidDate(date: Temporal): Boolean { + return Duration.between(date, LocalDateTime.now()).toMinutes() < 1 + } + + @Test + fun testTellMessage() { + val message = "Test message." + val recipient = "recipient" + val sender = "sender" + val tellMessage = TellMessage(sender, recipient, message) + assertThat(tellMessage).all { + prop(TellMessage::sender).isEqualTo(sender) + prop(TellMessage::recipient).isEqualTo(recipient) + prop(TellMessage::message).isEqualTo(message) + } + assertThat(isValidDate(tellMessage.queued), "isValidDate()").isTrue() + assertThat(tellMessage.isMatch(sender), "isMatch(sender)").isTrue() + assertThat(tellMessage.isMatch(recipient), "isMatch(recipient)").isTrue() + assertThat(tellMessage.isMatch("foo"), "isMatch(foo)").isFalse() + tellMessage.isReceived = false + assertThat(tellMessage.receptionDate, "receptionDate").isEqualTo(LocalDateTime.MIN) + tellMessage.isReceived = true + assertThat(isValidDate(tellMessage.receptionDate), "isValidDate(creationDate)").isTrue() + } +} diff --git a/bin/test/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt b/bin/test/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt new file mode 100644 index 0000000..5acba78 --- /dev/null +++ b/bin/test/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt @@ -0,0 +1,87 @@ +/* + * TellMessagesMgrTest.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.commands.tell + +import assertk.all +import assertk.assertThat +import assertk.assertions.* +import org.testng.annotations.AfterClass +import org.testng.annotations.BeforeClass +import kotlin.test.Test +import java.time.LocalDateTime +import kotlin.io.path.createTempFile +import kotlin.io.path.deleteIfExists +import kotlin.io.path.fileSize + +class TellMessagesMgrTest { + private val testFile = createTempFile(suffix = ".ser") + private val maxDays = 10L + private val testMessages = mutableListOf().apply { + for (i in 0..5) { + this.add(i, TellMessage("sender$i", "recipient$i", "message $i")) + } + } + + @BeforeClass + fun saveTest() { + TellManager.save(testFile.toAbsolutePath().toString(), testMessages) + assertThat(testFile.fileSize()).isGreaterThan(0) + } + + @AfterClass + fun afterClass() { + testFile.deleteIfExists() + } + + @Test + fun cleanTest() { + testMessages.add(TellMessage("sender", "recipient", "message").apply { + queued = LocalDateTime.now().minusDays(maxDays) + }) + val size = testMessages.size + assertThat(TellManager.clean(testMessages, maxDays + 2), "clean(maxDays=${maxDays + 2})").isFalse() + assertThat(TellManager.clean(testMessages, maxDays), "clean(maxDays=$maxDays)").isTrue() + assertThat(testMessages, "testMessages").size().isEqualTo(size - 1) + } + + @Test + fun loadTest() { + val messages = TellManager.load(testFile.toAbsolutePath().toString()) + for (i in messages.indices) { + assertThat(messages).index(i).all { + prop(TellMessage::sender).isEqualTo(testMessages[i].sender) + prop(TellMessage::recipient).isEqualTo(testMessages[i].recipient) + prop(TellMessage::message).isEqualTo(testMessages[i].message) + } + } + } +} diff --git a/bin/test/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt b/bin/test/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt new file mode 100644 index 0000000..0ad26b5 --- /dev/null +++ b/bin/test/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt @@ -0,0 +1,91 @@ +/* + * EntriesUtilsTest.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.entries + +import assertk.assertThat +import assertk.assertions.contains +import assertk.assertions.isEqualTo +import net.thauvin.erik.mobibot.Constants +import net.thauvin.erik.mobibot.entries.EntriesUtils.printComment +import net.thauvin.erik.mobibot.entries.EntriesUtils.printLink +import net.thauvin.erik.mobibot.entries.EntriesUtils.printTags +import net.thauvin.erik.mobibot.entries.EntriesUtils.toLinkLabel +import kotlin.test.Test + +class EntriesUtilsTest { + private val comment = EntryComment("comment", "nick") + private val links = buildList { + for (i in 0..5) { + add( + EntryLink( + "https://www.mobitopia.org/$i", + "Mobitopia$i", + "Skynx$i", + "JimH$i", + "#mobitopia$i", + listOf("tag1", "tag2", "tag3", "TAG4", "Tag5") + ) + ) + } + } + + @Test + fun printCommentTest() { + assertThat(printComment(0, 0, comment)).isEqualTo("${Constants.LINK_CMD}1.1: [nick] comment") + } + + @Test + fun printLinkTest() { + for (i in links.indices) { + assertThat( + printLink(i - 1, links[i]), "link $i" + ).isEqualTo("L$i: [Skynx$i] \u0002Mobitopia$i\u0002 ( \u000303https://www.mobitopia.org/$i\u000F )") + } + + assertThat(links.first().addComment(comment), "addComment()").isEqualTo(0) + assertThat(printLink(0, links.first(), isView = true), "printLink(isView=true)").contains("[+1]") + } + + @Test + fun printTagsTest() { + for (i in links.indices) { + assertThat( + printTags(i - 1, links[i]), "tag $i" + ).isEqualTo("L${i}T: tag1, tag2, tag3, tag4, tag5") + } + } + + @Test + fun toLinkLabelTest() { + assertThat(1.toLinkLabel()).isEqualTo("${Constants.LINK_CMD}2") + } +} diff --git a/bin/test/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt b/bin/test/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt new file mode 100644 index 0000000..f421099 --- /dev/null +++ b/bin/test/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt @@ -0,0 +1,133 @@ +/* + * EntryLinkTest.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.entries + +import assertk.all +import assertk.assertThat +import assertk.assertions.* +import com.rometools.rome.feed.synd.SyndCategory +import com.rometools.rome.feed.synd.SyndCategoryImpl +import kotlin.test.Test +import java.security.SecureRandom +import java.util.* + +/** + * The `EntryUtilsTest` class. + * + * @author [Erik C. Thauvin](https://erik.thauvin.net/) + * @created 2019-04-19 + * @since 1.0 + */ +class EntryLinkTest { + private val entryLink = EntryLink( + "https://www.mobitopia.org/", "Mobitopia", "Skynx", "JimH", "#mobitopia", + listOf("tag1", "tag2", "tag3", "TAG4", "Tag5") + ) + + @Test + fun testAddDeleteComment() { + var i = 0 + while (i < 5) { + entryLink.addComment("c$i", "u$i") + i++ + } + assertThat(entryLink.comments, "comments").size().isEqualTo(i) + i = 0 + for (comment in entryLink.comments) { + assertThat(comment).all { + prop(EntryComment::comment).isEqualTo("c$i") + prop(EntryComment::nick).isEqualTo("u$i") + } + i++ + } + + val r = SecureRandom() + while (entryLink.comments.size > 0) { + entryLink.deleteComment(r.nextInt(entryLink.comments.size)) + } + assertThat(entryLink.comments, "hasComments()").isEmpty() + entryLink.addComment("nothing", "nobody") + entryLink.setComment(0, "something", "somebody") + val comment = entryLink.getComment(0) + assertThat(comment, "comment[first]").all { + prop(EntryComment::nick).isEqualTo("somebody") + prop(EntryComment::comment).isEqualTo("something") + } + assertThat(entryLink.deleteComment(comment), "deleteComment").isTrue() + assertThat(entryLink.deleteComment(comment), "comment is already deleted").isFalse() + } + + @Test + fun testConstructor() { + val tags = listOf(SyndCategoryImpl().apply { name = "tag1" }, SyndCategoryImpl().apply { name = "tag2" }) + val link = EntryLink("link", "title", "nick", "channel", Date(), tags) + assertThat(link, "link").all { + prop(EntryLink::tags).size().isEqualTo(tags.size) + prop(EntryLink::tags).index(0).prop(SyndCategory::getName).isEqualTo("tag1") + } + } + + @Test + fun testMatches() { + assertThat(entryLink.matches("mobitopia"), "matches(mobitopia)").isTrue() + assertThat(entryLink.matches("skynx"), "match(nick)").isTrue() + assertThat(entryLink.matches("www.mobitopia.org"), "matches(url)").isTrue() + assertThat(entryLink.matches("foo"), "matches(foo)").isFalse() + assertThat(entryLink.matches(""), "matches(empty)").isFalse() + assertThat(entryLink.matches(null), "matches(null)").isFalse() + } + + + @Test + fun testTags() { + val tags: List = entryLink.tags + for ((i, tag) in tags.withIndex()) { + assertThat(tag.name, "tag.name($i)").isEqualTo("tag${i + 1}") + } + assertThat(entryLink::tags).size().isEqualTo(5) + entryLink.setTags("-tag5, tag4") + entryLink.setTags("+mobitopia") + entryLink.setTags("-mobitopia") + assertThat( + entryLink.formatTags(","), + "formatTags(',')" + ).isEqualTo("tag1,tag2,tag3,tag4,mobitopia") + entryLink.setTags("-tag4 tag5") + assertThat( + entryLink.formatTags(" ", ","), "formatTag(' ',',')" + ).isEqualTo(",tag1 tag2 tag3 mobitopia tag5") + val size = entryLink.tags.size + entryLink.setTags("") + assertThat(entryLink.tags, "setTags('')").size().isEqualTo(size) + entryLink.setTags(" ") + assertThat(entryLink.tags, "setTags(' ')").size().isEqualTo(size) + } +} diff --git a/bin/test/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt b/bin/test/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt new file mode 100644 index 0000000..1611009 --- /dev/null +++ b/bin/test/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt @@ -0,0 +1,115 @@ +/* + * FeedMgrTest.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.entries + +import assertk.all +import assertk.assertThat +import assertk.assertions.* +import net.thauvin.erik.mobibot.Utils.today +import org.testng.annotations.BeforeSuite +import kotlin.test.Test +import java.nio.file.Paths +import java.util.* +import kotlin.io.path.deleteIfExists +import kotlin.io.path.fileSize +import kotlin.io.path.name + +class FeedMgrTest { + private val entries = Entries() + private val channel = "mobibot" + + @BeforeSuite(alwaysRun = true) + fun beforeSuite() { + entries.logsDir = "src/test/resources/" + entries.ircServer = "irc.example.com" + entries.channel = channel + entries.backlogs = "https://www.mobitopia.org/mobibot/logs" + } + + @Test + fun testFeedMgr() { + // Load the feed + assertThat(FeedsManager.loadFeed(entries), "loadFeed()").isEqualTo("2021-10-31") + + assertThat(entries.links, "entries.links").size().isEqualTo(2) + entries.links.forEachIndexed { i, entryLink -> + assertThat(entryLink, "entryLink[${i + 1}]").all { + prop(EntryLink::title).isEqualTo("Example ${i + 1}") + prop(EntryLink::link).isEqualTo("https://www.example.com/${i + 1}") + prop(EntryLink::channel).isEqualTo(channel) + } + entryLink.tags.forEachIndexed { y, tag -> + assertThat(tag.name, "tag${i + 1}-${y + 1}").isEqualTo("tag${i + 1}-${y + 1}") + } + } + + with(entries.links.first()) { + assertThat(nick, "nick[first]").isEqualTo("ErikT") + assertThat(date, "date[first]").isEqualTo(Date(1635638400000L)) + assertThat(comments.first(), "comments[first]").all { + prop(EntryComment::comment).endsWith("comment 1.") + prop(EntryComment::nick).isEqualTo("ErikT") + } + assertThat(comments.last(), "comments[last]").all { + prop(EntryComment::comment).endsWith("comment 2.") + prop(EntryComment::nick).isEqualTo("Skynx") + } + } + + assertThat(entries.links, "links").index(1).all { + prop(EntryLink::nick).isEqualTo("Skynx") + prop(EntryLink::date).isEqualTo(Date(1635638460000L)) + } + + val currentFile = Paths.get("${entries.logsDir}test.xml") + val backlogFile = Paths.get("${entries.logsDir}${today()}.xml") + + // Save the feed + FeedsManager.saveFeed(entries, currentFile.name) + + assertThat(currentFile, "currentFile").exists() + assertThat(backlogFile, "backlogFile").exists() + + assertThat(currentFile.fileSize(), "currentFile == backlogFile").isEqualTo(backlogFile.fileSize()) + + // Load the test feed + entries.links.clear() + FeedsManager.loadFeed(entries, currentFile.name) + + entries.links.forEachIndexed { i, entryLink -> + assertThat(entryLink.title, "entryLink.title[${i + 1}]").isEqualTo("Example ${i + 1}") + } + + assertThat(currentFile.deleteIfExists(), "currentFile.deleteIfExists()").isTrue() + assertThat(backlogFile.deleteIfExists(), "backlogFile.deleteIfExists()").isTrue() + } +} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/CalcTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/CalcTest.kt new file mode 100644 index 0000000..3bd4c0f --- /dev/null +++ b/bin/test/net/thauvin/erik/mobibot/modules/CalcTest.kt @@ -0,0 +1,53 @@ +/* + * CalcTest.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.modules + +import assertk.assertFailure +import assertk.assertThat +import assertk.assertions.isEqualTo +import assertk.assertions.isInstanceOf +import net.objecthunter.exp4j.tokenizer.UnknownFunctionOrVariableException +import net.thauvin.erik.mobibot.Utils.bold +import net.thauvin.erik.mobibot.modules.Calc.Companion.calculate +import kotlin.test.Test + +/** + * The `CalcTest` class. + */ +class CalcTest { + @Test + fun testCalculate() { + assertThat(calculate("1 + 1"), "calculate(1+1)").isEqualTo("1+1 = ${2.bold()}") + assertThat(calculate("1 -3"), "calculate(1-3)").isEqualTo("1-3 = ${(-2).bold()}") + assertThat(calculate("pi+π+e+φ"), "calculate(pi+π+e+φ)").isEqualTo("pi+π+e+φ = ${"10.62".bold()}") + assertFailure { calculate("one + one") }.isInstanceOf(UnknownFunctionOrVariableException::class.java) + } +} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/ChatGptTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/ChatGptTest.kt new file mode 100644 index 0000000..085f228 --- /dev/null +++ b/bin/test/net/thauvin/erik/mobibot/modules/ChatGptTest.kt @@ -0,0 +1,62 @@ +/* + * ChatGptTest.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.modules + +import assertk.assertFailure +import assertk.assertThat +import assertk.assertions.contains +import assertk.assertions.hasNoCause +import assertk.assertions.isInstanceOf +import net.thauvin.erik.mobibot.LocalProperties +import kotlin.test.Test + +class ChatGptTest : LocalProperties() { + @Test + fun testApiKey() { + assertFailure { ChatGpt.chat("1 gallon to liter", "", 0) } + .isInstanceOf(ModuleException::class.java) + .hasNoCause() + } + + @Test(groups = ["modules", "no-ci"]) + fun testChat() { + val apiKey = getProperty(ChatGpt.API_KEY_PROP) + assertThat( + ChatGpt.chat("how do I make an HTTP request in Javascript?", apiKey, 100) + ).contains("XMLHttpRequest") + assertThat( + ChatGpt.chat("how do I encode a URL in java?", apiKey, 60) + ).contains("URLEncoder") + + assertFailure { ChatGpt.chat("1 liter to gallon", apiKey, 0) } + .isInstanceOf(ModuleException::class.java) + } +} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt new file mode 100644 index 0000000..d0ecbc9 --- /dev/null +++ b/bin/test/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt @@ -0,0 +1,78 @@ +/* + * CryptoPricesTest.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.modules + +import assertk.all +import assertk.assertThat +import assertk.assertions.isEqualTo +import assertk.assertions.isGreaterThan +import assertk.assertions.prop +import net.thauvin.erik.crypto.CryptoPrice +import net.thauvin.erik.mobibot.modules.CryptoPrices.Companion.currentPrice +import net.thauvin.erik.mobibot.modules.CryptoPrices.Companion.getCurrencyName +import net.thauvin.erik.mobibot.modules.CryptoPrices.Companion.loadCurrencies +import org.testng.annotations.BeforeClass +import kotlin.test.Test + +/** + * The `CryptoPricesTest` class. + */ +class CryptoPricesTest { + @BeforeClass + @Throws(ModuleException::class) + fun before() { + loadCurrencies() + } + + @Test + @Throws(ModuleException::class) + fun testMarketPrice() { + var price = currentPrice(listOf("BTC")) + assertThat(price, "currentPrice(BTC)").all { + prop(CryptoPrice::base).isEqualTo("BTC") + prop(CryptoPrice::currency).isEqualTo("USD") + prop(CryptoPrice::amount).transform { it.signum() }.isGreaterThan(0) + } + + price = currentPrice(listOf("ETH", "EUR")) + assertThat(price, "currentPrice(ETH, EUR)").all { + prop(CryptoPrice::base).isEqualTo("ETH") + prop(CryptoPrice::currency).isEqualTo("EUR") + prop(CryptoPrice::amount).transform { it.signum() }.isGreaterThan(0) + } + } + + @Test + fun testGetCurrencyName() { + assertThat(getCurrencyName("USD"), "USD").isEqualTo("United States Dollar") + assertThat(getCurrencyName("EUR"), "EUR").isEqualTo("Euro") + } +} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt new file mode 100644 index 0000000..8d8c997 --- /dev/null +++ b/bin/test/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt @@ -0,0 +1,85 @@ +/* + * CurrencyConverterTest.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.modules + +import assertk.all +import assertk.assertThat +import assertk.assertions.contains +import assertk.assertions.isInstanceOf +import assertk.assertions.matches +import assertk.assertions.prop +import net.thauvin.erik.mobibot.LocalProperties +import net.thauvin.erik.mobibot.modules.CurrencyConverter.Companion.convertCurrency +import net.thauvin.erik.mobibot.modules.CurrencyConverter.Companion.loadSymbols +import net.thauvin.erik.mobibot.msg.ErrorMessage +import net.thauvin.erik.mobibot.msg.Message +import net.thauvin.erik.mobibot.msg.PublicMessage +import org.testng.annotations.BeforeClass +import kotlin.test.Test + + +/** + * The `CurrencyConvertTest` class. + */ +class CurrencyConverterTest : LocalProperties() { + + @BeforeClass + @Throws(ModuleException::class) + fun before() { + val apiKey = getProperty(CurrencyConverter.API_KEY_PROP) + loadSymbols(apiKey) + } + + @Test + fun testConvertCurrency() { + val apiKey = getProperty(CurrencyConverter.API_KEY_PROP) + assertThat( + convertCurrency(apiKey, "100 USD to EUR").msg, + "convertCurrency(100 USD to EUR)" + ).matches("100 United States Dollar = \\d{2,3}\\.\\d{2,3} Euro".toRegex()) + assertThat( + convertCurrency(apiKey, "1 USD to GBP").msg, + "convertCurrency(1 USD to BGP)" + ).matches("1 United States Dollar = 0\\.\\d{2,3} Pound Sterling".toRegex()) + assertThat( + convertCurrency(apiKey, "100,000.00 CAD to USD").msg, + "convertCurrency(100,000.00 GBP to USD)" + ).matches("100,000.00 Canadian Dollar = \\d+\\.\\d{2,3} United States Dollar".toRegex()) + assertThat(convertCurrency(apiKey, "100 USD to USD"), "convertCurrency(100 USD to USD)").all { + prop(Message::msg).contains("You're kidding, right?") + isInstanceOf(PublicMessage::class.java) + } + assertThat(convertCurrency(apiKey, "100 USD"), "convertCurrency(100 USD)").all { + prop(Message::msg).contains("Invalid query.") + isInstanceOf(ErrorMessage::class.java) + } + } +} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/DiceTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/DiceTest.kt new file mode 100644 index 0000000..8bafede --- /dev/null +++ b/bin/test/net/thauvin/erik/mobibot/modules/DiceTest.kt @@ -0,0 +1,53 @@ +/* + * DiceTest.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.modules + + +import assertk.assertThat +import assertk.assertions.isEqualTo +import assertk.assertions.matches +import kotlin.test.Test + +class DiceTest { + @Test + fun testRoll() { + assertThat(Dice.roll(1, 1), "roll(1d1)").isEqualTo("\u00021\u0002") + assertThat(Dice.roll(2, 1), "roll(2d1)") + .isEqualTo("\u00021\u0002 + \u00021\u0002 = \u00022\u0002") + assertThat(Dice.roll(5, 1), "roll(5d1)") + .isEqualTo("\u00021\u0002 + \u00021\u0002 + \u00021\u0002 + \u00021\u0002 + \u00021\u0002 = \u00025\u0002") + assertThat(Dice.roll(2, 6), "roll(2d6)") + .matches("\u0002[1-6]\u0002 \\+ \u0002[1-6]\u0002 = \u0002[1-9][0-2]?\u0002".toRegex()) + assertThat(Dice.roll(3, 7), "roll(3d7)") + .matches("\u0002[1-7]\u0002 \\+ \u0002[1-7]\u0002 \\+ \u0002[1-7]\u0002 = \u0002\\d{1,2}\u0002".toRegex()) + } +} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt new file mode 100644 index 0000000..85c990c --- /dev/null +++ b/bin/test/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt @@ -0,0 +1,95 @@ +/* + * GoogleSearchTest.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.modules + +import assertk.all +import assertk.assertFailure +import assertk.assertThat +import assertk.assertions.* +import net.thauvin.erik.mobibot.ExceptionSanitizer.sanitize +import net.thauvin.erik.mobibot.LocalProperties +import net.thauvin.erik.mobibot.modules.GoogleSearch.Companion.searchGoogle +import net.thauvin.erik.mobibot.msg.ErrorMessage +import net.thauvin.erik.mobibot.msg.Message +import kotlin.test.Test + +/** + * The `GoogleSearchTest` class. + */ +class GoogleSearchTest : LocalProperties() { + @Test + fun testAPIKeys() { + assertThat( + searchGoogle("", "apikey", "cssKey").first(), + "searchGoogle(empty)" + ).isInstanceOf(ErrorMessage::class.java) + + assertFailure { searchGoogle("test", "", "apiKey") } + .isInstanceOf(ModuleException::class.java).hasNoCause() + + assertFailure { searchGoogle("test", "apiKey", "") } + .isInstanceOf(ModuleException::class.java).hasNoCause() + + assertFailure { searchGoogle("test", "apiKey", "cssKey") } + .isInstanceOf(ModuleException::class.java) + .hasMessage("API key not valid. Please pass a valid API key.") + } + + @Test\n@DisableOnCi + @Throws(ModuleException::class) + fun testSearchGoogle() { + val apiKey = getProperty(GoogleSearch.API_KEY_PROP) + val cseKey = getProperty(GoogleSearch.CSE_KEY_PROP) + + try { + var query = "mobibot" + var messages = searchGoogle(query, apiKey, cseKey) + assertThat(messages, "searchGoogle($query)").all { + isNotEmpty() + index(0).prop(Message::msg).contains(query, true) + } + + query = "adadflkjl" + messages = searchGoogle(query, apiKey, cseKey) + assertThat(messages, "searchGoogle($query)").index(0).all { + isInstanceOf(ErrorMessage::class.java) + prop(Message::msg).isEqualTo("No results found.") + } + } catch (e: ModuleException) { + // Avoid displaying api keys in CI logs + if ("true" == System.getenv("CI")) { + throw e.sanitize(apiKey, cseKey) + } else { + throw e + } + } + } +} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/JokeTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/JokeTest.kt new file mode 100644 index 0000000..0af8e75 --- /dev/null +++ b/bin/test/net/thauvin/erik/mobibot/modules/JokeTest.kt @@ -0,0 +1,57 @@ +/* + * JokeTest.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.modules + +import assertk.all +import assertk.assertThat +import assertk.assertions.* +import net.thauvin.erik.mobibot.modules.Joke.Companion.randomJoke +import net.thauvin.erik.mobibot.msg.Message +import net.thauvin.erik.mobibot.msg.PublicMessage +import kotlin.test.Test + +/** + * The `JokeTest` class. + */ +class JokeTest { + @Test + @Throws(ModuleException::class) + fun testRandomJoke() { + val joke = randomJoke() + assertThat(joke, "randomJoke()").all { + size().isGreaterThan(0) + each { + it.isInstanceOf(PublicMessage::class.java) + it.prop(Message::msg).doesNotContain("\n") + } + } + } +} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/LookupTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/LookupTest.kt new file mode 100644 index 0000000..a3fc226 --- /dev/null +++ b/bin/test/net/thauvin/erik/mobibot/modules/LookupTest.kt @@ -0,0 +1,60 @@ +/* + * LookupTest.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.modules + +import assertk.assertThat +import assertk.assertions.any +import assertk.assertions.contains +import net.thauvin.erik.mobibot.modules.Lookup.Companion.nslookup +import net.thauvin.erik.mobibot.modules.Lookup.Companion.whois +import kotlin.test.Test + +/** + * The `Lookup Test` class. + */ +class LookupTest { + @Test + @Throws(Exception::class) + fun testLookup() { + var result = nslookup("apple.com") + assertThat(result, "lookup(apple.com)").contains("17.253.144.10") + + result = nslookup("204.122.16.136") + assertThat(result, "lookup(204.122.16.136)").contains("nix3.thauvin.us") + } + + @Test + @Throws(Exception::class) + fun testWhois() { + val result = whois("17.178.96.59", Lookup.WHOIS_HOST) + assertThat(result, "whois(17.178.96.59").any { it.contains("Apple Inc.") } + } +} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/MastodonTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/MastodonTest.kt new file mode 100644 index 0000000..f4b5e99 --- /dev/null +++ b/bin/test/net/thauvin/erik/mobibot/modules/MastodonTest.kt @@ -0,0 +1,54 @@ +/* + * MastodonTest.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.modules + +import assertk.assertThat +import assertk.assertions.contains +import net.thauvin.erik.mobibot.LocalProperties +import net.thauvin.erik.mobibot.modules.Mastodon.Companion.toot +import kotlin.test.Test + +class MastodonTest : LocalProperties() { + @Test + @Throws(ModuleException::class) + fun testToot() { + val msg = "Testing Mastodon API from ${getHostName()}" + assertThat( + toot( + getProperty(Mastodon.ACCESS_TOKEN_PROP), + getProperty(Mastodon.INSTANCE_PROP), + getProperty(Mastodon.HANDLE_PROP), + msg, + true + ) + ).contains(msg) + } +} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt new file mode 100644 index 0000000..1416eec --- /dev/null +++ b/bin/test/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt @@ -0,0 +1,105 @@ +/* + * ModuleExceptionTest.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.modules + +import assertk.all +import assertk.assertThat +import assertk.assertions.* +import net.thauvin.erik.mobibot.ExceptionSanitizer.sanitize +import org.testng.annotations.DataProvider +import kotlin.test.Test +import java.io.IOException +import java.lang.reflect.Method + +/** + * The `ModuleExceptionTest` class. + */ +class ModuleExceptionTest { + companion object { + const val DEBUG_MESSAGE = "debugMessage" + const val MESSAGE = "message" + } + + @DataProvider(name = "dp") + fun createData(@Suppress("UNUSED_PARAMETER") m: Method?): Array> { + return arrayOf( + arrayOf(ModuleException(DEBUG_MESSAGE, MESSAGE, IOException("URL http://foobar.com"))), + arrayOf(ModuleException(DEBUG_MESSAGE, MESSAGE, IOException("URL http://foobar.com?"))), + arrayOf(ModuleException(DEBUG_MESSAGE, MESSAGE)) + ) + } + + @Test(dataProvider = "dp") + fun testGetDebugMessage(e: ModuleException) { + assertThat(e::debugMessage).isEqualTo(DEBUG_MESSAGE) + } + + @Test(dataProvider = "dp") + fun testGetMessage(e: ModuleException) { + assertThat(e).hasMessage(MESSAGE) + } + + @Test + fun testSanitizeMessage() { + val apiKey = "1234567890" + var e = ModuleException(DEBUG_MESSAGE, MESSAGE, IOException("URL http://foo.com?apiKey=$apiKey&userID=me")) + assertThat( + e.sanitize(apiKey, "", "me").message, "ModuleException(debugMessage, message, IOException(url))" + ).isNotNull().all { + contains("xxxxxxxxxx", "userID=xx", "java.io.IOException") + doesNotContain(apiKey, "me") + } + + e = ModuleException(DEBUG_MESSAGE, MESSAGE, null) + assertThat(e.sanitize(apiKey), "ModuleException(debugMessage, message, null)").hasMessage(MESSAGE) + + e = ModuleException(DEBUG_MESSAGE, MESSAGE, IOException()) + assertThat(e.sanitize(apiKey), "ModuleException(debugMessage, message, IOException())").hasMessage(MESSAGE) + + e = ModuleException(DEBUG_MESSAGE, apiKey) + assertThat(e.sanitize(apiKey).message, "ModuleException(debugMessage, apiKey)").isNotNull() + .doesNotContain(apiKey) + + val msg: String? = null + e = ModuleException(DEBUG_MESSAGE, msg, IOException(msg)) + assertThat(e.sanitize(apiKey).message, "ModuleException(debugMessage, msg, IOException(msg))").isNull() + + e = ModuleException(DEBUG_MESSAGE, msg, IOException("foo is $apiKey")) + assertThat( + e.sanitize(" ", apiKey, "foo").message, + "ModuleException(debugMessage, msg, IOException(foo is $apiKey))" + ).isNotNull().all { + doesNotContain(apiKey) + endsWith("xxx is xxxxxxxxxx") + } + assertThat(e.sanitize(), "exception should be unchanged").isEqualTo(e) + } +} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/PingTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/PingTest.kt new file mode 100644 index 0000000..d1399e0 --- /dev/null +++ b/bin/test/net/thauvin/erik/mobibot/modules/PingTest.kt @@ -0,0 +1,54 @@ +/* + * PingTest.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.modules + +import assertk.assertThat +import assertk.assertions.contains +import assertk.assertions.isNotEmpty +import net.thauvin.erik.mobibot.modules.Ping.Companion.randomPing +import kotlin.test.Test + +/** + * The `PingTest` class. + */ +class PingTest { + @Test + fun testPingsArray() { + assertThat(Ping.PINGS, "Ping.PINGS").isNotEmpty() + } + + @Test + fun testRandomPing() { + for (i in 0..9) { + assertThat(Ping.PINGS, "Ping.PINGS[$i]").contains(randomPing()) + } + } +} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt new file mode 100644 index 0000000..f836b0e --- /dev/null +++ b/bin/test/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt @@ -0,0 +1,50 @@ +/* + * RockPaperScissorsTest.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.modules + +import assertk.assertThat +import assertk.assertions.isEqualTo +import net.thauvin.erik.mobibot.modules.RockPaperScissors.Companion.winLoseOrDraw +import kotlin.test.Test + +class RockPaperScissorsTest { + @Test + fun testWinLoseOrDraw() { + assertThat(winLoseOrDraw("scissors", "paper"), "scissors vs. paper").isEqualTo("win") + assertThat(winLoseOrDraw("paper", "rock"), "paper vs. rock").isEqualTo("win") + assertThat(winLoseOrDraw("rock", "scissors"), "rock vs. scissors").isEqualTo("win") + assertThat(winLoseOrDraw("paper", "scissors"), "paper vs. scissors").isEqualTo("lose") + assertThat(winLoseOrDraw("rock", "paper"), "rock vs. paper").isEqualTo("lose") + assertThat(winLoseOrDraw("scissors", "rock"), "scissors vs. rock").isEqualTo("lose") + assertThat(winLoseOrDraw("scissors", "scissors"), "scissors vs. scissors").isEqualTo("draw") + } +} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt new file mode 100644 index 0000000..d96812b --- /dev/null +++ b/bin/test/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt @@ -0,0 +1,85 @@ +/* + * StockQuoteTest.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.modules + +import assertk.all +import assertk.assertFailure +import assertk.assertThat +import assertk.assertions.* +import net.thauvin.erik.mobibot.ExceptionSanitizer.sanitize +import net.thauvin.erik.mobibot.LocalProperties +import net.thauvin.erik.mobibot.modules.StockQuote.Companion.getQuote +import net.thauvin.erik.mobibot.msg.ErrorMessage +import net.thauvin.erik.mobibot.msg.Message +import kotlin.test.Test + +/** + * The `StockQuoteTest` class. + */ +class StockQuoteTest : LocalProperties() { + private fun buildMatch(label: String): String { + return "${label}:[ ]+[0-9.]+".prependIndent() + } + + @Test + @Throws(ModuleException::class) + fun testGetQuote() { + val apiKey = getProperty(StockQuote.API_KEY_PROP) + try { + var symbol = "apple inc" + val messages = getQuote(symbol, apiKey) + assertThat(messages, "response not empty").isNotEmpty() + assertThat(messages, "getQuote($symbol)").index(0).prop(Message::msg).matches("Symbol: AAPL .*".toRegex()) + assertThat(messages, "getQuote($symbol)").index(1).prop(Message::msg).matches(buildMatch("Price").toRegex()) + assertThat(messages, "getQuote($symbol)").index(2).prop(Message::msg) + .matches(buildMatch("Previous").toRegex()) + assertThat(messages, "getQuote($symbol)").index(3).prop(Message::msg).matches(buildMatch("Open").toRegex()) + + symbol = "blahfoo" + assertThat(getQuote(symbol, apiKey).first(), "getQuote($symbol)").all { + isInstanceOf(ErrorMessage::class.java) + prop(Message::msg).isEqualTo(StockQuote.INVALID_SYMBOL) + } + assertThat(getQuote("", "apikey").first(), "getQuote(empty)").all { + isInstanceOf(ErrorMessage::class.java) + prop(Message::msg).isEqualTo(StockQuote.INVALID_SYMBOL) + } + assertFailure { getQuote("test", "") }.isInstanceOf(ModuleException::class.java).hasNoCause() + } catch (e: ModuleException) { + // Avoid displaying api keys in CI logs + if ("true" == System.getenv("CI")) { + throw e.sanitize(apiKey) + } else { + throw e + } + } + } +} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/Weather2Test.kt b/bin/test/net/thauvin/erik/mobibot/modules/Weather2Test.kt new file mode 100644 index 0000000..66f4d22 --- /dev/null +++ b/bin/test/net/thauvin/erik/mobibot/modules/Weather2Test.kt @@ -0,0 +1,117 @@ +/* + * Weather2Test.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.modules + +import assertk.all +import assertk.assertFailure +import assertk.assertThat +import assertk.assertions.* +import net.aksingh.owmjapis.api.APIException +import net.aksingh.owmjapis.core.OWM +import net.thauvin.erik.mobibot.LocalProperties +import net.thauvin.erik.mobibot.modules.Weather2.Companion.API_KEY_PROP +import net.thauvin.erik.mobibot.modules.Weather2.Companion.ftoC +import net.thauvin.erik.mobibot.modules.Weather2.Companion.getCountry +import net.thauvin.erik.mobibot.modules.Weather2.Companion.getWeather +import net.thauvin.erik.mobibot.modules.Weather2.Companion.mphToKmh +import net.thauvin.erik.mobibot.msg.Message +import kotlin.test.Test + +/** + * The `Weather2Test` class. + */ +class Weather2Test : LocalProperties() { + @Test + fun testFtoC() { + val t = ftoC(32.0) + assertThat(t.second, "32 °F is 0 °C").isEqualTo(0) + } + + @Test + fun testGetCountry() { + assertThat(getCountry("foo"), "foo is not a valid country").isEqualTo(OWM.Country.UNITED_STATES) + assertThat(getCountry("fr"), "country should France").isEqualTo(OWM.Country.FRANCE) + + val country = OWM.Country.entries.toTypedArray() + repeat(3) { + val rand = country[(country.indices).random()] + assertThat(getCountry(rand.value), rand.name).isEqualTo(rand) + } + } + + @Test + fun testMphToKmh() { + val w = mphToKmh(0.62) + assertThat(w.second, "0.62 mph is 1 km/h").isEqualTo(1) + } + + @Test + @Throws(ModuleException::class) + fun testWeather() { + var query = "98204" + var messages = getWeather(query, getProperty(API_KEY_PROP)) + assertThat(messages, "getWeather($query)").index(0).prop(Message::msg).all { + contains("Everett, United States") + contains("US") + } + assertThat(messages, "getWeather($query)").index(messages.size - 1).prop(Message::msg).endsWith("98204%2CUS") + + query = "San Francisco" + messages = getWeather(query, getProperty(API_KEY_PROP)) + assertThat(messages, "getWeather($query)").index(0).prop(Message::msg).all { + contains("San Francisco") + contains("US") + } + assertThat(messages, "getWeather($query)").index(messages.size - 1).prop(Message::msg).endsWith("5391959") + + query = "London, GB" + messages = getWeather(query, getProperty(API_KEY_PROP)) + assertThat(messages, "getWeather($query)").index(0).prop(Message::msg).all { + contains("London, United Kingdom") + contains("GB") + } + assertThat(messages, "getWeather($query)").index(messages.size - 1).prop(Message::msg).endsWith("2643743") + + try { + query = "Foo, US" + getWeather(query, getProperty(API_KEY_PROP)) + } catch (e: ModuleException) { + assertThat(e.cause, "getWeather($query)").isNotNull().isInstanceOf(APIException::class.java) + } + + query = "test" + assertFailure { getWeather(query, "") }.isInstanceOf(ModuleException::class.java).hasNoCause() + assertFailure { getWeather(query, null) }.isInstanceOf(ModuleException::class.java).hasNoCause() + + messages = getWeather("", "apikey") + assertThat(messages, "getWeather(empty)").index(0).prop(Message::isError).isTrue() + } +} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt new file mode 100644 index 0000000..855522c --- /dev/null +++ b/bin/test/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt @@ -0,0 +1,77 @@ +/* + * WolframAlphaTest.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.modules + +import assertk.assertFailure +import assertk.assertThat +import assertk.assertions.contains +import assertk.assertions.hasMessage +import assertk.assertions.isInstanceOf +import net.thauvin.erik.mobibot.ExceptionSanitizer.sanitize +import net.thauvin.erik.mobibot.LocalProperties +import net.thauvin.erik.mobibot.modules.WolframAlpha.Companion.queryWolfram +import kotlin.test.Test + +class WolframAlphaTest : LocalProperties() { + @Test + fun testAppId() { + assertFailure { queryWolfram("1 gallon to liter", appId = "DEMO") } + .isInstanceOf(ModuleException::class.java) + .hasMessage("Error 1: Invalid appid") + + assertFailure { queryWolfram("1 gallon to liter", appId = "") } + .isInstanceOf(ModuleException::class.java) + } + + @Test(groups = ["modules", "no-ci"]) + @Throws(ModuleException::class) + fun queryWolframTest() { + val apiKey = getProperty(WolframAlpha.APPID_KEY_PROP) + try { + var query = "SFO to SEA" + assertThat(queryWolfram(query, appId = apiKey), "queryWolfram($query)").contains("miles") + + query = "SFO to LAX" + assertThat( + queryWolfram(query, WolframAlpha.METRIC, apiKey), + "queryWolfram($query)" + ).contains("kilometers") + } catch (e: ModuleException) { + // Avoid displaying api key in CI logs + if ("true" == System.getenv("CI")) { + throw e.sanitize(apiKey) + } else { + throw e + } + } + } +} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/WordTimeTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/WordTimeTest.kt new file mode 100644 index 0000000..7931f33 --- /dev/null +++ b/bin/test/net/thauvin/erik/mobibot/modules/WordTimeTest.kt @@ -0,0 +1,70 @@ +/* + * WordTimeTest.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.modules + +import assertk.assertThat +import assertk.assertions.endsWith +import assertk.assertions.matches +import assertk.assertions.startsWith +import net.thauvin.erik.mobibot.Utils.bold +import net.thauvin.erik.mobibot.modules.WorldTime.Companion.BEATS_KEYWORD +import net.thauvin.erik.mobibot.modules.WorldTime.Companion.COUNTRIES_MAP +import net.thauvin.erik.mobibot.modules.WorldTime.Companion.time +import org.pircbotx.Colors +import kotlin.test.Test +import java.time.ZoneId + +/** + * The `WordTimeTest` class. + */ +class WordTimeTest { + @Test + fun testTime() { + assertThat(time(), "time()").matches( + ("The time is ${Colors.BOLD}\\d{1,2}:\\d{2}${Colors.BOLD} " + + "on ${Colors.BOLD}\\w+, \\d{1,2} \\w+ \\d{4}${Colors.BOLD} " + + "in ${Colors.BOLD}Los Angeles${Colors.BOLD}").toRegex() + ) + assertThat(time(""), "time()").endsWith("Los Angeles".bold()) + assertThat(time("PST"), "time(PST)").endsWith("Los Angeles".bold()) + assertThat(time("GB"), "time(GB)").endsWith("London".bold()) + assertThat(time("FR"), "time(FR)").endsWith("Paris".bold()) + assertThat(time("BLAH"), "time(BLAH)").startsWith("Unsupported") + assertThat(time("BEAT"), "time($BEATS_KEYWORD)").matches("[\\w ]+ .?@\\d{3}+.? .beats".toRegex()) + } + + @Test + fun testZones() { + COUNTRIES_MAP.filter { it.value != BEATS_KEYWORD }.forEach { + assertThat(ZoneId.of(it.value)) + } + } +} diff --git a/bin/test/net/thauvin/erik/mobibot/msg/MessageTest.kt b/bin/test/net/thauvin/erik/mobibot/msg/MessageTest.kt new file mode 100644 index 0000000..32a0495 --- /dev/null +++ b/bin/test/net/thauvin/erik/mobibot/msg/MessageTest.kt @@ -0,0 +1,109 @@ +/* + * MessageTest.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.msg + +import assertk.all +import assertk.assertThat +import assertk.assertions.isFalse +import assertk.assertions.isTrue +import assertk.assertions.prop +import kotlin.test.Test + +class MessageTest { + @Test + fun testConstructor() { + var msg = Message("foo") + + msg.isError = true + assertThat(msg.isNotice, "message is notice").isTrue() + + msg = Message("foo", isError = true) + assertThat(msg.isNotice, "message is notice too").isTrue() + } + + @Test + fun testErrorMessage() { + val msg = ErrorMessage("foo") + assertThat(msg).all { + prop(Message::isError).isTrue() + prop(Message::isNotice).isTrue() + prop(Message::isPrivate).isFalse() + } + } + + @Test + fun testIsError() { + val msg = Message("foo") + msg.isError = true + assertThat(msg).all { + prop(Message::isError).isTrue() + prop(Message::isNotice).isTrue() + prop(Message::isPrivate).isFalse() + } + msg.isError = false + assertThat(msg).all { + prop(Message::isError).isFalse() + prop(Message::isNotice).isTrue() + prop(Message::isPrivate).isFalse() + } + } + + @Test + fun testNoticeMessage() { + val msg = NoticeMessage("food") + assertThat(msg).all { + prop(Message::isError).isFalse() + prop(Message::isNotice).isTrue() + prop(Message::isPrivate).isFalse() + } + } + + @Test + fun testPrivateMessage() { + val msg = PrivateMessage("foo") + assertThat(msg).all { + prop(Message::isPrivate).isTrue() + prop(Message::isError).isFalse() + prop(Message::isNotice).isFalse() + } + } + + @Test + fun testPublicMessage() { + val msg = PublicMessage("foo") + assertThat(msg).all { + prop(Message::isError).isFalse() + prop(Message::isNotice).isFalse() + prop(Message::isPrivate).isFalse() + } + } +} diff --git a/bitbucket-pipelines.yml b/bitbucket-pipelines.yml index 623b3c3..7c85194 100644 --- a/bitbucket-pipelines.yml +++ b/bitbucket-pipelines.yml @@ -1,9 +1,10 @@ -image: maven:3-eclipse-temurin-17 +image: openjdk:17 pipelines: default: - step: - caches: - - gradle + name: Test with bld script: - - bash ./gradlew check + - ./bld download + - ./bld compile + - ./bld test diff --git a/bld b/bld new file mode 100755 index 0000000..77721d6 --- /dev/null +++ b/bld @@ -0,0 +1,2 @@ +#!/usr/bin/env sh +java -jar "$(dirname "$0")/lib/bld/bld-wrapper.jar" "$0" --build net.thauvin.erik.MobibotBuild "$@" \ No newline at end of file diff --git a/bld.bat b/bld.bat new file mode 100644 index 0000000..12ffa36 --- /dev/null +++ b/bld.bat @@ -0,0 +1,4 @@ +@echo off +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +java -jar "%DIRNAME%/lib/bld/bld-wrapper.jar" "%0" --build net.thauvin.erik.MobibotBuild %* \ No newline at end of file diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 6507e20..0000000 --- a/build.gradle +++ /dev/null @@ -1,247 +0,0 @@ -import java.time.LocalDateTime -import java.time.format.DateTimeFormatter -import io.gitlab.arturbosch.detekt.Detekt -import io.gitlab.arturbosch.detekt.DetektCreateBaselineTask - -plugins { - id 'application' - id 'com.github.ben-manes.versions' version '0.49.0' - id 'idea' - id 'io.gitlab.arturbosch.detekt' version '1.23.3' - id 'java' - id 'net.thauvin.erik.gradle.semver' version '1.0.4' - id 'org.jetbrains.kotlin.jvm' version '1.9.20' - id 'org.jetbrains.kotlin.kapt' version '1.9.20' - id 'org.jetbrains.kotlinx.kover' version '0.7.4' - id 'org.sonarqube' version '4.4.1.3373' - id 'pmd' -} - -defaultTasks 'deploy' - -final def packageName = 'net.thauvin.erik.mobibot' -final def deployDir = 'deploy' -final def semverProcessor = "net.thauvin.erik:semver:1.2.1" - -final def isCI = (System.getenv('CI') != null) - -def isNonStable = { String version -> - def stableKeyword = ['RELEASE', 'FINAL', 'GA', 'JRE'].any { it -> version.toUpperCase().contains(it) } - def regex = /^[0-9,.v-]+(-r)?$/ - return !stableKeyword && !(version ==~ regex) -} - -mainClassName = packageName + '.Mobibot' - -ext.versions = [ - log4j: '2.21.1', - pmd : '6.55.0', -] - -repositories { - mavenLocal() - mavenCentral() - maven { url 'https://jitpack.io' } - maven { url 'https://oss.sonatype.org/content/repositories/snapshots' } -} - -dependencies { - kapt(semverProcessor) - compileOnly(semverProcessor) - - // PircBotX - implementation 'com.github.pircbotx:pircbotx:2.3.1' - // implementation fileTree(dir: 'lib', include: '*.jar') - - // Commons (mostly for PircBotX) - implementation 'org.apache.commons:commons-lang3:3.13.0' - implementation 'org.apache.commons:commons-text:1.11.0' - implementation 'commons-codec:commons-codec:1.16.0' - implementation 'commons-net:commons-net:3.10.0' - - // Google - implementation 'com.google.code.gson:gson:2.10.1' - implementation 'com.google.guava:guava:32.1.3-jre' - - // Kotlin - implementation platform('org.jetbrains.kotlin:kotlin-bom') - implementation 'org.jetbrains.kotlin:kotlin-stdlib' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3' - implementation 'org.jetbrains.kotlinx:kotlinx-cli:0.3.6' - - // Logging - implementation 'org.slf4j:slf4j-api:2.0.9' - implementation "org.apache.logging.log4j:log4j-api:$versions.log4j" - implementation "org.apache.logging.log4j:log4j-core:$versions.log4j" - implementation "org.apache.logging.log4j:log4j-slf4j2-impl:$versions.log4j" - - implementation 'com.rometools:rome:2.1.0' - implementation 'com.squareup.okhttp3:okhttp:4.12.0' - implementation 'net.aksingh:owm-japis:2.5.3.0' - implementation 'net.objecthunter:exp4j:0.4.8' - implementation 'org.json:json:20231013' - implementation 'org.jsoup:jsoup:1.16.2' - - // Thauvin - implementation 'net.thauvin.erik:cryptoprice:1.0.1' - implementation 'net.thauvin.erik:jokeapi:0.9.0' - implementation 'net.thauvin.erik:pinboard-poster:1.1.0' - implementation 'net.thauvin.erik.urlencoder:urlencoder-lib:1.4.0' - - testImplementation 'com.willowtreeapps.assertk:assertk-jvm:0.27.0' -// testImplementation 'org.mockito.kotlin:mockito-kotlin:4.0.0' -// testImplementation "org.mockito:mockito-core:4.0.0" - testImplementation 'org.testng:testng:7.8.0' -} - -test { - useTestNG() { - // excludeGroups.add('twitter') - if (isCI) { - excludeGroups.add('no-ci') - } - if (!excludeGroups.isEmpty()) { - println "Excluded test groups: ${excludeGroups}" - } - } -} - -tasks.withType(Test).configureEach { - testLogging { - exceptionFormat = 'full' - events('skipped', 'failed') - } -} - -java { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 -} - -kotlin { - jvmToolchain { - languageVersion.set(JavaLanguageVersion.of(17)) - } -} - -kapt { - includeCompileClasspath = false - arguments { - arg('semver.project.dir', projectDir) - } -} - -tasks.withType(JavaCompile).configureEach { - options.encoding = 'UTF-8' -} - - -compileJava { - dependsOn 'incrementBuildMeta' - options.compilerArgs += ['-Xlint:unchecked', '-Xlint:deprecation'] -} - -tasks.named("dependencyUpdates").configure { - rejectVersionIf { - isNonStable(it.candidate.version) - } -} - -pmd { - toolVersion = versions.pmd - ignoreFailures = true - ruleSets = [] - ruleSetFiles = files("${projectDir}/config/pmd.xml") - consoleOutput = true -} - -detekt { - //toolVersion = "main-SNAPSHOT" - baseline = file("${projectDir}/config/detekt/baseline.xml") -} - -tasks.withType(Detekt).configureEach { - jvmTarget = java.targetCompatibility.toString() -} - -tasks.withType(DetektCreateBaselineTask).configureEach { - jvmTarget = java.targetCompatibility.toString() -} - -jar { - manifest.attributes('Main-Class': mainClassName, - 'Class-Path': '. ./lib/' + configurations.runtimeClasspath.collect { it.getName() }.join(' ./lib/')) - archiveVersion.set("") - exclude('log4j2.xml') -} - -clean { - doFirst { - project.delete(fileTree(deployDir)) - } -} - -run { - args('-h') -} - -incrementBuildMeta { - doFirst { - if (isCI) { - println 'No increment with CI.' - } else { - buildMeta = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now()) - } - } -} - -koverReport { - defaults { - xml { - onCheck = true - } - html { - onCheck = true - } - } -} - -sonarqube { - properties { - property('sonar.organization', 'ethauvin-github') - property('sonar.projectKey', 'ethauvin_mobibot') - property('sonar.host.url', 'https://sonarcloud.io') - property('sonar.coverage.jacoco.xmlReportPaths', "${layout.buildDirectory.get()}/reports/kover/report.xml") - } -} - -tasks.register('copyToDeploy', Copy) { - from('properties', jar) - into deployDir -} - -tasks.register('copyToDeployLib', Copy) { - from(configurations.runtimeClasspath) { - exclude 'annotations-*.jar' - } - into(deployDir + '/lib') -} - -tasks.register('deploy') { - description = "Copies all needed files to the ${deployDir} directory." - group = 'Publishing' - dependsOn(assemble, jar) - outputs.dir deployDir - inputs.files(copyToDeploy, copyToDeployLib) - doLast { - file(deployDir + '/logs').mkdir() - } - mustRunAfter(clean) -} - -tasks.register('release') { - group = 'Publishing' - description = 'Releases new version.' - dependsOn(clean, check, deploy) - mustRunAfter clean -} diff --git a/deploy.sh b/deploy.sh index ce3fde5..58dd32d 100755 --- a/deploy.sh +++ b/deploy.sh @@ -1,6 +1,6 @@ #!/bin/bash -./gradlew release +./bld jar deploy [ $? -eq 0 ] && sftp nix3.thauvin.us <nW$ZR+`W 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鯊%1Et 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⁢ zv5o9#E7!G0XmdzfsS{efPNi`1b44~SZ4Z8fuX!I}#8g+(wxzQwUT#Xb2(tbY1+EUhGKoT@KEU9Ktl>_0 z%bjDJg;#*gtJZv!-Zs`?^}v5eKmnbjqlvnSzE@_SP|LG_PJ6CYU+6zY6>92%E+ z=j@TZf-iW4(%U{lnYxQA;7Q!b;^brF8n0D>)`q5>|WDDXLrqYU_tKN2>=#@~OE7grMnNh?UOz-O~6 z6%rHy{#h9K0AT+lDC7q4{hw^|q6*Ry;;L%Q@)Ga}$60_q%D)rv(CtS$CQbpq9|y1e zRSrN4;$Jyl{m5bZw`$8TGvb}(LpY{-cQ)fcyJv7l3S52TLXVDsphtv&aPuDk1OzCA z4A^QtC(!11`IsNx_HnSy?>EKpHJWT^wmS~hc^p^zIIh@9f6U@I2 zC=Mve{j2^)mS#U$e{@Q?SO6%LDsXz@SY+=cK_QMmXBIU)j!$ajc-zLx3V60EXJ!qC zi<%2x8Q24YN+&8U@CIlN zrZkcT9yh%LrlGS9`G)KdP(@9Eo-AQz@8GEFWcb7U=a0H^ZVbLmz{+&M7W(nXJ4sN8 zJLR7eeK(K8`2-}j(T7JsO`L!+CvbueT%izanm-^A1Dn{`1Nw`9P?cq;7no+XfC`K(GO9?O^5zNIt4M+M8LM0=7Gz8UA@Z0N+lg+cX)NfazRu z5D)~HA^(u%w^cz+@2@_#S|u>GpB+j4KzQ^&Wcl9f z&hG#bCA(Yk0D&t&aJE^xME^&E-&xGHhXn%}psEIj641H+Nl-}boj;)Zt*t(4wZ5DN z@GXF$bL=&pBq-#vkTkh>7hl%K5|3 z{`Vn9b$iR-SoGENp}bn4;fR3>9sA%X2@1L3aE9yTra;Wb#_`xWwLSLdfu+PAu+o3| zGVnpzPr=ch{uuoHjtw7+_!L_2;knQ!DuDl0R`|%jr+}jFzXtrHIKc323?JO{l&;VF z*L1+}JU7%QJOg|5|Tc|D8fN zJORAg=_vsy{ak|o);@)Yh8Lkcg@$FG3k@ep36BRa^>~UmnRPziS>Z=`Jb2x*Q#`%A zU*i3&Vg?TluO@X0O;r2Jl6LKLUOVhSqg1*qOt^|8*c7 zo(298@+r$k_wQNGHv{|$tW(T8L+4_`FQ{kEW5Jgg{yf7ey4ss_(SNKfz(N9lx&a;< je(UuV8hP?p&}TPdm1I$XmG#(RzlD&B2izSj9sl%y5~4qc diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 3fa8f86..0000000 --- a/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew deleted file mode 100755 index 1aa94a4..0000000 --- a/gradlew +++ /dev/null @@ -1,249 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# 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 -# -# https://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. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, -# and any embedded shellness will be escaped. -# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be -# treated as '${Hostname}' itself on the command line. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat deleted file mode 100644 index 93e3f59..0000000 --- a/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/lib/bld/bld-wrapper.jar b/lib/bld/bld-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..d17ad8982355ae5516129c6b07841609641eb492 GIT binary patch literal 27321 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 Kus>-qu>S(PSAA^& literal 0 HcmV?d00001 diff --git a/lib/bld/bld-wrapper.properties b/lib/bld/bld-wrapper.properties new file mode 100644 index 0000000..8375666 --- /dev/null +++ b/lib/bld/bld-wrapper.properties @@ -0,0 +1,10 @@ +bld.downloadExtensionJavadoc=false +bld.downloadExtensionSources=true +bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.1 +bld.extensions=com.uwyn.rife2:bld-generated-version:0.9.3-SNAPSHOT +bld.extensions-kotlin=com.uwyn.rife2:bld-kotlin:0.9.0-SNAPSHOT +bld.extensions-pmd=com.uwyn.rife2:bld-testng:0.9.2 +bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES +bld.downloadLocation= +bld.sourceDirectories= +bld.version=1.7.5 diff --git a/release_info.txt b/release_info.txt new file mode 100644 index 0000000..f5efde2 --- /dev/null +++ b/release_info.txt @@ -0,0 +1,27 @@ +/* + * This file is automatically generated + * Do not modify! -- ALL CHANGES WILL BE ERASED! + */ + +package {{v packageName/}} + +import java.time.Instant +import java.time.LocalDateTime +import java.time.ZoneId + +/** + * Provides release information. + */ +object {{v className/}} { + const val PROJECT = "{{v project/}}" + const val VERSION = "{{v version/}}" + + @JvmField + val BUILD_DATE: LocalDateTime = LocalDateTime.ofInstant( + Instant.ofEpochMilli({{v epoch/}}L), ZoneId.systemDefault() + ) + + const val WEBSITE = "https://www.mobitopia.org/mobibot/" + const val AUTHOR = "Erik C. Thauvin" + const val AUTHOR_URL = "https://erik.thauvin.net/" +} diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index 53bc4db..0000000 --- a/settings.gradle +++ /dev/null @@ -1,18 +0,0 @@ -plugins { - id "com.gradle.enterprise" version "3.6.3" -} - -gradleEnterprise { - buildScan { - link("GitHub", "https://github.com/ethauvin/pinboard-poster/tree/master") - if (System.getenv("CI")) { - uploadInBackground = false - publishOnFailure() - tag "CI" - } - termsOfServiceUrl = "https://gradle.com/terms-of-service" - termsOfServiceAgree = "yes" - } -} - -rootProject.name = 'mobibot' diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 0000000..85d8fce --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,7 @@ +sonar.organization=ethauvin-github +sonar.projectKey=ethauvin_mobibot +sonar.coverage.jacoco.xmlReportPaths=build/reports/jacoco/test/jacocoTestReport.xml +sonar.sources=src/main/kotlin/ +sonar.tests=src/test/kotlin/ +sonar.java.binaries=build/main,build/test +sonar.java.libraries=lib/compile/*.jar diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java new file mode 100644 index 0000000..9b6b32a --- /dev/null +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -0,0 +1,170 @@ +/* + * MobibotBuild.java + * + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik; + +import rife.bld.BuildCommand; +import rife.bld.Project; +import rife.bld.dependencies.Repository; +import rife.bld.extension.CompileKotlinOperation; +import rife.bld.extension.CompileKotlinOptions; +import rife.bld.extension.GeneratedVersionOperation; +import rife.bld.extension.JacocoReportOperation; +import rife.tools.FileUtils; +import rife.tools.exceptions.FileUtilsErrorException; + +import java.io.File; +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; +import java.util.jar.Attributes; + +import static rife.bld.dependencies.Repository.MAVEN_CENTRAL; +import static rife.bld.dependencies.Repository.MAVEN_LOCAL; +import static rife.bld.dependencies.Scope.compile; +import static rife.bld.dependencies.Scope.test; + +public class MobibotBuild extends Project { + public MobibotBuild() { + pkg = "net.thauvin.erik.mobibot"; + name = "mobibot"; + version = version(0, 8, 0, "rc+" + + DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now())); + + mainClass = pkg + ".Mobibot"; + + javaRelease = 17; + downloadSources = true; + autoDownloadPurge = true; + repositories = List.of(MAVEN_LOCAL, MAVEN_CENTRAL, new Repository("https://jitpack.io")); + + var log4j = version(2, 21, 1); + scope(compile) + // PircBotX + .include(dependency("com.github.pircbotx", "pircbotx", "2.3.1")) + // Commons (mostly for PircBotX) + .include(dependency("org.apache.commons", "commons-lang3", "3.13.0")) + .include(dependency("org.apache.commons", "commons-text", "1.11.0")) + .include(dependency("commons-codec", "commons-codec", "1.16.0")) + .include(dependency("commons-net", "commons-net", "3.10.0")) + // Google + .include(dependency("com.google.code.gson", "gson", "2.10.1")) + .include(dependency("com.google.guava", "guava", "32.1.3-jre")) + // Kotlin + .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", version(1, 9, 20))) + .include(dependency("org.jetbrains.kotlinx", "kotlinx-coroutines-core", "1.7.3")) + .include(dependency("org.jetbrains.kotlinx", "kotlinx-cli-jvm", "0.3.6")) + // Logging + .include(dependency("org.slf4j", "slf4j-api", "2.0.9")) + .include(dependency("org.apache.logging.log4j", "log4j-api", log4j)) + .include(dependency("org.apache.logging.log4j", "log4j-core", log4j)) + .include(dependency("org.apache.logging.log4j", "log4j-slf4j2-impl", log4j)) + .include(dependency("com.rometools", "rome", "2.1.0")) + .include(dependency("com.squareup.okhttp3", "okhttp", "4.12.0")) + .include(dependency("net.aksingh", "owm-japis", "2.5.3.0")) + .include(dependency("net.objecthunter", "exp4j", "0.4.8")) + .include(dependency("org.json", "json", "20231013")) + .include(dependency("org.jsoup", "jsoup", "1.16.2")) + // Thauvin + .include(dependency("net.thauvin.erik", "cryptoprice", "1.0.1")) + .include(dependency("net.thauvin.erik", "jokeapi", "0.9.0")) + .include(dependency("net.thauvin.erik", "pinboard-poster", "1.1.0")) + .include(dependency("net.thauvin.erik.urlencoder", "urlencoder-lib-jvm", "1.4.0")); + scope(test) + .include(dependency("com.willowtreeapps.assertk", "assertk-jvm", version(0, 27, 0))) + .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", version(1, 9, 20))) + .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 10, 1))) + .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 10, 1))); + + List jars = new ArrayList<>(); + compileClasspathJars().forEach(f -> jars.add("./lib/" + f.getName())); + jarOperation() + .manifestAttribute(Attributes.Name.MAIN_CLASS, mainClass()) + .manifestAttribute(Attributes.Name.CLASS_PATH, ". " + String.join(" ", jars)); + + jarSourcesOperation().sourceDirectories(new File(srcMainDirectory(), "kotlin")); + } + + public static void main(String[] args) { + new MobibotBuild().start(args); + } + + @Override + public void clean() throws Exception { + FileUtils.deleteDirectory(new File("deploy")); + super.clean(); + } + + @BuildCommand(summary = "Compiles the Kotlin project") + @Override + public void compile() throws Exception { + releaseInfo(); + new CompileKotlinOperation() + .fromProject(this) + .compileOptions( + new CompileKotlinOptions() + .jdkRelease(javaRelease) + .verbose(true) + ) + .execute(); + } + + @BuildCommand(summary = "Copies all needed files to the deploy directory") + public void deploy() throws FileUtilsErrorException { + var deploy = new File("deploy"); + var lib = new File(deploy, "lib"); + var ignore = lib.mkdirs(); + FileUtils.copyDirectory(new File("properties"), deploy); + FileUtils.copyDirectory(libCompileDirectory(), lib); + FileUtils.copy(new File(buildDistDirectory(), jarFileName()), new File(deploy, "mobibot.jar")); + } + + @BuildCommand(summary = "Generates JaCoCo Reports") + public void jacoco() throws IOException { + new JacocoReportOperation() + .fromProject(this) + .execute(); + } + + @BuildCommand(value = "release-info", summary = "Generates the ReleaseInfo class") + public void releaseInfo() { + new GeneratedVersionOperation() + .fromProject(this) + .classTemplate(new File(workDirectory(), "release-info.txt")) + .className("ReleaseInfo") + .packageName(pkg) + .directory(new File(srcMainDirectory(), "kotlin")) + .extension(".kt") + .execute(); + } +} diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/War.java b/src/main/java/net/thauvin/erik/mobibot/modules/War.java deleted file mode 100644 index 4bbbd9b..0000000 --- a/src/main/java/net/thauvin/erik/mobibot/modules/War.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * War.java - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.modules; - -import net.thauvin.erik.mobibot.Utils; -import org.jetbrains.annotations.NotNull; -import org.pircbotx.hooks.types.GenericMessageEvent; - -import java.security.SecureRandom; - -import static net.thauvin.erik.mobibot.Utils.bold; - -/** - * The War module. - * - * @author Erik C. Thauvin - * @since 1.0 - */ -public final class War extends AbstractModule { - private static final String[] CLUBS = - {"🃑", "🃞", "🃝", "🃛", "🃚", "🃙", "🃘", "🃗", "🃖", "🃕", "🃔", "🃓", "🃒"}; - private static final String[] DIAMONDS = - {"🃁", "🃎", "🃍", "🃋", "🃊", "🃉", "🃈", "🃇", "🃆", "🃅", "🃄", "🃃", "🃂"}; - private static final String[] HEARTS = - {"🂱", "🂾", "🂽", "🂻", "🂺", "🂹", "🂸", "🂷", "🂶", "🂵", "🂴", "🂳", "🂲"}; - // Random - private static final SecureRandom RANDOM = new SecureRandom(); - private static final String[] SPADES = - {"🂡", "🂮", "🂭", "🂫", "🂪", "🂩", "🂨", "🂧", "🂦", "🂥", "🂤", "🂣", "🂢"}; - private static final String[][] DECK = {HEARTS, SPADES, DIAMONDS, CLUBS}; - // War command - private static final String WAR_CMD = "war"; - - /** - * The default constructor. - */ - public War() { - super(); - - commands.add(WAR_CMD); - - help.add("To play war:"); - help.add(Utils.helpFormat("%c " + WAR_CMD)); - } - - @NotNull - @Override - public String getName() { - return "War"; - } - - /** - * {@inheritDoc} - */ - @Override - public void commandResponse(@NotNull final String channel, @NotNull final String cmd, @NotNull final String args, - @NotNull final GenericMessageEvent event) { - int i; - int y; - - do { - i = RANDOM.nextInt(HEARTS.length); - y = RANDOM.nextInt(HEARTS.length); - - final String result; - if (i < y) { - result = bold("win"); - } else if (i > y) { - result = bold("lose"); - } else { - result = bold("tie") + ". This means " + bold("WAR"); - } - - event.respond(DECK[RANDOM.nextInt(DECK.length)][i] + " " + DECK[RANDOM.nextInt(DECK.length)][y] + - " » You " + result + '!'); - - } while (i == y); - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt index 2c5f05d..c6f16cb 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt @@ -1,7 +1,7 @@ /* * Addons.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt index 98ef74a..ea89f4c 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt @@ -1,7 +1,7 @@ /* * Constants.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt b/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt index d82f011..371b523 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt @@ -1,7 +1,7 @@ /* * FeedReader.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt index f91c457..47dd7c2 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt @@ -1,7 +1,7 @@ /* * Mobibot.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -51,7 +51,6 @@ import net.thauvin.erik.mobibot.commands.links.* import net.thauvin.erik.mobibot.commands.seen.Seen import net.thauvin.erik.mobibot.commands.tell.Tell import net.thauvin.erik.mobibot.modules.* -import net.thauvin.erik.semver.Version import org.pircbotx.Configuration import org.pircbotx.PircBotX import org.pircbotx.hooks.ListenerAdapter @@ -66,7 +65,6 @@ import java.util.* import java.util.regex.Pattern import kotlin.system.exitProcess -@Version(properties = "version.properties", className = "ReleaseInfo", template = "version.mustache", type = "kt") class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Properties) : ListenerAdapter() { // The bot configuration. private val config: Configuration @@ -257,7 +255,7 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro // Output the version println( "${ReleaseInfo.PROJECT.capitalise()} ${ReleaseInfo.VERSION}" + - " (${ReleaseInfo.BUILDDATE.toIsoLocalDate()})" + " (${ReleaseInfo.BUILD_DATE.toIsoLocalDate()})" ) println(ReleaseInfo.WEBSITE) } else { diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt index 7cb5aed..ac01b0a 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt @@ -1,7 +1,7 @@ /* * Pinboard.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt b/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt new file mode 100644 index 0000000..88634ae --- /dev/null +++ b/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt @@ -0,0 +1,27 @@ +/* + * This file is automatically generated + * Do not modify! -- ALL CHANGES WILL BE ERASED! + */ + +package net.thauvin.erik.mobibot + +import java.time.Instant +import java.time.LocalDateTime +import java.time.ZoneId + +/** + * Provides release information. + */ +object ReleaseInfo { + const val PROJECT = "mobibot" + const val VERSION = "0.8.0-rc+20231110234054" + + @JvmField + val BUILD_DATE: LocalDateTime = LocalDateTime.ofInstant( + Instant.ofEpochMilli(1699688454937L), ZoneId.systemDefault() + ) + + const val WEBSITE = "https://www.mobitopia.org/mobibot/" + const val AUTHOR = "Erik C. Thauvin" + const val AUTHOR_URL = "https://erik.thauvin.net/" +} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt index e4760d2..d69c0c5 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt @@ -1,7 +1,7 @@ /* * Utils.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/AbstractCommand.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/AbstractCommand.kt index 5f79472..e0b091a 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/AbstractCommand.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/AbstractCommand.kt @@ -1,7 +1,7 @@ /* * AbstractCommand.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/ChannelFeed.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/ChannelFeed.kt index 038e378..9084660 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/ChannelFeed.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/ChannelFeed.kt @@ -1,7 +1,7 @@ /* * ChannelFeed.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Cycle.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Cycle.kt index 9608ca8..18a8b1d 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Cycle.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Cycle.kt @@ -1,7 +1,7 @@ /* * Cycle.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Die.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Die.kt index f271bfa..c1708a9 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Die.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Die.kt @@ -1,7 +1,7 @@ /* * Die.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt index d083c10..8d2b154 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt @@ -1,7 +1,7 @@ /* * Ignore.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Info.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Info.kt index ed0b6ef..8ee8c4f 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Info.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Info.kt @@ -1,7 +1,7 @@ /* * Info.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Me.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Me.kt index ec7823b..f2a13ba 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Me.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Me.kt @@ -1,7 +1,7 @@ /* * Me.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Modules.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Modules.kt index b2293b0..1aaefd7 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Modules.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Modules.kt @@ -1,7 +1,7 @@ /* * Modules.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Msg.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Msg.kt index 20a6635..0f492c9 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Msg.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Msg.kt @@ -1,7 +1,7 @@ /* * Msg.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Nick.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Nick.kt index 85a03ab..41b2c4b 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Nick.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Nick.kt @@ -1,7 +1,7 @@ /* * Nick.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Recap.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Recap.kt index 77154c7..0159017 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Recap.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Recap.kt @@ -1,7 +1,7 @@ /* * Recap.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Say.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Say.kt index 7f76d35..1f89982 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Say.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Say.kt @@ -1,7 +1,7 @@ /* * Say.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Users.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Users.kt index 33d6fef..4a881a7 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Users.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Users.kt @@ -1,7 +1,7 @@ /* * Users.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Versions.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Versions.kt index 896c569..a8300f0 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Versions.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Versions.kt @@ -1,7 +1,7 @@ /* * Versions.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -40,7 +40,7 @@ import org.pircbotx.hooks.types.GenericMessageEvent class Versions : AbstractCommand() { private val allVersions = listOf( - "Version: ${ReleaseInfo.VERSION} (${ReleaseInfo.BUILDDATE.toIsoLocalDate()})", + "Version: ${ReleaseInfo.VERSION} (${ReleaseInfo.BUILD_DATE.toIsoLocalDate()})", "${System.getProperty("os.name")} ${System.getProperty("os.version")} (${System.getProperty("os.arch")})" + ", JVM ${System.getProperty("java.runtime.version")}", "Kotlin ${KotlinVersion.CURRENT}, PircBotX ${PircBotX.VERSION}" diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Comment.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Comment.kt index 1443d44..90d8bb3 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Comment.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Comment.kt @@ -1,7 +1,7 @@ /* * Comment.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManager.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManager.kt index fba6b99..2d7add6 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManager.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManager.kt @@ -1,7 +1,7 @@ /* * LinksManager.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Posting.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Posting.kt index ff4278d..dca99cf 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Posting.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Posting.kt @@ -1,7 +1,7 @@ /* * Posting.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Tags.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Tags.kt index 1662857..c59cad9 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Tags.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Tags.kt @@ -1,7 +1,7 @@ /* * Tags.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/View.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/View.kt index 825e374..1626a58 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/View.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/View.kt @@ -1,7 +1,7 @@ /* * View.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt index cfd2c27..2a3856b 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt @@ -1,7 +1,7 @@ /* * NickComparator.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt index c9ee0f3..83083fd 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt @@ -1,7 +1,7 @@ /* * Seen.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt index 7924977..1445f9f 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt @@ -1,7 +1,7 @@ /* * SeenNick.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt index 061ca6a..e9d18ae 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt @@ -1,7 +1,7 @@ /* * Tell.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellManager.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellManager.kt index b65a4da..229bc5f 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellManager.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellManager.kt @@ -1,7 +1,7 @@ /* * TellManager.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt index d17fbb5..cc48d59 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt @@ -1,7 +1,7 @@ /* * TellMessage.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/Entries.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/Entries.kt index e8676ec..15506e0 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/Entries.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/Entries.kt @@ -1,7 +1,7 @@ /* * Entries.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt index 9c09626..6e58fd9 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt @@ -1,7 +1,7 @@ /* * EntriesUtils.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryComment.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryComment.kt index e18d692..c0cc2a8 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryComment.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryComment.kt @@ -1,7 +1,7 @@ /* * EntryComment.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt index 4a69446..8098bbf 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt @@ -1,7 +1,7 @@ /* * EntryLink.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt index f786cb2..e7017ab 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt @@ -1,7 +1,7 @@ /* * FeedsManager.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/AbstractModule.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/AbstractModule.kt index 8c8e736..8dcf6d8 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/AbstractModule.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/AbstractModule.kt @@ -1,7 +1,7 @@ /* * AbstractModule.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Calc.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Calc.kt index b7aae28..9003783 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Calc.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Calc.kt @@ -1,7 +1,7 @@ /* * Calc.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt index bd92332..09791a8 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt @@ -1,7 +1,7 @@ /* * ChatGpt.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt index d14056e..4464732 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt @@ -1,7 +1,7 @@ /* * CryptoPrices.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -120,7 +120,7 @@ class CryptoPrices : AbstractModule() { } /** - * Loads the Fiat currencies.. + * Loads the Fiat currencies. */ @JvmStatic @Throws(ModuleException::class) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt index da0efd8..954f4d1 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt @@ -1,7 +1,7 @@ /* * CurrencyConverter.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Dice.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Dice.kt index 8420fb1..84f2280 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Dice.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Dice.kt @@ -1,7 +1,7 @@ /* * Dice.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt index f426d1e..a9b15a5 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt @@ -1,7 +1,7 @@ /* * GoogleSearch.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Joke.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Joke.kt index 2760fa7..91b9ad2 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Joke.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Joke.kt @@ -1,7 +1,7 @@ /* * Joke.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Lookup.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Lookup.kt index 9ab2ead..eecc55e 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Lookup.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Lookup.kt @@ -1,7 +1,7 @@ /* * Lookup.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Mastodon.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Mastodon.kt index 3be3a5f..1141c0e 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Mastodon.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Mastodon.kt @@ -1,7 +1,7 @@ /* * Mastodon.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ModuleException.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ModuleException.kt index a7416c2..9a0e641 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ModuleException.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ModuleException.kt @@ -1,7 +1,7 @@ /* * ModuleException.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Ping.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Ping.kt index 944dbc1..86b311a 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Ping.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Ping.kt @@ -1,7 +1,7 @@ /* * Ping.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt index a299d8d..d224568 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt @@ -1,7 +1,7 @@ /* * RockPaperScissors.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt index dcae5e7..6b591cd 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt @@ -1,7 +1,7 @@ /* * StockQuote.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/War.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/War.kt new file mode 100644 index 0000000..0c64465 --- /dev/null +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/War.kt @@ -0,0 +1,89 @@ +/* + * War.kt + * + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.modules + +import net.thauvin.erik.mobibot.Utils.bold +import net.thauvin.erik.mobibot.Utils.helpFormat +import org.pircbotx.hooks.types.GenericMessageEvent +import java.security.SecureRandom + +/** + * The War module. + * + * @author [Erik C. Thauvin](https://erik.thauvin.net/) + * @since 1.0 + */ +class War : AbstractModule() { + override val name = "War" + + override fun commandResponse( + channel: String, cmd: String, args: String, + event: GenericMessageEvent + ) { + var i: Int + var y: Int + do { + i = RANDOM.nextInt(HEARTS.size) + y = RANDOM.nextInt(HEARTS.size) + val result: String = if (i < y) { + "win".bold() + } else if (i > y) { + "lose".bold() + } else { + "tie".bold() + ". This means " + "WAR".bold() + } + event.respond( + DECK[RANDOM.nextInt(DECK.size)][i] + " " + DECK[RANDOM.nextInt(DECK.size)][y] + + " » You " + result + '!' + ) + } while (i == y) + } + + companion object { + private val CLUBS = arrayOf("🃑", "🃞", "🃝", "🃛", "🃚", "🃙", "🃘", "🃗", "🃖", "🃕", "🃔", "🃓", "🃒") + private val DIAMONDS = arrayOf("🃁", "🃎", "🃍", "🃋", "🃊", "🃉", "🃈", "🃇", "🃆", "🃅", "🃄", "🃃", "🃂") + private val HEARTS = arrayOf("🂱", "🂾", "🂽", "🂻", "🂺", "🂹", "🂸", "🂷", "🂶", "🂵", "🂴", "🂳", "🂲") + + // Random + private val RANDOM = SecureRandom() + private val SPADES = arrayOf("🂡", "🂮", "🂭", "🂫", "🂪", "🂩", "🂨", "🂧", "🂦", "🂥", "🂤", "🂣", "🂢") + private val DECK = arrayOf(HEARTS, SPADES, DIAMONDS, CLUBS) + + // War command + private const val WAR_CMD = "war" + } + + init { + commands.add(WAR_CMD) + help.add("To play war:") + help.add(helpFormat("%c $WAR_CMD")) + } +} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt index 80a06fa..83eba95 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt @@ -1,7 +1,7 @@ /* * Weather2.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt index a72efab..8d9c4e6 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt @@ -1,7 +1,7 @@ /* * WolframAlpha.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WorldTime.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WorldTime.kt index 18072bc..0c379b3 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WorldTime.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WorldTime.kt @@ -1,7 +1,7 @@ /* * WorldTime.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/ErrorMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/ErrorMessage.kt index 0607936..b9f5212 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/ErrorMessage.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/msg/ErrorMessage.kt @@ -1,7 +1,7 @@ /* * ErrorMessage.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/Message.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/Message.kt index 23a33b9..84e3a1e 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/Message.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/msg/Message.kt @@ -1,7 +1,7 @@ /* * Message.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -30,8 +30,6 @@ */ package net.thauvin.erik.mobibot.msg -import net.thauvin.erik.semver.Constants - /** * The `Message` class. */ @@ -43,7 +41,7 @@ open class Message @JvmOverloads constructor( var isPrivate: Boolean = false ) { companion object { - var DEFAULT_COLOR = Constants.EMPTY + var DEFAULT_COLOR = "" } init { diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/NoticeMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/NoticeMessage.kt index 037d504..2be52aa 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/NoticeMessage.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/msg/NoticeMessage.kt @@ -1,7 +1,7 @@ /* * NoticeMessage.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/PrivateMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/PrivateMessage.kt index b424fdf..8d34d28 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/PrivateMessage.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/msg/PrivateMessage.kt @@ -1,7 +1,7 @@ /* * PrivateMessage.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/PublicMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/PublicMessage.kt index 9c5e088..9e67ecb 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/PublicMessage.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/msg/PublicMessage.kt @@ -1,7 +1,7 @@ /* * PublicMessage.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialManager.kt b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialManager.kt index 91f2dd9..3fb3874 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialManager.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialManager.kt @@ -1,7 +1,7 @@ /* * SocialManager.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialModule.kt b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialModule.kt index b594670..47a33d9 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialModule.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialModule.kt @@ -1,7 +1,7 @@ /* * SocialModule.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialTimer.kt b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialTimer.kt index 3fd315e..e779a3c 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialTimer.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialTimer.kt @@ -1,7 +1,7 @@ /* * SocialTimer.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml new file mode 100644 index 0000000..16644cc --- /dev/null +++ b/src/main/resources/log4j2.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt index 3241bf0..7f65548 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt @@ -1,7 +1,7 @@ /* * AddonsTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -42,8 +42,8 @@ import net.thauvin.erik.mobibot.commands.Ignore import net.thauvin.erik.mobibot.commands.links.Comment import net.thauvin.erik.mobibot.commands.links.View import net.thauvin.erik.mobibot.modules.* -import org.testng.annotations.Test import java.util.* +import kotlin.test.Test class AddonsTest { private val p = Properties().apply { diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCi.kt b/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCi.kt new file mode 100644 index 0000000..01d98ca --- /dev/null +++ b/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCi.kt @@ -0,0 +1,44 @@ +/* + * DisableOnCi.kt + * + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot + +import org.junit.jupiter.api.extension.ExtendWith + +/** + * Disables tests on CI annotation. + * + * @author [Erik C. Thauvin](https://erik.thauvin.net/) + * @since 1.0 + */ +@Target(AnnotationTarget.TYPE, AnnotationTarget.FUNCTION) +@Retention(AnnotationRetention.RUNTIME) +@ExtendWith(DisableOnCiCondition::class) +annotation class DisabledOnCi diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCiCondition.kt b/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCiCondition.kt new file mode 100644 index 0000000..24f1ca0 --- /dev/null +++ b/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCiCondition.kt @@ -0,0 +1,51 @@ +/* + * DisableOnCiCondition.kt + * + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot + +import org.junit.jupiter.api.extension.ConditionEvaluationResult +import org.junit.jupiter.api.extension.ExecutionCondition +import org.junit.jupiter.api.extension.ExtensionContext + +/** + * Disables tests on CI condition. + * + * @author [Erik C. Thauvin](https://erik.thauvin.net/) + * @since 1.0 + */ +class DisableOnCiCondition : ExecutionCondition { + override fun evaluateExecutionCondition(context: ExtensionContext): ConditionEvaluationResult { + return if (System.getenv("CI") != null) { + ConditionEvaluationResult.disabled("Test disabled on CI") + } else { + ConditionEvaluationResult.enabled("Test enabled") + } + } +} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/ExceptionSanitizer.kt b/src/test/kotlin/net/thauvin/erik/mobibot/ExceptionSanitizer.kt index a3994ec..b02188e 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/ExceptionSanitizer.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/ExceptionSanitizer.kt @@ -1,7 +1,7 @@ /* * ExceptionSanitizer.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt index 78f5b18..cfc3d4e 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt @@ -1,7 +1,7 @@ /* * FeedReaderTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -37,10 +37,10 @@ import assertk.assertions.* import com.rometools.rome.io.FeedException import net.thauvin.erik.mobibot.FeedReader.Companion.readFeed import net.thauvin.erik.mobibot.msg.Message -import org.testng.annotations.Test import java.io.IOException import java.net.MalformedURLException import java.net.UnknownHostException +import kotlin.test.Test /** * The `FeedReader Test` class. diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/LocalProperties.kt b/src/test/kotlin/net/thauvin/erik/mobibot/LocalProperties.kt index 1384a72..95b6c08 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/LocalProperties.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/LocalProperties.kt @@ -1,7 +1,7 @@ /* * LocalProperties.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -30,7 +30,6 @@ */ package net.thauvin.erik.mobibot -import org.testng.annotations.BeforeSuite import java.io.IOException import java.net.InetAddress import java.net.UnknownHostException @@ -42,8 +41,7 @@ import java.util.* * Access to `local.properties`. */ open class LocalProperties { - @BeforeSuite(alwaysRun = true) - fun loadProperties() { + init { val localPath = Paths.get("local.properties") if (Files.exists(localPath)) { try { diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/PinboardTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/PinboardTest.kt index 87617e8..cf9d59a 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/PinboardTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/PinboardTest.kt @@ -1,7 +1,7 @@ /* * PinboardTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -34,10 +34,10 @@ package net.thauvin.erik.mobibot import net.thauvin.erik.mobibot.Utils.encodeUrl import net.thauvin.erik.mobibot.Utils.reader import net.thauvin.erik.mobibot.entries.EntryLink -import org.testng.Assert.assertFalse -import org.testng.Assert.assertTrue -import org.testng.annotations.Test import java.net.URL +import kotlin.test.Test +import kotlin.test.assertFalse +import kotlin.test.assertTrue class PinboardTest : LocalProperties() { private val pinboard = Pinboard() diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt index 7a3f5d2..a024cff 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt @@ -1,7 +1,7 @@ /* * UtilsTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -59,14 +59,14 @@ import net.thauvin.erik.mobibot.Utils.today import net.thauvin.erik.mobibot.Utils.underline import net.thauvin.erik.mobibot.Utils.unescapeXml import net.thauvin.erik.mobibot.msg.Message.Companion.DEFAULT_COLOR +import org.junit.jupiter.api.BeforeEach import org.pircbotx.Colors -import org.testng.annotations.BeforeClass -import org.testng.annotations.Test import java.io.File import java.io.IOException import java.net.URL import java.time.LocalDateTime import java.util.* +import kotlin.test.Test /** * The `Utils Test` class. @@ -78,7 +78,7 @@ class UtilsTest { private val localDateTime = LocalDateTime.of(1952, 2, 17, 12, 30, 0) private val test = "This is a test." - @BeforeClass + @BeforeEach fun setUp() { cal[1952, Calendar.FEBRUARY, 17, 12, 30] = 0 } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/InfoTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/InfoTest.kt index 265009b..33a411f 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/InfoTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/InfoTest.kt @@ -1,7 +1,7 @@ /* * InfoTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -34,10 +34,10 @@ package net.thauvin.erik.mobibot.commands import assertk.assertThat import assertk.assertions.isEqualTo import net.thauvin.erik.mobibot.commands.Info.Companion.toUptime -import org.testng.annotations.Test +import kotlin.test.Test class InfoTest { - @Test(groups = ["commands"]) + @Test fun testToUptime() { assertThat( 547800300076L.toUptime(), diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/RecapTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/RecapTest.kt index f1fbe11..34dce0e 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/RecapTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/RecapTest.kt @@ -1,7 +1,7 @@ /* * RecapTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -37,10 +37,10 @@ import assertk.assertions.isEqualTo import assertk.assertions.matches import assertk.assertions.prop import assertk.assertions.size -import org.testng.annotations.Test +import kotlin.test.Test class RecapTest { - @Test(groups = ["commands"]) + @Test fun storeRecapTest() { for (i in 1..20) { Recap.storeRecap("sender$i", "test $i", false) diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt index 8e49b5e..eea09db 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt @@ -1,7 +1,7 @@ /* * LinksManagerTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -38,12 +38,12 @@ import assertk.assertions.isEqualTo import assertk.assertions.isTrue import assertk.assertions.size import net.thauvin.erik.mobibot.Constants -import org.testng.annotations.Test +import kotlin.test.Test class LinksManagerTest { private val linksManager = LinksManager() - @Test(groups = ["commands", "links"]) + @Test fun fetchTitle() { assertThat(linksManager.fetchTitle("https://erik.thauvin.net/"), "fetchTitle(Erik)").contains("Erik's Weblog") assertThat( @@ -52,13 +52,13 @@ class LinksManagerTest { ).isEqualTo(Constants.NO_TITLE) } - @Test(groups = ["commands", "links"]) + @Test fun testMatches() { assertThat(linksManager.matches("https://www.example.com/"), "matches(url)").isTrue() assertThat(linksManager.matches("HTTP://erik.thauvin.net/blog/ Erik's Weblog"), "matches(HTTP)").isTrue() } - @Test(groups = ["commands", "links"]) + @Test fun matchTagKeywordsTest() { linksManager.setProperty(LinksManager.KEYWORDS_PROP, "key1 key2,key3") val tags = mutableListOf() diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/ViewTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/ViewTest.kt index c28090d..b5028e3 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/ViewTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/ViewTest.kt @@ -1,7 +1,7 @@ /* * ViewTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -36,10 +36,10 @@ import assertk.assertThat import assertk.assertions.isEqualTo import assertk.assertions.prop import net.thauvin.erik.mobibot.entries.EntryLink -import org.testng.annotations.Test +import kotlin.test.Test class ViewTest { - @Test(groups = ["commands", "links"]) + @Test fun testParseArgs() { val view = View() diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt index 52a21cc..331f97c 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt @@ -1,7 +1,7 @@ /* * SeenTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -34,29 +34,16 @@ package net.thauvin.erik.mobibot.commands.seen import assertk.all import assertk.assertThat import assertk.assertions.* -import org.testng.annotations.AfterClass -import org.testng.annotations.BeforeClass -import org.testng.annotations.Test +import org.junit.AfterClass +import org.junit.BeforeClass +import org.junit.jupiter.api.Order import kotlin.io.path.deleteIfExists import kotlin.io.path.fileSize +import kotlin.test.Test class SeenTest { - private val tmpFile = kotlin.io.path.createTempFile(suffix = ".ser") - private val seen = Seen(tmpFile.toAbsolutePath().toString()) - private val nick = "ErikT" - - @BeforeClass - fun saveTest() { - seen.add("ErikT") - assertThat(tmpFile.fileSize(), "tmpFile.size").isGreaterThan(0) - } - - @AfterClass(alwaysRun = true) - fun afterClass() { - tmpFile.deleteIfExists() - } - - @Test(priority = 1, groups = ["commands"]) + @Test + @Order(1) fun loadTest() { seen.clear() assertThat(seen::seenNicks).isEmpty() @@ -64,7 +51,8 @@ class SeenTest { assertThat(seen::seenNicks).key(nick).isNotNull() } - @Test(groups = ["commands"]) + @Test + @Order(2) fun addTest() { val last = seen.seenNicks[nick]?.lastSeen seen.add(nick.lowercase()) @@ -75,11 +63,31 @@ class SeenTest { } } - @Test(priority = 10, groups = ["commands"]) + @Test + @Order(3) fun clearTest() { seen.clear() seen.save() seen.load() assertThat(seen::seenNicks).size().isEqualTo(0) } + + companion object { + private val tmpFile = kotlin.io.path.createTempFile(suffix = ".ser") + private val seen = Seen(tmpFile.toAbsolutePath().toString()) + private const val nick = "ErikT" + + @JvmStatic + @BeforeClass + fun beforeClass() { + seen.add(nick) + assertThat(tmpFile.fileSize(), "tmpFile.size").isGreaterThan(0) + } + + @JvmStatic + @AfterClass + fun afterClass() { + tmpFile.deleteIfExists() + } + } } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt index f7239e0..f2c6f35 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt @@ -1,7 +1,7 @@ /* * TellMessageTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -36,10 +36,10 @@ import assertk.assertions.isEqualTo import assertk.assertions.isFalse import assertk.assertions.isTrue import assertk.assertions.prop -import org.testng.annotations.Test import java.time.Duration import java.time.LocalDateTime import java.time.temporal.Temporal +import kotlin.test.Test /** * The `TellMessageTest` class. @@ -49,7 +49,7 @@ class TellMessageTest { return Duration.between(date, LocalDateTime.now()).toMinutes() < 1 } - @Test(groups = ["commands", "tell"]) + @Test fun testTellMessage() { val message = "Test message." val recipient = "recipient" diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt index 115e9fb..9ab1bce 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt @@ -1,7 +1,7 @@ /* * TellMessagesMgrTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -34,16 +34,14 @@ package net.thauvin.erik.mobibot.commands.tell import assertk.all import assertk.assertThat import assertk.assertions.* -import org.testng.annotations.AfterClass -import org.testng.annotations.BeforeClass -import org.testng.annotations.Test +import org.junit.AfterClass import java.time.LocalDateTime import kotlin.io.path.createTempFile import kotlin.io.path.deleteIfExists import kotlin.io.path.fileSize +import kotlin.test.Test class TellMessagesMgrTest { - private val testFile = createTempFile(suffix = ".ser") private val maxDays = 10L private val testMessages = mutableListOf().apply { for (i in 0..5) { @@ -51,18 +49,12 @@ class TellMessagesMgrTest { } } - @BeforeClass - fun saveTest() { + init { TellManager.save(testFile.toAbsolutePath().toString(), testMessages) assertThat(testFile.fileSize()).isGreaterThan(0) } - @AfterClass - fun afterClass() { - testFile.deleteIfExists() - } - - @Test(groups = ["commands", "tell"]) + @Test fun cleanTest() { testMessages.add(TellMessage("sender", "recipient", "message").apply { queued = LocalDateTime.now().minusDays(maxDays) @@ -73,7 +65,7 @@ class TellMessagesMgrTest { assertThat(testMessages, "testMessages").size().isEqualTo(size - 1) } - @Test(groups = ["commands", "tell"]) + @Test fun loadTest() { val messages = TellManager.load(testFile.toAbsolutePath().toString()) for (i in messages.indices) { @@ -84,4 +76,14 @@ class TellMessagesMgrTest { } } } + + companion object { + private val testFile = createTempFile(suffix = ".ser") + + @JvmStatic + @AfterClass + fun afterClass() { + testFile.deleteIfExists() + } + } } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt index 6eef16e..8e9bd6f 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt @@ -1,7 +1,7 @@ /* * EntriesUtilsTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -39,7 +39,7 @@ import net.thauvin.erik.mobibot.entries.EntriesUtils.printComment import net.thauvin.erik.mobibot.entries.EntriesUtils.printLink import net.thauvin.erik.mobibot.entries.EntriesUtils.printTags import net.thauvin.erik.mobibot.entries.EntriesUtils.toLinkLabel -import org.testng.annotations.Test +import kotlin.test.Test class EntriesUtilsTest { private val comment = EntryComment("comment", "nick") @@ -58,12 +58,12 @@ class EntriesUtilsTest { } } - @Test(groups = ["entries"]) + @Test fun printCommentTest() { assertThat(printComment(0, 0, comment)).isEqualTo("${Constants.LINK_CMD}1.1: [nick] comment") } - @Test(groups = ["entries"]) + @Test fun printLinkTest() { for (i in links.indices) { assertThat( @@ -75,7 +75,7 @@ class EntriesUtilsTest { assertThat(printLink(0, links.first(), isView = true), "printLink(isView=true)").contains("[+1]") } - @Test(groups = ["entries"]) + @Test fun printTagsTest() { for (i in links.indices) { assertThat( @@ -84,7 +84,7 @@ class EntriesUtilsTest { } } - @Test(groups = ["entries"]) + @Test fun toLinkLabelTest() { assertThat(1.toLinkLabel()).isEqualTo("${Constants.LINK_CMD}2") } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt index ab3feee..495ed15 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt @@ -1,7 +1,7 @@ /* * EntryLinkTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -35,9 +35,9 @@ import assertk.assertThat import assertk.assertions.* import com.rometools.rome.feed.synd.SyndCategory import com.rometools.rome.feed.synd.SyndCategoryImpl -import org.testng.annotations.Test import java.security.SecureRandom import java.util.* +import kotlin.test.Test /** * The `EntryUtilsTest` class. @@ -52,7 +52,7 @@ class EntryLinkTest { listOf("tag1", "tag2", "tag3", "TAG4", "Tag5") ) - @Test(groups = ["entries"]) + @Test fun testAddDeleteComment() { var i = 0 while (i < 5) { @@ -85,7 +85,7 @@ class EntryLinkTest { assertThat(entryLink.deleteComment(comment), "comment is already deleted").isFalse() } - @Test(groups = ["entries"]) + @Test fun testConstructor() { val tags = listOf(SyndCategoryImpl().apply { name = "tag1" }, SyndCategoryImpl().apply { name = "tag2" }) val link = EntryLink("link", "title", "nick", "channel", Date(), tags) @@ -95,7 +95,7 @@ class EntryLinkTest { } } - @Test(groups = ["entries"]) + @Test fun testMatches() { assertThat(entryLink.matches("mobitopia"), "matches(mobitopia)").isTrue() assertThat(entryLink.matches("skynx"), "match(nick)").isTrue() @@ -106,7 +106,7 @@ class EntryLinkTest { } - @Test(groups = ["entries"]) + @Test fun testTags() { val tags: List = entryLink.tags for ((i, tag) in tags.withIndex()) { diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt index 4223d9d..de6075d 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt @@ -1,7 +1,7 @@ /* * FeedMgrTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -35,27 +35,25 @@ import assertk.all import assertk.assertThat import assertk.assertions.* import net.thauvin.erik.mobibot.Utils.today -import org.testng.annotations.BeforeSuite -import org.testng.annotations.Test import java.nio.file.Paths import java.util.* import kotlin.io.path.deleteIfExists import kotlin.io.path.fileSize import kotlin.io.path.name +import kotlin.test.Test class FeedMgrTest { private val entries = Entries() private val channel = "mobibot" - @BeforeSuite(alwaysRun = true) - fun beforeSuite() { + init { entries.logsDir = "src/test/resources/" entries.ircServer = "irc.example.com" entries.channel = channel entries.backlogs = "https://www.mobitopia.org/mobibot/logs" } - @Test(groups = ["entries"]) + @Test fun testFeedMgr() { // Load the feed assertThat(FeedsManager.loadFeed(entries), "loadFeed()").isEqualTo("2021-10-31") diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt index 2b1d3f9..6df5616 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt @@ -1,7 +1,7 @@ /* * CalcTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -37,13 +37,13 @@ import assertk.assertions.isInstanceOf import net.objecthunter.exp4j.tokenizer.UnknownFunctionOrVariableException import net.thauvin.erik.mobibot.Utils.bold import net.thauvin.erik.mobibot.modules.Calc.Companion.calculate -import org.testng.annotations.Test +import kotlin.test.Test /** * The `CalcTest` class. */ class CalcTest { - @Test(groups = ["modules"]) + @Test fun testCalculate() { assertThat(calculate("1 + 1"), "calculate(1+1)").isEqualTo("1+1 = ${2.bold()}") assertThat(calculate("1 -3"), "calculate(1-3)").isEqualTo("1-3 = ${(-2).bold()}") diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt index 66fb98d..00fa43f 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt @@ -1,7 +1,7 @@ /* * ChatGptTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -35,18 +35,20 @@ import assertk.assertThat import assertk.assertions.contains import assertk.assertions.hasNoCause import assertk.assertions.isInstanceOf +import net.thauvin.erik.mobibot.DisabledOnCi import net.thauvin.erik.mobibot.LocalProperties -import org.testng.annotations.Test +import kotlin.test.Test class ChatGptTest : LocalProperties() { - @Test(groups = ["modules"]) + @Test fun testApiKey() { assertFailure { ChatGpt.chat("1 gallon to liter", "", 0) } .isInstanceOf(ModuleException::class.java) .hasNoCause() } - @Test(groups = ["modules", "no-ci"]) + @Test + @DisabledOnCi fun testChat() { val apiKey = getProperty(ChatGpt.API_KEY_PROP) assertThat( diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt index 0547c95..9847080 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt @@ -1,7 +1,7 @@ /* * CryptoPricesTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -39,20 +39,17 @@ import net.thauvin.erik.crypto.CryptoPrice import net.thauvin.erik.mobibot.modules.CryptoPrices.Companion.currentPrice import net.thauvin.erik.mobibot.modules.CryptoPrices.Companion.getCurrencyName import net.thauvin.erik.mobibot.modules.CryptoPrices.Companion.loadCurrencies -import org.testng.annotations.BeforeClass -import org.testng.annotations.Test +import kotlin.test.Test /** * The `CryptoPricesTest` class. */ class CryptoPricesTest { - @BeforeClass - @Throws(ModuleException::class) - fun before() { + init { loadCurrencies() } - @Test(groups = ["modules"]) + @Test @Throws(ModuleException::class) fun testMarketPrice() { var price = currentPrice(listOf("BTC")) @@ -70,7 +67,7 @@ class CryptoPricesTest { } } - @Test(groups = ["modules"]) + @Test fun testGetCurrencyName() { assertThat(getCurrencyName("USD"), "USD").isEqualTo("United States Dollar") assertThat(getCurrencyName("EUR"), "EUR").isEqualTo("Euro") diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt index 5375784..57affe5 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt @@ -1,7 +1,7 @@ /* * CurrencyConverterTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -42,23 +42,19 @@ import net.thauvin.erik.mobibot.modules.CurrencyConverter.Companion.loadSymbols import net.thauvin.erik.mobibot.msg.ErrorMessage import net.thauvin.erik.mobibot.msg.Message import net.thauvin.erik.mobibot.msg.PublicMessage -import org.testng.annotations.BeforeClass -import org.testng.annotations.Test +import kotlin.test.Test /** * The `CurrencyConvertTest` class. */ class CurrencyConverterTest : LocalProperties() { - - @BeforeClass - @Throws(ModuleException::class) - fun before() { + init { val apiKey = getProperty(CurrencyConverter.API_KEY_PROP) loadSymbols(apiKey) } - @Test(groups = ["modules"]) + @Test fun testConvertCurrency() { val apiKey = getProperty(CurrencyConverter.API_KEY_PROP) assertThat( diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/DiceTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/DiceTest.kt index cdc04f0..0aaacb9 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/DiceTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/DiceTest.kt @@ -1,7 +1,7 @@ /* * DiceTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -35,10 +35,10 @@ package net.thauvin.erik.mobibot.modules import assertk.assertThat import assertk.assertions.isEqualTo import assertk.assertions.matches -import org.testng.annotations.Test +import kotlin.test.Test class DiceTest { - @Test(groups = ["modules"]) + @Test fun testRoll() { assertThat(Dice.roll(1, 1), "roll(1d1)").isEqualTo("\u00021\u0002") assertThat(Dice.roll(2, 1), "roll(2d1)") diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt index fa50f8c..b0c154a 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt @@ -1,7 +1,7 @@ /* * GoogleSearchTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -34,18 +34,19 @@ import assertk.all import assertk.assertFailure import assertk.assertThat import assertk.assertions.* +import net.thauvin.erik.mobibot.DisabledOnCi import net.thauvin.erik.mobibot.ExceptionSanitizer.sanitize import net.thauvin.erik.mobibot.LocalProperties import net.thauvin.erik.mobibot.modules.GoogleSearch.Companion.searchGoogle import net.thauvin.erik.mobibot.msg.ErrorMessage import net.thauvin.erik.mobibot.msg.Message -import org.testng.annotations.Test +import kotlin.test.Test /** * The `GoogleSearchTest` class. */ class GoogleSearchTest : LocalProperties() { - @Test(groups = ["modules"]) + @Test fun testAPIKeys() { assertThat( searchGoogle("", "apikey", "cssKey").first(), @@ -63,7 +64,8 @@ class GoogleSearchTest : LocalProperties() { .hasMessage("API key not valid. Please pass a valid API key.") } - @Test(groups = ["no-ci", "modules"]) + @Test + @DisabledOnCi @Throws(ModuleException::class) fun testSearchGoogle() { val apiKey = getProperty(GoogleSearch.API_KEY_PROP) diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/JokeTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/JokeTest.kt index 55a7b8f..9b8dcb3 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/JokeTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/JokeTest.kt @@ -1,7 +1,7 @@ /* * JokeTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -36,13 +36,13 @@ import assertk.assertions.* import net.thauvin.erik.mobibot.modules.Joke.Companion.randomJoke import net.thauvin.erik.mobibot.msg.Message import net.thauvin.erik.mobibot.msg.PublicMessage -import org.testng.annotations.Test +import kotlin.test.Test /** * The `JokeTest` class. */ class JokeTest { - @Test(groups = ["modules"]) + @Test @Throws(ModuleException::class) fun testRandomJoke() { val joke = randomJoke() diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt index 9c21f7c..e67c8ad 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt @@ -1,7 +1,7 @@ /* * LookupTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -35,13 +35,13 @@ import assertk.assertions.any import assertk.assertions.contains import net.thauvin.erik.mobibot.modules.Lookup.Companion.nslookup import net.thauvin.erik.mobibot.modules.Lookup.Companion.whois -import org.testng.annotations.Test +import kotlin.test.Test /** * The `Lookup Test` class. */ class LookupTest { - @Test(groups = ["modules"]) + @Test @Throws(Exception::class) fun testLookup() { var result = nslookup("apple.com") @@ -51,7 +51,7 @@ class LookupTest { assertThat(result, "lookup(204.122.16.136)").contains("nix3.thauvin.us") } - @Test(groups = ["modules"]) + @Test @Throws(Exception::class) fun testWhois() { val result = whois("17.178.96.59", Lookup.WHOIS_HOST) diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt index 34f778a..d189d75 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt @@ -1,7 +1,7 @@ /* * MastodonTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -34,10 +34,10 @@ import assertk.assertThat import assertk.assertions.contains import net.thauvin.erik.mobibot.LocalProperties import net.thauvin.erik.mobibot.modules.Mastodon.Companion.toot -import org.testng.annotations.Test +import kotlin.test.Test class MastodonTest : LocalProperties() { - @Test(groups = ["modules"]) + @Test @Throws(ModuleException::class) fun testToot() { val msg = "Testing Mastodon API from ${getHostName()}" diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt index db68280..9dda5b3 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt @@ -1,7 +1,7 @@ /* * ModuleExceptionTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -34,10 +34,10 @@ import assertk.all import assertk.assertThat import assertk.assertions.* import net.thauvin.erik.mobibot.ExceptionSanitizer.sanitize -import org.testng.annotations.DataProvider -import org.testng.annotations.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.MethodSource import java.io.IOException -import java.lang.reflect.Method +import kotlin.test.Test /** * The `ModuleExceptionTest` class. @@ -46,28 +46,30 @@ class ModuleExceptionTest { companion object { const val DEBUG_MESSAGE = "debugMessage" const val MESSAGE = "message" + + @JvmStatic + fun dataProviders(): List { + return listOf( + ModuleException(DEBUG_MESSAGE, MESSAGE, IOException("URL http://foobar.com")), + ModuleException(DEBUG_MESSAGE, MESSAGE, IOException("URL http://foobar.com?")), + ModuleException(DEBUG_MESSAGE, MESSAGE) + ) + } } - @DataProvider(name = "dp") - fun createData(@Suppress("UNUSED_PARAMETER") m: Method?): Array> { - return arrayOf( - arrayOf(ModuleException(DEBUG_MESSAGE, MESSAGE, IOException("URL http://foobar.com"))), - arrayOf(ModuleException(DEBUG_MESSAGE, MESSAGE, IOException("URL http://foobar.com?"))), - arrayOf(ModuleException(DEBUG_MESSAGE, MESSAGE)) - ) - } - - @Test(dataProvider = "dp") + @ParameterizedTest + @MethodSource("dataProviders") fun testGetDebugMessage(e: ModuleException) { assertThat(e::debugMessage).isEqualTo(DEBUG_MESSAGE) } - @Test(dataProvider = "dp") + @ParameterizedTest + @MethodSource("dataProviders") fun testGetMessage(e: ModuleException) { assertThat(e).hasMessage(MESSAGE) } - @Test(groups = ["modules"]) + @Test fun testSanitizeMessage() { val apiKey = "1234567890" var e = ModuleException(DEBUG_MESSAGE, MESSAGE, IOException("URL http://foo.com?apiKey=$apiKey&userID=me")) diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/PingTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/PingTest.kt index e1e79f3..a6ff707 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/PingTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/PingTest.kt @@ -1,7 +1,7 @@ /* * PingTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -34,18 +34,18 @@ import assertk.assertThat import assertk.assertions.contains import assertk.assertions.isNotEmpty import net.thauvin.erik.mobibot.modules.Ping.Companion.randomPing -import org.testng.annotations.Test +import kotlin.test.Test /** * The `PingTest` class. */ class PingTest { - @Test(groups = ["modules"]) + @Test fun testPingsArray() { assertThat(Ping.PINGS, "Ping.PINGS").isNotEmpty() } - @Test(groups = ["modules"]) + @Test fun testRandomPing() { for (i in 0..9) { assertThat(Ping.PINGS, "Ping.PINGS[$i]").contains(randomPing()) diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt index 8dc90ba..fb8865b 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt @@ -1,7 +1,7 @@ /* * RockPaperScissorsTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -34,10 +34,10 @@ package net.thauvin.erik.mobibot.modules import assertk.assertThat import assertk.assertions.isEqualTo import net.thauvin.erik.mobibot.modules.RockPaperScissors.Companion.winLoseOrDraw -import org.testng.annotations.Test +import kotlin.test.Test class RockPaperScissorsTest { - @Test(groups = ["modules"]) + @Test fun testWinLoseOrDraw() { assertThat(winLoseOrDraw("scissors", "paper"), "scissors vs. paper").isEqualTo("win") assertThat(winLoseOrDraw("paper", "rock"), "paper vs. rock").isEqualTo("win") diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt index aff4188..ae8cff2 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt @@ -1,7 +1,7 @@ /* * StockQuoteTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -39,7 +39,7 @@ import net.thauvin.erik.mobibot.LocalProperties import net.thauvin.erik.mobibot.modules.StockQuote.Companion.getQuote import net.thauvin.erik.mobibot.msg.ErrorMessage import net.thauvin.erik.mobibot.msg.Message -import org.testng.annotations.Test +import kotlin.test.Test /** * The `StockQuoteTest` class. @@ -49,7 +49,7 @@ class StockQuoteTest : LocalProperties() { return "${label}:[ ]+[0-9.]+".prependIndent() } - @Test(groups = ["modules"]) + @Test @Throws(ModuleException::class) fun testGetQuote() { val apiKey = getProperty(StockQuote.API_KEY_PROP) diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt index d7d65de..e135866 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt @@ -1,7 +1,7 @@ /* * Weather2Test.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -43,19 +43,19 @@ import net.thauvin.erik.mobibot.modules.Weather2.Companion.getCountry import net.thauvin.erik.mobibot.modules.Weather2.Companion.getWeather import net.thauvin.erik.mobibot.modules.Weather2.Companion.mphToKmh import net.thauvin.erik.mobibot.msg.Message -import org.testng.annotations.Test +import kotlin.test.Test /** * The `Weather2Test` class. */ class Weather2Test : LocalProperties() { - @Test(groups = ["modules"]) + @Test fun testFtoC() { val t = ftoC(32.0) assertThat(t.second, "32 °F is 0 °C").isEqualTo(0) } - @Test(groups = ["modules"]) + @Test fun testGetCountry() { assertThat(getCountry("foo"), "foo is not a valid country").isEqualTo(OWM.Country.UNITED_STATES) assertThat(getCountry("fr"), "country should France").isEqualTo(OWM.Country.FRANCE) @@ -67,13 +67,13 @@ class Weather2Test : LocalProperties() { } } - @Test(groups = ["modules"]) + @Test fun testMphToKmh() { val w = mphToKmh(0.62) assertThat(w.second, "0.62 mph is 1 km/h").isEqualTo(1) } - @Test(groups = ["modules"]) + @Test @Throws(ModuleException::class) fun testWeather() { var query = "98204" diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt index ae1722d..417f9fc 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt @@ -1,7 +1,7 @@ /* * WolframAlphaTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -36,13 +36,14 @@ import assertk.assertThat import assertk.assertions.contains import assertk.assertions.hasMessage import assertk.assertions.isInstanceOf +import net.thauvin.erik.mobibot.DisabledOnCi import net.thauvin.erik.mobibot.ExceptionSanitizer.sanitize import net.thauvin.erik.mobibot.LocalProperties import net.thauvin.erik.mobibot.modules.WolframAlpha.Companion.queryWolfram -import org.testng.annotations.Test +import kotlin.test.Test class WolframAlphaTest : LocalProperties() { - @Test(groups = ["modules"]) + @Test fun testAppId() { assertFailure { queryWolfram("1 gallon to liter", appId = "DEMO") } .isInstanceOf(ModuleException::class.java) @@ -52,7 +53,8 @@ class WolframAlphaTest : LocalProperties() { .isInstanceOf(ModuleException::class.java) } - @Test(groups = ["modules", "no-ci"]) + @Test + @DisabledOnCi @Throws(ModuleException::class) fun queryWolframTest() { val apiKey = getProperty(WolframAlpha.APPID_KEY_PROP) diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt index 3602a27..5c8cc84 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt @@ -1,7 +1,7 @@ /* * WordTimeTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -39,14 +39,14 @@ import net.thauvin.erik.mobibot.modules.WorldTime.Companion.BEATS_KEYWORD import net.thauvin.erik.mobibot.modules.WorldTime.Companion.COUNTRIES_MAP import net.thauvin.erik.mobibot.modules.WorldTime.Companion.time import org.pircbotx.Colors -import org.testng.annotations.Test import java.time.ZoneId +import kotlin.test.Test /** * The `WordTimeTest` class. */ class WordTimeTest { - @Test(groups = ["modules"]) + @Test fun testTime() { assertThat(time(), "time()").matches( ("The time is ${Colors.BOLD}\\d{1,2}:\\d{2}${Colors.BOLD} " + @@ -61,7 +61,7 @@ class WordTimeTest { assertThat(time("BEAT"), "time($BEATS_KEYWORD)").matches("[\\w ]+ .?@\\d{3}+.? .beats".toRegex()) } - @Test(groups = ["modules"]) + @Test fun testZones() { COUNTRIES_MAP.filter { it.value != BEATS_KEYWORD }.forEach { assertThat(ZoneId.of(it.value)) diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/msg/MessageTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/msg/MessageTest.kt index e856112..477c1a4 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/msg/MessageTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/msg/MessageTest.kt @@ -1,7 +1,7 @@ /* * MessageTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -36,7 +36,7 @@ import assertk.assertThat import assertk.assertions.isFalse import assertk.assertions.isTrue import assertk.assertions.prop -import org.testng.annotations.Test +import kotlin.test.Test class MessageTest { @Test diff --git a/src/test/resources/current.xml b/src/test/resources/current.xml index 535a400..8552a9a 100644 --- a/src/test/resources/current.xml +++ b/src/test/resources/current.xml @@ -1,35 +1,4 @@ - - #mobibot IRC Links diff --git a/version.mustache b/version.mustache deleted file mode 100644 index b2672e4..0000000 --- a/version.mustache +++ /dev/null @@ -1,32 +0,0 @@ -/* -* This file is automatically generated. -* Do not modify! -- ALL CHANGES WILL BE ERASED! -*/ -package {{packageName}} - -import java.time.LocalDateTime -import java.time.ZoneId -import java.time.Instant - -/** -* Provides semantic version information. -* -* @author [Semantic Version Annotation Processor](https://github.com/ethauvin/semver) -*/ -object ReleaseInfo{ - const val PROJECT = "{{project}}" - const val VERSION = "{{version}}" - - @JvmField - val BUILDDATE = LocalDateTime.ofInstant(Instant.ofEpochMilli({{epoch}}L), ZoneId.systemDefault()) - - const val MAJOR = {{major}} - const val MINOR = {{minor}} - const val PATCH = {{patch}} - const val BUILDMETA = "{{buildMeta}}" - const val PRERELEASE = "{{preRelease}}" - - const val WEBSITE = "https://www.mobitopia.org/mobibot/" - const val AUTHOR = "Erik C. Thauvin" - const val AUTHOR_URL = "https://erik.thauvin.net/" -} diff --git a/version.properties b/version.properties deleted file mode 100644 index 9c446af..0000000 --- a/version.properties +++ /dev/null @@ -1,9 +0,0 @@ -#Generated by the Semver Plugin for Gradle -#Wed Nov 01 22:09:32 PDT 2023 -version.buildmeta=20231101220932 -version.major=0 -version.minor=8 -version.patch=0 -version.prerelease=rc -version.project=mobibot -version.semver=0.8.0-rc+20231101220932 From f8de100dde2e02996f1b0e10c9d6183c6f213b63 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sat, 11 Nov 2023 00:34:54 -0800 Subject: [PATCH 740/844] Added missing env variables --- .github/workflows/gradle.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index ae6c66f..19081a4 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -35,6 +35,16 @@ jobs: run: ./bld compile - name: Run tests with bld + env: + CI_NAME: "GitHub CI" + ALPHAVANTAGE_API_KEY: ${{ secrets.ALPHAVANTAGE_API_KEY }} + CHATGPT_API_KEY: ${{ secrets.CHATGPT_API_KEY }} + OWM_API_KEY: ${{ secrets.OWM_API_KEY }} + PINBOARD_API_TOKEN: ${{ secrets.PINBOARD_API_TOKEN }} + MASTODON_ACCESS_TOKEN: ${{ secrets.MASTODON_ACCESS_TOKEN }} + MASTODON_HANDLE: ${{ secrets.MASTODON_HANDLE }} + MASTODON_INSTANCE: ${{ secrets.MASTODON_INSTANCE }} + EXCHANGERATE_API_KEY: ${{ secrets.EXCHANGERATE_API_KEY }} run: ./bld jacoco - name: SonarCloud Scan From 208f3a82d99f1c056c424948f7ad107d482ea481 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sat, 11 Nov 2023 13:13:35 -0800 Subject: [PATCH 741/844] Ignored bin directory --- .gitignore | 5 +- bin/main/log4j2.xml | 69 --- bin/main/net/thauvin/erik/mobibot/Addons.kt | 190 -------- .../net/thauvin/erik/mobibot/Constants.kt | 102 ---- .../net/thauvin/erik/mobibot/FeedReader.kt | 92 ---- bin/main/net/thauvin/erik/mobibot/Mobibot.kt | 421 ----------------- bin/main/net/thauvin/erik/mobibot/Pinboard.kt | 113 ----- bin/main/net/thauvin/erik/mobibot/Utils.kt | 439 ------------------ .../erik/mobibot/commands/AbstractCommand.kt | 79 ---- .../erik/mobibot/commands/ChannelFeed.kt | 62 --- .../thauvin/erik/mobibot/commands/Cycle.kt | 66 --- .../net/thauvin/erik/mobibot/commands/Die.kt | 62 --- .../thauvin/erik/mobibot/commands/Ignore.kt | 147 ------ .../net/thauvin/erik/mobibot/commands/Info.kt | 124 ----- .../net/thauvin/erik/mobibot/commands/Me.kt | 51 -- .../thauvin/erik/mobibot/commands/Modules.kt | 63 --- .../net/thauvin/erik/mobibot/commands/Msg.kt | 60 --- .../net/thauvin/erik/mobibot/commands/Nick.kt | 51 -- .../thauvin/erik/mobibot/commands/Recap.kt | 81 ---- .../net/thauvin/erik/mobibot/commands/Say.kt | 51 -- .../thauvin/erik/mobibot/commands/Users.kt | 50 -- .../thauvin/erik/mobibot/commands/Versions.kt | 59 --- .../erik/mobibot/commands/links/Comment.kt | 151 ------ .../mobibot/commands/links/LinksManager.kt | 207 --------- .../erik/mobibot/commands/links/Posting.kt | 164 ------- .../erik/mobibot/commands/links/Tags.kt | 87 ---- .../erik/mobibot/commands/links/View.kt | 120 ----- .../mobibot/commands/seen/NickComparator.kt | 45 -- .../erik/mobibot/commands/seen/Seen.kt | 150 ------ .../erik/mobibot/commands/seen/SeenNick.kt | 41 -- .../erik/mobibot/commands/tell/Tell.kt | 306 ------------ .../erik/mobibot/commands/tell/TellManager.kt | 74 --- .../erik/mobibot/commands/tell/TellMessage.kt | 104 ----- .../thauvin/erik/mobibot/entries/Entries.kt | 54 --- .../erik/mobibot/entries/EntriesUtils.kt | 83 ---- .../erik/mobibot/entries/EntryComment.kt | 52 --- .../thauvin/erik/mobibot/entries/EntryLink.kt | 213 --------- .../erik/mobibot/entries/FeedsManager.kt | 187 -------- .../erik/mobibot/modules/AbstractModule.kt | 131 ------ .../net/thauvin/erik/mobibot/modules/Calc.kt | 87 ---- .../thauvin/erik/mobibot/modules/ChatGpt.kt | 176 ------- .../erik/mobibot/modules/CryptoPrices.kt | 159 ------- .../erik/mobibot/modules/CurrencyConverter.kt | 222 --------- .../net/thauvin/erik/mobibot/modules/Dice.kt | 87 ---- .../erik/mobibot/modules/GoogleSearch.kt | 162 ------- .../net/thauvin/erik/mobibot/modules/Joke.kt | 105 ----- .../thauvin/erik/mobibot/modules/Lookup.kt | 171 ------- .../thauvin/erik/mobibot/modules/Mastodon.kt | 149 ------ .../erik/mobibot/modules/ModuleException.kt | 45 -- .../net/thauvin/erik/mobibot/modules/Ping.kt | 83 ---- .../erik/mobibot/modules/RockPaperScissors.kt | 114 ----- .../erik/mobibot/modules/StockQuote.kt | 236 ---------- .../thauvin/erik/mobibot/modules/War.class | Bin 2452 -> 0 bytes .../thauvin/erik/mobibot/modules/Weather2.kt | 250 ---------- .../erik/mobibot/modules/WolframAlpha.kt | 142 ------ .../thauvin/erik/mobibot/modules/WorldTime.kt | 390 ---------------- .../thauvin/erik/mobibot/msg/ErrorMessage.kt | 37 -- .../net/thauvin/erik/mobibot/msg/Message.kt | 65 --- .../thauvin/erik/mobibot/msg/NoticeMessage.kt | 38 -- .../erik/mobibot/msg/PrivateMessage.kt | 37 -- .../thauvin/erik/mobibot/msg/PublicMessage.kt | 36 -- .../erik/mobibot/social/SocialManager.kt | 116 ----- .../erik/mobibot/social/SocialModule.kt | 96 ---- .../erik/mobibot/social/SocialTimer.kt | 40 -- bin/test/current.xml | 67 --- .../net/thauvin/erik/mobibot/AddonsTest.kt | 86 ---- .../erik/mobibot/ExceptionSanitizer.kt | 60 --- .../thauvin/erik/mobibot/FeedReaderTest.kt | 78 ---- .../thauvin/erik/mobibot/LocalProperties.kt | 85 ---- .../net/thauvin/erik/mobibot/PinboardTest.kt | 81 ---- .../net/thauvin/erik/mobibot/UtilsTest.kt | 278 ----------- .../thauvin/erik/mobibot/commands/InfoTest.kt | 58 --- .../erik/mobibot/commands/RecapTest.kt | 60 --- .../commands/links/LinksManagerTest.kt | 77 --- .../erik/mobibot/commands/links/ViewTest.kt | 111 ----- .../erik/mobibot/commands/seen/SeenTest.kt | 85 ---- .../mobibot/commands/tell/TellMessageTest.kt | 72 --- .../commands/tell/TellMessagesMgrTest.kt | 87 ---- .../erik/mobibot/entries/EntriesUtilsTest.kt | 91 ---- .../erik/mobibot/entries/EntryLinkTest.kt | 133 ------ .../erik/mobibot/entries/FeedMgrTest.kt | 115 ----- .../thauvin/erik/mobibot/modules/CalcTest.kt | 53 --- .../erik/mobibot/modules/ChatGptTest.kt | 62 --- .../erik/mobibot/modules/CryptoPricesTest.kt | 78 ---- .../mobibot/modules/CurrencyConverterTest.kt | 85 ---- .../thauvin/erik/mobibot/modules/DiceTest.kt | 53 --- .../erik/mobibot/modules/GoogleSearchTest.kt | 95 ---- .../thauvin/erik/mobibot/modules/JokeTest.kt | 57 --- .../erik/mobibot/modules/LookupTest.kt | 60 --- .../erik/mobibot/modules/MastodonTest.kt | 54 --- .../mobibot/modules/ModuleExceptionTest.kt | 105 ----- .../thauvin/erik/mobibot/modules/PingTest.kt | 54 --- .../mobibot/modules/RockPaperScissorsTest.kt | 50 -- .../erik/mobibot/modules/StockQuoteTest.kt | 85 ---- .../erik/mobibot/modules/Weather2Test.kt | 117 ----- .../erik/mobibot/modules/WolframAlphaTest.kt | 77 --- .../erik/mobibot/modules/WordTimeTest.kt | 70 --- .../thauvin/erik/mobibot/msg/MessageTest.kt | 109 ----- .../net/thauvin/erik/mobibot/ReleaseInfo.kt | 4 +- src/main/resources/log4j2.xml | 38 -- 100 files changed, 5 insertions(+), 10574 deletions(-) delete mode 100644 bin/main/log4j2.xml delete mode 100644 bin/main/net/thauvin/erik/mobibot/Addons.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/Constants.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/FeedReader.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/Mobibot.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/Pinboard.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/Utils.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/commands/AbstractCommand.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/commands/ChannelFeed.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/commands/Cycle.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/commands/Die.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/commands/Ignore.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/commands/Info.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/commands/Me.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/commands/Modules.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/commands/Msg.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/commands/Nick.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/commands/Recap.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/commands/Say.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/commands/Users.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/commands/Versions.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/commands/links/Comment.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/commands/links/LinksManager.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/commands/links/Posting.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/commands/links/Tags.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/commands/links/View.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/commands/seen/Seen.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/commands/tell/Tell.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/commands/tell/TellManager.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/entries/Entries.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/entries/EntriesUtils.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/entries/EntryComment.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/entries/EntryLink.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/entries/FeedsManager.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/modules/AbstractModule.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/modules/Calc.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/modules/ChatGpt.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/modules/CryptoPrices.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/modules/Dice.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/modules/GoogleSearch.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/modules/Joke.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/modules/Lookup.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/modules/Mastodon.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/modules/ModuleException.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/modules/Ping.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/modules/StockQuote.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/modules/War.class delete mode 100644 bin/main/net/thauvin/erik/mobibot/modules/Weather2.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/modules/WolframAlpha.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/modules/WorldTime.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/msg/ErrorMessage.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/msg/Message.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/msg/NoticeMessage.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/msg/PrivateMessage.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/msg/PublicMessage.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/social/SocialManager.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/social/SocialModule.kt delete mode 100644 bin/main/net/thauvin/erik/mobibot/social/SocialTimer.kt delete mode 100644 bin/test/current.xml delete mode 100644 bin/test/net/thauvin/erik/mobibot/AddonsTest.kt delete mode 100644 bin/test/net/thauvin/erik/mobibot/ExceptionSanitizer.kt delete mode 100644 bin/test/net/thauvin/erik/mobibot/FeedReaderTest.kt delete mode 100644 bin/test/net/thauvin/erik/mobibot/LocalProperties.kt delete mode 100644 bin/test/net/thauvin/erik/mobibot/PinboardTest.kt delete mode 100644 bin/test/net/thauvin/erik/mobibot/UtilsTest.kt delete mode 100644 bin/test/net/thauvin/erik/mobibot/commands/InfoTest.kt delete mode 100644 bin/test/net/thauvin/erik/mobibot/commands/RecapTest.kt delete mode 100644 bin/test/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt delete mode 100644 bin/test/net/thauvin/erik/mobibot/commands/links/ViewTest.kt delete mode 100644 bin/test/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt delete mode 100644 bin/test/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt delete mode 100644 bin/test/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt delete mode 100644 bin/test/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt delete mode 100644 bin/test/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt delete mode 100644 bin/test/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt delete mode 100644 bin/test/net/thauvin/erik/mobibot/modules/CalcTest.kt delete mode 100644 bin/test/net/thauvin/erik/mobibot/modules/ChatGptTest.kt delete mode 100644 bin/test/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt delete mode 100644 bin/test/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt delete mode 100644 bin/test/net/thauvin/erik/mobibot/modules/DiceTest.kt delete mode 100644 bin/test/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt delete mode 100644 bin/test/net/thauvin/erik/mobibot/modules/JokeTest.kt delete mode 100644 bin/test/net/thauvin/erik/mobibot/modules/LookupTest.kt delete mode 100644 bin/test/net/thauvin/erik/mobibot/modules/MastodonTest.kt delete mode 100644 bin/test/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt delete mode 100644 bin/test/net/thauvin/erik/mobibot/modules/PingTest.kt delete mode 100644 bin/test/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt delete mode 100644 bin/test/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt delete mode 100644 bin/test/net/thauvin/erik/mobibot/modules/Weather2Test.kt delete mode 100644 bin/test/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt delete mode 100644 bin/test/net/thauvin/erik/mobibot/modules/WordTimeTest.kt delete mode 100644 bin/test/net/thauvin/erik/mobibot/msg/MessageTest.kt delete mode 100644 src/main/resources/log4j2.xml diff --git a/.gitignore b/.gitignore index fa550e5..6c5fc87 100644 --- a/.gitignore +++ b/.gitignore @@ -54,8 +54,9 @@ atlassian-ide-plugin.xml # Editor-based Rest Client .idea/httpRequests -local.properties - +bin deploy +local.properties logs mobibot.properties +out diff --git a/bin/main/log4j2.xml b/bin/main/log4j2.xml deleted file mode 100644 index 265c88f..0000000 --- a/bin/main/log4j2.xml +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/bin/main/net/thauvin/erik/mobibot/Addons.kt b/bin/main/net/thauvin/erik/mobibot/Addons.kt deleted file mode 100644 index 2c5f05d..0000000 --- a/bin/main/net/thauvin/erik/mobibot/Addons.kt +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Addons.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot - -import net.thauvin.erik.mobibot.Utils.notContains -import net.thauvin.erik.mobibot.commands.AbstractCommand -import net.thauvin.erik.mobibot.commands.links.LinksManager -import net.thauvin.erik.mobibot.modules.AbstractModule -import org.pircbotx.hooks.events.PrivateMessageEvent -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.util.* - -/** - * Modules and Commands addons. - */ -class Addons(private val props: Properties) { - private val logger: Logger = LoggerFactory.getLogger(Addons::class.java) - private val disabledModules = props.getProperty("disabled-modules", "").split(LinksManager.TAG_MATCH) - private val disableCommands = props.getProperty("disabled-commands", "").split(LinksManager.TAG_MATCH) - - val commands: MutableList = mutableListOf() - val modules: MutableList = mutableListOf() - val names = Names - - /** - * Add a module with properties. - */ - fun add(module: AbstractModule): Boolean { - var enabled = false - with(module) { - if (disabledModules.notContains(name, true)) { - if (hasProperties()) { - propertyKeys.forEach { - setProperty(it, props.getProperty(it, "")) - } - } - - if (isEnabled) { - modules.add(this) - names.modules.add(name) - names.commands.addAll(commands) - enabled = true - } else { - if (logger.isDebugEnabled) { - logger.debug("Module $name is disabled.") - } - names.disabledModules.add(name) - } - } else { - names.disabledModules.add(name) - } - } - return enabled - } - - /** - * Add a command with properties. - */ - fun add(command: AbstractCommand): Boolean { - var enabled = false - with(command) { - if (disableCommands.notContains(name, true)) { - if (properties.isNotEmpty()) { - properties.keys.forEach { - setProperty(it, props.getProperty(it, "")) - } - } - if (isEnabled()) { - commands.add(this) - if (isVisible) { - if (isOpOnly) { - names.ops.add(name) - } else { - names.commands.add(name) - } - } - enabled = true - } else { - if (logger.isDebugEnabled) { - logger.debug("Command $name is disabled.") - } - names.disabledCommands.add(name) - } - } else { - names.disabledCommands.add(name) - } - } - return enabled - } - - /** - * Execute a command or module. - */ - fun exec(channel: String, cmd: String, args: String, event: GenericMessageEvent): Boolean { - val cmds = if (event is PrivateMessageEvent) commands else commands.filter { it.isPublic } - for (command in cmds) { - if (command.name.startsWith(cmd)) { - command.commandResponse(channel, args, event) - return true - } - } - val mods = if (event is PrivateMessageEvent) modules.filter { it.isPrivateMsgEnabled } else modules - for (module in mods) { - if (module.commands.contains(cmd)) { - module.commandResponse(channel, cmd, args, event) - return true - } - } - return false - } - - /** - * Match a command. - */ - fun match(channel: String, event: GenericMessageEvent): Boolean { - for (command in commands) { - if (command.matches(event.message)) { - command.commandResponse(channel, event.message, event) - return true - } - } - return false - } - - /** - * Commands and Modules help. - */ - fun help(channel: String, topic: String, event: GenericMessageEvent): Boolean { - for (command in commands) { - if (command.isVisible && command.name.startsWith(topic)) { - return command.helpResponse(channel, topic, event) - } - } - for (module in modules) { - if (module.commands.contains(topic)) { - return module.helpResponse(event) - } - } - return false - } - - /** - * Holds commands and modules names. - */ - object Names { - val modules: MutableList = mutableListOf() - val disabledModules: MutableList = mutableListOf() - val commands: MutableList = mutableListOf() - val disabledCommands: MutableList = mutableListOf() - val ops: MutableList = mutableListOf() - - fun sort() { - modules.sort() - disabledModules.sort() - commands.sort() - disabledCommands.sort() - ops.sort() - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/Constants.kt b/bin/main/net/thauvin/erik/mobibot/Constants.kt deleted file mode 100644 index 98ef74a..0000000 --- a/bin/main/net/thauvin/erik/mobibot/Constants.kt +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Constants.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot - -/** - * The `Constants`. - */ -object Constants { - /** - * The connect/read timeout in ms. - */ - const val CONNECT_TIMEOUT = 5000 - - /** - * Debug command line argument. - */ - const val DEBUG_ARG = "debug" - - /** - * Default IRC Port. - */ - const val DEFAULT_PORT = 6667 - - /** - * Default IRC Server. - */ - const val DEFAULT_SERVER = "irc.libera.chat" - - /** - * CLI command for usage. - */ - const val CLI_CMD = "java -jar ${ReleaseInfo.PROJECT}.jar" - - /** - * User-Agent - */ - const val USER_AGENT = - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36" - - /** - * The help command. - */ - const val HELP_CMD = "help" - - /** - * The link command. - */ - const val LINK_CMD = "L" - - /** - * The empty title string. - */ - const val NO_TITLE = "No Title" - - /** - * Properties command line argument. - */ - const val PROPS_ARG = "properties" - - /** - * The tag command - */ - const val TAG_CMD = "T" - - /** - * The timer delay in minutes. - */ - const val TIMER_DELAY = 10L - - /** - * Properties version line argument. - */ - const val VERSION_ARG = "version" -} diff --git a/bin/main/net/thauvin/erik/mobibot/FeedReader.kt b/bin/main/net/thauvin/erik/mobibot/FeedReader.kt deleted file mode 100644 index d82f011..0000000 --- a/bin/main/net/thauvin/erik/mobibot/FeedReader.kt +++ /dev/null @@ -1,92 +0,0 @@ -/* - * FeedReader.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot - -import com.rometools.rome.io.FeedException -import com.rometools.rome.io.SyndFeedInput -import com.rometools.rome.io.XmlReader -import net.thauvin.erik.mobibot.Utils.green -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.entries.FeedsManager -import net.thauvin.erik.mobibot.msg.Message -import net.thauvin.erik.mobibot.msg.NoticeMessage -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.io.IOException -import java.net.URL - -/** - * Reads an RSS feed. - */ -class FeedReader(private val url: String, val event: GenericMessageEvent) : Runnable { - private val logger: Logger = LoggerFactory.getLogger(FeedsManager::class.java) - - /** - * Fetches the Feed's items. - */ - override fun run() { - try { - readFeed(url).forEach { - event.sendMessage("", it) - } - } catch (e: FeedException) { - if (logger.isWarnEnabled) logger.warn("Unable to parse the feed at $url", e) - event.sendMessage("An error has occurred while parsing the feed: ${e.message}") - } catch (e: IOException) { - if (logger.isWarnEnabled) logger.warn("Unable to fetch the feed at $url", e) - event.sendMessage("An IO error has occurred while fetching the feed: ${e.message}") - } - } - - companion object { - @JvmStatic - @Throws(FeedException::class, IOException::class) - fun readFeed(url: String, maxItems: Int = 5): List { - val messages = mutableListOf() - val input = SyndFeedInput() - XmlReader(URL(url).openStream()).use { reader -> - val feed = input.build(reader) - val items = feed.entries - if (items.isEmpty()) { - messages.add(NoticeMessage("There is currently nothing to view.")) - } else { - items.take(maxItems).forEach { - messages.add(NoticeMessage(it.title)) - messages.add(NoticeMessage(helpFormat(it.link.green(), false))) - } - } - } - return messages - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/Mobibot.kt b/bin/main/net/thauvin/erik/mobibot/Mobibot.kt deleted file mode 100644 index f91c457..0000000 --- a/bin/main/net/thauvin/erik/mobibot/Mobibot.kt +++ /dev/null @@ -1,421 +0,0 @@ -/* - * Mobibot.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot - -import kotlinx.cli.ArgParser -import kotlinx.cli.ArgType -import kotlinx.cli.default -import net.thauvin.erik.mobibot.Utils.appendIfMissing -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.capitalise -import net.thauvin.erik.mobibot.Utils.getIntProperty -import net.thauvin.erik.mobibot.Utils.helpCmdSyntax -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.isChannelOp -import net.thauvin.erik.mobibot.Utils.lastOrEmpty -import net.thauvin.erik.mobibot.Utils.sendList -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.Utils.toIsoLocalDate -import net.thauvin.erik.mobibot.commands.* -import net.thauvin.erik.mobibot.commands.Recap.Companion.storeRecap -import net.thauvin.erik.mobibot.commands.links.* -import net.thauvin.erik.mobibot.commands.seen.Seen -import net.thauvin.erik.mobibot.commands.tell.Tell -import net.thauvin.erik.mobibot.modules.* -import net.thauvin.erik.semver.Version -import org.pircbotx.Configuration -import org.pircbotx.PircBotX -import org.pircbotx.hooks.ListenerAdapter -import org.pircbotx.hooks.events.* -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.io.* -import java.nio.file.Files -import java.nio.file.Paths -import java.util.* -import java.util.regex.Pattern -import kotlin.system.exitProcess - -@Version(properties = "version.properties", className = "ReleaseInfo", template = "version.mustache", type = "kt") -class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Properties) : ListenerAdapter() { - // The bot configuration. - private val config: Configuration - - // Commands and Modules - private val addons: Addons - - // Seen command - private val seen: Seen - - // Tell command - private val tell: Tell - - /** Logger. */ - val logger: Logger = LoggerFactory.getLogger(Mobibot::class.java) - - /** - * Connects to the server and joins the channel. - */ - fun connect() { - PircBotX(config).startBot() - } - - /** - * Responds with the default help. - */ - private fun helpDefault(event: GenericMessageEvent) { - event.sendMessage("Type a URL on $channel to post it.") - event.sendMessage("For more information on a specific command, type:") - event.sendMessage( - helpFormat( - helpCmdSyntax("%c ${Constants.HELP_CMD} ", event.bot().nick, event is PrivateMessageEvent) - ) - ) - event.sendMessage("The commands are:") - event.sendList(addons.names.commands, 8, isBold = true, isIndent = true) - if (event.isChannelOp(channel)) { - if (addons.names.disabledCommands.isNotEmpty()) { - event.sendMessage("The disabled commands are:") - event.sendList(addons.names.disabledCommands, 8, isBold = false, isIndent = true) - } - event.sendMessage("The op commands are:") - event.sendList(addons.names.ops, 8, isBold = true, isIndent = true) - } - } - - /** - * Responds with the default, commands or modules help. - */ - private fun helpResponse(event: GenericMessageEvent, topic: String) { - if (topic.isBlank() || !addons.help(channel, topic.lowercase().trim(), event)) { - helpDefault(event) - } - } - - override fun onAction(event: ActionEvent?) { - event?.channel?.let { - if (channel == it.name) { - event.user?.let { user -> - storeRecap(user.nick, event.action, true) - } - } - } - } - - override fun onDisconnect(event: DisconnectEvent?) { - event?.let { - with(event.getBot()) { - LinksManager.socialManager.notification("$nick disconnected from $serverHostname") - seen.add(userChannelDao.getChannel(channel).users) - } - } - LinksManager.socialManager.shutdown() - } - - override fun onPrivateMessage(event: PrivateMessageEvent?) { - event?.user?.let { user -> - if (logger.isTraceEnabled) logger.trace("<<< ${user.nick}: ${event.message}") - val cmds = event.message.trim().split(" ".toRegex(), 2) - val cmd = cmds[0].lowercase() - val args = cmds.lastOrEmpty().trim() - if (cmd.startsWith(Constants.HELP_CMD)) { // help - helpResponse(event, args) - } else if (!addons.exec(channel, cmd, args, event)) { // Execute command or module - helpDefault(event) - } - } - } - - override fun onJoin(event: JoinEvent?) { - event?.user?.let { user -> - with(event.getBot()) { - if (user.nick == nick) { - LinksManager.socialManager.notification( - "$nick has joined ${event.channel.name} on $serverHostname" - ) - seen.add(userChannelDao.getChannel(channel).users) - } else { - tell.send(event) - seen.add(user.nick) - } - } - } - } - - override fun onMessage(event: MessageEvent?) { - event?.user?.let { user -> - tell.send(event) - if (event.message.matches("(?i)${Pattern.quote(event.bot().nick)}:.*".toRegex())) { // mobibot: - if (logger.isTraceEnabled) logger.trace(">>> ${user.nick}: ${event.message}") - val cmds = event.message.substring(event.bot().nick.length + 1).trim().split(" ".toRegex(), 2) - val cmd = cmds[0].lowercase() - val args = cmds.lastOrEmpty().trim() - if (cmd.startsWith(Constants.HELP_CMD)) { // mobibot: help - helpResponse(event, args) - } else { - // Execute module or command - addons.exec(channel, cmd, args, event) - } - } else if (addons.match(channel, event)) { // Links, e.g.: https://www.example.com/ or L1: , etc. - if (logger.isTraceEnabled) logger.trace(">>> ${user.nick}: ${event.message}") - } - storeRecap(user.nick, event.message, false) - seen.add(user.nick) - } - } - - override fun onNickChange(event: NickChangeEvent?) { - event?.let { - tell.send(event) - if (!it.oldNick.equals(it.newNick, true)) { - seen.add(it.oldNick) - } - seen.add(it.newNick) - } - } - - override fun onPart(event: PartEvent?) { - event?.user?.let { user -> - with(event.getBot()) { - if (user.nick == nick) { - LinksManager.socialManager.notification( - "$nick has left ${event.channel.name} on $serverHostname" - ) - seen.add(userChannelDao.getChannel(channel).users) - } else { - seen.add(user.nick) - } - } - } - } - - override fun onQuit(event: QuitEvent?) { - event?.user?.let { user -> - seen.add(user.nick) - } - } - - companion object { - @JvmStatic - @Throws(Exception::class) - fun main(args: Array) { - // Set up the command line options - val parser = ArgParser(Constants.CLI_CMD) - val debug by parser.option( - ArgType.Boolean, - Constants.DEBUG_ARG, - Constants.DEBUG_ARG.substring(0, 1), - "Print debug & logging data directly to the console" - ).default(false) - val property by parser.option( - ArgType.String, - Constants.PROPS_ARG, - Constants.PROPS_ARG.substring(0, 1), - "Use alternate properties file" - ).default("./${ReleaseInfo.PROJECT}.properties") - val version by parser.option( - ArgType.Boolean, - Constants.VERSION_ARG, - Constants.VERSION_ARG.substring(0, 1), - "Print version info" - ).default(false) - - // Parse the command line - parser.parse(args) - - if (version) { - // Output the version - println( - "${ReleaseInfo.PROJECT.capitalise()} ${ReleaseInfo.VERSION}" + - " (${ReleaseInfo.BUILDDATE.toIsoLocalDate()})" - ) - println(ReleaseInfo.WEBSITE) - } else { - // Load the properties - val p = Properties() - try { - Files.newInputStream( - Paths.get(property) - ).use { fis -> - p.load(fis) - } - } catch (ignore: FileNotFoundException) { - System.err.println("Unable to find properties file.") - exitProcess(1) - } catch (ignore: IOException) { - System.err.println("Unable to open properties file.") - exitProcess(1) - } - val nickname = p.getProperty("nick", Mobibot::class.java.name.lowercase()) - val channel = p.getProperty("channel") - val logsDir = p.getProperty("logs", ".").appendIfMissing(File.separatorChar) - - // Redirect stdout and stderr - if (!debug) { - try { - val stdout = PrintStream( - BufferedOutputStream( - FileOutputStream( - logsDir + channel.substring(1) + '.' + Utils.today() + ".log", true - ) - ), true - ) - System.setOut(stdout) - } catch (ignore: IOException) { - System.err.println("Unable to open output (stdout) log file.") - exitProcess(1) - } - try { - val stderr = PrintStream( - BufferedOutputStream( - FileOutputStream("$logsDir$nickname.err", true) - ), true - ) - System.setErr(stderr) - } catch (ignore: IOException) { - System.err.println("Unable to open error (stderr) log file.") - exitProcess(1) - } - } - - // Start the bot - Mobibot(nickname, channel, logsDir, p).connect() - } - } - } - - /** - * Initialize the bot. - */ - init { - val ircServer = p.getProperty("server", Constants.DEFAULT_SERVER) - config = Configuration.Builder().apply { - name = nickname - login = p.getProperty("login", nickname) - realName = p.getProperty("realname", nickname) - addServer( - ircServer, - p.getIntProperty("port", Constants.DEFAULT_PORT) - ) - addAutoJoinChannel(channel) - addListener(this@Mobibot) - version = "${ReleaseInfo.PROJECT} ${ReleaseInfo.VERSION}" - isAutoNickChange = true - val identPwd = p.getProperty("ident") - if (!identPwd.isNullOrBlank()) { - nickservPassword = identPwd - } - val identNick = p.getProperty("ident-nick") - if (!identNick.isNullOrBlank()) { - nickservNick = identNick - } - val identMsg = p.getProperty("ident-msg") - if (!identMsg.isNullOrBlank()) { - nickservCustomMessage = identMsg - } - isAutoReconnect = true - - //socketConnectTimeout = Constants.CONNECT_TIMEOUT - //socketTimeout = Constants.CONNECT_TIMEOUT - //messageDelay = StaticDelay(500) - }.buildConfiguration() - - // Load the current entries - with(LinksManager) { - entries.channel = channel - entries.ircServer = ircServer - entries.logsDir = logsDirPath - entries.backlogs = p.getProperty("backlogs", "") - entries.load() - - // Set up pinboard - pinboard.setApiToken(p.getProperty("pinboard-api-token", "")) - } - - addons = Addons(p) - - // Load the commands - addons.add(ChannelFeed(channel.removePrefix("#"))) - addons.add(Comment()) - addons.add(Cycle()) - addons.add(Die()) - addons.add(Ignore()) - addons.add(LinksManager()) - addons.add(Me()) - addons.add(Modules(addons.names.modules, addons.names.disabledModules)) - addons.add(Msg()) - addons.add(Nick()) - addons.add(Posting()) - addons.add(Recap()) - addons.add(Say()) - - // Seen command - seen = Seen("${logsDirPath}${nickname}-seen.ser") - addons.add(seen) - - addons.add(Tags()) - - // Tell command - tell = Tell("${logsDirPath}${nickname}.ser") - addons.add(tell) - - addons.add(Users()) - addons.add(Versions()) - addons.add(View()) - - // Load social modules - LinksManager.socialManager.add(addons, Mastodon()) - - // Load the modules - addons.add(Calc()) - addons.add(ChatGpt()) - addons.add(CryptoPrices()) - addons.add(CurrencyConverter()) - addons.add(Dice()) - addons.add(GoogleSearch()) - addons.add(Info(tell, seen)) - addons.add(Joke()) - addons.add(Lookup()) - addons.add(Ping()) - addons.add(RockPaperScissors()) - addons.add(StockQuote()) - addons.add(War()) - addons.add(Weather2()) - addons.add(WolframAlpha()) - addons.add(WorldTime()) - - // Sort the addons - addons.names.sort() - } -} - diff --git a/bin/main/net/thauvin/erik/mobibot/Pinboard.kt b/bin/main/net/thauvin/erik/mobibot/Pinboard.kt deleted file mode 100644 index 7cb5aed..0000000 --- a/bin/main/net/thauvin/erik/mobibot/Pinboard.kt +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Pinboard.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot - -import net.thauvin.erik.mobibot.entries.EntryLink -import net.thauvin.erik.pinboard.PinboardPoster -import java.time.ZoneId -import java.time.ZonedDateTime -import java.time.format.DateTimeFormatter -import java.time.temporal.ChronoUnit -import java.util.* - -/** - * Handles posts to pinboard.in. - */ -class Pinboard { - private val poster = PinboardPoster() - - /** - * Adds a pin. - */ - fun addPin(ircServer: String, entry: EntryLink) { - if (poster.apiToken.isNotBlank()) { - with(entry) { - poster.addPin(link, title, postedBy(ircServer), formatTags(), date.toTimestamp()) - } - } - } - - /** - * Sets the pinboard API token. - */ - fun setApiToken(apiToken: String) { - poster.apiToken = apiToken - } - - /** - * Deletes a pin. - */ - fun deletePin(entry: EntryLink) { - if (poster.apiToken.isNotBlank()) { - poster.deletePin(entry.link) - } - - } - - /** - * Updates a pin. - */ - fun updatePin(ircServer: String, oldUrl: String, entry: EntryLink) { - if (poster.apiToken.isNotBlank()) { - with(entry) { - if (oldUrl != link) { - poster.deletePin(oldUrl) - } - poster.addPin(link, title, postedBy(ircServer), formatTags(), date.toTimestamp()) - } - } - } - - /** - * Formats a date to a UTC timestamp. - */ - private fun Date.toTimestamp(): String { - return ZonedDateTime.ofInstant( - toInstant().truncatedTo(ChronoUnit.SECONDS), ZoneId.systemDefault() - ).format(DateTimeFormatter.ISO_INSTANT) - } - - /** - * Formats the tags for pinboard. - */ - private fun EntryLink.formatTags(): String { - return nick + formatTags(",", ",") - } - - /** - * Returns the pinboard.in extended attribution line. - */ - private fun EntryLink.postedBy(ircServer: String): String { - return "Posted by $nick on $channel ( $ircServer )" - } -} - diff --git a/bin/main/net/thauvin/erik/mobibot/Utils.kt b/bin/main/net/thauvin/erik/mobibot/Utils.kt deleted file mode 100644 index e4760d2..0000000 --- a/bin/main/net/thauvin/erik/mobibot/Utils.kt +++ /dev/null @@ -1,439 +0,0 @@ -/* - * Utils.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot - -import net.thauvin.erik.mobibot.msg.Message -import net.thauvin.erik.mobibot.msg.Message.Companion.DEFAULT_COLOR -import net.thauvin.erik.urlencoder.UrlEncoderUtil -import org.jsoup.Jsoup -import org.pircbotx.Colors -import org.pircbotx.PircBotX -import org.pircbotx.hooks.events.PrivateMessageEvent -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import java.io.* -import java.net.HttpURLConnection -import java.net.URL -import java.nio.file.Files -import java.nio.file.Paths -import java.time.LocalDateTime -import java.time.ZoneId -import java.time.format.DateTimeFormatter -import java.util.* -import kotlin.io.path.exists -import kotlin.io.path.fileSize - -/** - * Miscellaneous utilities. - */ -@Suppress("TooManyFunctions") -object Utils { - private val searchFlags = arrayOf("%c", "%n") - - /** - * Prepends a prefix if not present. - */ - @JvmStatic - fun String.prefixIfMissing(prefix: Char): String { - return if (first() != prefix) { - "$prefix${this}" - } else { - this - } - } - - /** - * Appends a suffix to the end of the String if not present. - */ - @JvmStatic - fun String.appendIfMissing(suffix: Char): String { - return if (last() != suffix) { - "$this${suffix}" - } else { - this - } - } - - /** - * Makes the given int bold. - */ - @JvmStatic - fun Int.bold(): String = toString().bold() - - /** - * Makes the given long bold. - */ - @JvmStatic - fun Long.bold(): String = toString().bold() - - /** - * Makes the given string bold. - */ - @JvmStatic - fun String?.bold(): String = colorize(Colors.BOLD) - - /** - * Returns the [PircBotX] instance. - */ - fun GenericMessageEvent.bot(): PircBotX { - return getBot() as PircBotX - } - - /** - * Capitalize a string. - */ - @JvmStatic - fun String.capitalise(): String = lowercase().replaceFirstChar { it.uppercase() } - - /** - * Capitalize words - */ - @JvmStatic - fun String.capitalizeWords(): String = split(" ").joinToString(" ") { it.capitalise() } - - /** - * Colorize a string. - */ - @JvmStatic - fun String?.colorize(color: String): String { - return when { - isNullOrEmpty() -> { - "" - } - - color == DEFAULT_COLOR -> { - this - } - - Colors.BOLD == color || Colors.REVERSE == color -> { - color + this + color - } - - else -> { - color + this + Colors.NORMAL - } - } - } - - /** - * Makes the given string cyan. - */ - @JvmStatic - fun String?.cyan(): String = colorize(Colors.CYAN) - - /** - * URL encodes the given string. - */ - @JvmStatic - fun String.encodeUrl(): String = UrlEncoderUtil.encode(this) - - /** - * Returns a property as an int. - */ - @JvmStatic - fun Properties.getIntProperty(key: String, defaultValue: Int): Int { - return getProperty(key)?.toIntOrDefault(defaultValue) ?: defaultValue - } - - /** - * Makes the given string green. - */ - @JvmStatic - fun String?.green(): String = colorize(Colors.DARK_GREEN) - - /** - * Build a help command by replacing `%c` with the bot's pub/priv command, and `%n` with the bot's - * nick. - */ - @JvmStatic - fun helpCmdSyntax(text: String, botNick: String, isPrivate: Boolean): String { - val replace = arrayOf(if (isPrivate) "/msg $botNick" else "$botNick:", botNick) - return text.replaceEach(searchFlags, replace) - } - - /** - * Returns a formatted help string. - */ - @JvmStatic - @JvmOverloads - fun helpFormat(help: String, isBold: Boolean = true, isIndent: Boolean = true): String { - val s = if (isBold) help.bold() else help - return if (isIndent) s.prependIndent() else s - } - - /** - * Returns `true` if the specified user is an operator on the [channel]. - */ - @JvmStatic - fun GenericMessageEvent.isChannelOp(channel: String): Boolean { - return this.bot().userChannelDao.getChannel(channel).isOp(this.user) - } - - /** - * Returns `true` if a HTTP status code indicates a successful response. - */ - @JvmStatic - fun Int.isHttpSuccess() = this in 200..399 - - /** - * Returns the last item of a list of strings or empty if none. - */ - @JvmStatic - fun List.lastOrEmpty(): String { - return if (this.size >= 2) { - this.last() - } else - "" - } - - /** - * Load serial data from file. - */ - @JvmStatic - fun loadSerialData(file: String, default: Any, logger: Logger, description: String): Any { - val serialFile = Paths.get(file) - if (serialFile.exists() && serialFile.fileSize() > 0) { - try { - ObjectInputStream( - BufferedInputStream(Files.newInputStream(serialFile)) - ).use { input -> - if (logger.isDebugEnabled) logger.debug("Loading the ${description}.") - return input.readObject() - } - } catch (e: IOException) { - logger.error("An IO error occurred loading the ${description}.", e) - } catch (e: ClassNotFoundException) { - logger.error("An error occurred loading the ${description}.", e) - } - } - return default - } - - /** - * Returns `true` if the list does not contain the given string. - */ - @JvmStatic - fun List.notContains(text: String, ignoreCase: Boolean = false) = this.none { it.equals(text, ignoreCase) } - - /** - * Obfuscates the given string. - */ - @JvmStatic - fun String.obfuscate(): String { - return if (isNotBlank()) { - "x".repeat(length) - } else this - } - - /** - * Returns the plural form of a word, if count > 1. - */ - @JvmStatic - fun String.plural(count: Long): String { - return if (count > 1) "${this}s" else this - } - - /** - * Makes the given string red. - */ - @JvmStatic - fun String?.red(): String = colorize(Colors.RED) - - /** - * Replaces all occurrences of Strings within another String. - */ - @JvmStatic - fun String.replaceEach(search: Array, replace: Array): String { - var result = this - if (search.size == replace.size) { - search.forEachIndexed { i, s -> - result = result.replace(s, replace[i]) - } - } - return result - } - - /** - * Makes the given string reverse color. - */ - @JvmStatic - fun String?.reverseColor(): String = colorize(Colors.REVERSE) - - /** - * Save data - */ - @JvmStatic - fun saveSerialData(file: String, data: Any, logger: Logger, description: String) { - try { - BufferedOutputStream(Files.newOutputStream(Paths.get(file))).use { bos -> - ObjectOutputStream(bos).use { output -> - if (logger.isDebugEnabled) logger.debug("Saving the ${description}.") - output.writeObject(data) - } - } - } catch (e: IOException) { - logger.error("Unable to save the ${description}.", e) - } - } - - /** - * Send a formatted commands/modules, etc. list. - */ - @JvmStatic - @JvmOverloads - fun GenericMessageEvent.sendList( - list: List, - maxPerLine: Int, - separator: String = " ", - isBold: Boolean = false, - isIndent: Boolean = false - ) { - var i = 0 - while (i < list.size) { - sendMessage( - helpFormat( - list.subList(i, list.size.coerceAtMost(i + maxPerLine)).joinToString(separator, truncated = ""), - isBold, - isIndent - ), - ) - i += maxPerLine - } - } - - /** - * Sends a [message]. - */ - @JvmStatic - fun GenericMessageEvent.sendMessage(channel: String, message: Message) { - if (message.isNotice) { - bot().sendIRC().notice(user.nick, message.msg.colorize(message.color)) - } else if (message.isPrivate || this is PrivateMessageEvent || channel.isBlank()) { - respondPrivateMessage(message.msg.colorize(message.color)) - } else { - bot().sendIRC().message(channel, message.msg.colorize(message.color)) - } - } - - /** - * Sends a response as a private message or notice. - */ - @JvmStatic - fun GenericMessageEvent.sendMessage(message: String) { - if (this is PrivateMessageEvent) { - respondPrivateMessage(message) - } else { - bot().sendIRC().notice(user.nick, message) - } - } - - /** - * Returns today's date. - */ - @JvmStatic - fun today(): String = LocalDateTime.now().toIsoLocalDate() - - /** - * Converts a string to an int. - */ - @JvmStatic - fun String.toIntOrDefault(defaultValue: Int): Int { - return try { - toInt() - } catch (e: NumberFormatException) { - defaultValue - } - } - - /** - * Returns the specified date as an ISO local date string. - */ - @JvmStatic - fun Date.toIsoLocalDate(): String { - return LocalDateTime.ofInstant(toInstant(), ZoneId.systemDefault()).toIsoLocalDate() - } - - /** - * Returns the specified date as an ISO local date string. - */ - @JvmStatic - fun LocalDateTime.toIsoLocalDate(): String = format(DateTimeFormatter.ISO_LOCAL_DATE) - - /** - * Returns the specified date formatted as `yyyy-MM-dd HH:mm`. - */ - @JvmStatic - fun Date.toUtcDateTime(): String { - return LocalDateTime.ofInstant(toInstant(), ZoneId.systemDefault()).toUtcDateTime() - } - - /** - * Returns the specified date formatted as `yyyy-MM-dd HH:mm`. - */ - @JvmStatic - fun LocalDateTime.toUtcDateTime(): String = format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")) - - /** - * Makes the given string bold. - */ - @JvmStatic - fun String?.underline(): String = colorize(Colors.UNDERLINE) - - - /** - * Converts XML/XHTML entities to plain text. - */ - @JvmStatic - fun String.unescapeXml(): String = Jsoup.parse(this).text() - - /** - * Reads contents of a URL. - */ - @JvmStatic - @Throws(IOException::class) - fun URL.reader(): UrlReaderResponse { - val connection = this.openConnection() as HttpURLConnection - connection.setRequestProperty( - "User-Agent", - "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/109.0" - ) - return if (connection.responseCode.isHttpSuccess()) { - UrlReaderResponse(connection.responseCode, connection.inputStream.bufferedReader().use { it.readText() }) - } else { - UrlReaderResponse(connection.responseCode, connection.errorStream.bufferedReader().use { it.readText() }) - } - } - - /** - * Holds the [URL.reader] response code and body text. - */ - data class UrlReaderResponse(val responseCode: Int, val body: String) -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/AbstractCommand.kt b/bin/main/net/thauvin/erik/mobibot/commands/AbstractCommand.kt deleted file mode 100644 index 5f79472..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/AbstractCommand.kt +++ /dev/null @@ -1,79 +0,0 @@ -/* - * AbstractCommand.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands - -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpCmdSyntax -import net.thauvin.erik.mobibot.Utils.isChannelOp -import net.thauvin.erik.mobibot.Utils.sendMessage -import org.pircbotx.hooks.events.PrivateMessageEvent -import org.pircbotx.hooks.types.GenericMessageEvent - -abstract class AbstractCommand { - abstract val name: String - abstract val help: List - abstract val isOpOnly: Boolean - abstract val isPublic: Boolean - abstract val isVisible: Boolean - - val properties: MutableMap = mutableMapOf() - - abstract fun commandResponse(channel: String, args: String, event: GenericMessageEvent) - - open fun helpResponse(channel: String, topic: String, event: GenericMessageEvent): Boolean { - if (!isOpOnly || isOpOnly == event.isChannelOp(channel)) { - for (h in help) { - event.sendMessage(helpCmdSyntax(h, event.bot().nick, event is PrivateMessageEvent || !isPublic)) - } - return true - } - return false - } - - open fun initProperties(vararg keys: String) { - keys.forEach { - properties[it] = "" - } - } - - open fun isEnabled(): Boolean { - return true - } - - open fun matches(message: String): Boolean { - return false - } - - open fun setProperty(key: String, value: String) { - properties[key] = value - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/ChannelFeed.kt b/bin/main/net/thauvin/erik/mobibot/commands/ChannelFeed.kt deleted file mode 100644 index 038e378..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/ChannelFeed.kt +++ /dev/null @@ -1,62 +0,0 @@ -/* - * ChannelFeed.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands - -import net.thauvin.erik.mobibot.FeedReader -import net.thauvin.erik.mobibot.Utils.helpFormat -import org.pircbotx.hooks.types.GenericMessageEvent - -class ChannelFeed(channel: String) : AbstractCommand() { - override val name = channel - override val help = listOf("To list the last 5 posts from the channel's weblog feed:", helpFormat("%c $channel")) - override val isOpOnly = false - override val isPublic = true - override val isVisible = true - - companion object { - const val FEED_PROP = "feed" - } - - init { - initProperties(FEED_PROP) - } - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - if (isEnabled()) { - properties[FEED_PROP]?.let { FeedReader(it, event).run() } - } - } - - override fun isEnabled(): Boolean { - return !properties[FEED_PROP].isNullOrBlank() - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Cycle.kt b/bin/main/net/thauvin/erik/mobibot/commands/Cycle.kt deleted file mode 100644 index 9608ca8..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/Cycle.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Cycle.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands - -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.isChannelOp -import org.pircbotx.hooks.types.GenericMessageEvent - -class Cycle : AbstractCommand() { - private val wait = 10 - override val name = "cycle" - override val help = listOf("To have the bot leave the channel and come back:", helpFormat("%c $name")) - override val isOpOnly = true - override val isPublic = false - override val isVisible = true - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - with(event.bot()) { - if (event.isChannelOp(channel)) { - runBlocking { - launch { - sendIRC().message(channel, "${event.user.nick} asked me to leave. I'll be back!") - userChannelDao.getChannel(channel).send().part() - delay(wait * 1000L) - sendIRC().joinChannel(channel) - } - } - } else { - helpResponse(channel, args, event) - } - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Die.kt b/bin/main/net/thauvin/erik/mobibot/commands/Die.kt deleted file mode 100644 index f271bfa..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/Die.kt +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Die.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands - -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.isChannelOp -import org.pircbotx.hooks.types.GenericMessageEvent - -class Die : AbstractCommand() { - override val name = "die" - override val help = emptyList() - override val isOpOnly = true - override val isPublic = false - override val isVisible = false - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - with(event.bot()) { - if (event.isChannelOp(channel) && (properties[DIE_PROP].isNullOrBlank() || args == properties[DIE_PROP])) { - sendIRC().message(channel, "${event.user?.nick} has just signed my death sentence.") - stopBotReconnect() - sendIRC().quitServer("The Bot is Out There!") - } - } - } - - companion object { - const val DIE_PROP = "die" - } - - init { - initProperties(DIE_PROP) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Ignore.kt b/bin/main/net/thauvin/erik/mobibot/commands/Ignore.kt deleted file mode 100644 index d083c10..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/Ignore.kt +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Ignore.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands - -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpCmdSyntax -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.isChannelOp -import net.thauvin.erik.mobibot.Utils.sendList -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.commands.links.LinksManager -import org.pircbotx.hooks.types.GenericMessageEvent - -class Ignore : AbstractCommand() { - private val me = "me" - - init { - initProperties(IGNORE_PROP) - } - - override val name = IGNORE_CMD - override val help = listOf( - "To ignore a link posted to the channel:", - helpFormat("https://www.foo.bar %n"), - "To check your ignore status:", - helpFormat("%c $name"), - "To toggle your ignore status:", - helpFormat("%c $name $me") - ) - private val helpOp = help.plus( - arrayOf("To add/remove nicks from the ignored list:", helpFormat("%c $name [ ...]")) - ) - - override val isOpOnly = false - override val isPublic = true - override val isVisible = true - - companion object { - const val IGNORE_CMD = "ignore" - const val IGNORE_PROP = IGNORE_CMD - private val ignored = mutableSetOf() - - @JvmStatic - fun isNotIgnored(nick: String): Boolean { - return !ignored.contains(nick.lowercase()) - } - } - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - val isMe = args.trim().equals(me, true) - if (isMe || !event.isChannelOp(channel)) { - val nick = event.user.nick.lowercase() - ignoreNick(nick, isMe, event) - } else { - ignoreOp(args, event) - } - } - - override fun helpResponse(channel: String, topic: String, event: GenericMessageEvent): Boolean { - return if (event.isChannelOp(channel)) { - for (h in helpOp) { - event.sendMessage(helpCmdSyntax(h, event.bot().nick, true)) - } - true - } else { - super.helpResponse(channel, topic, event) - } - } - - private fun ignoreNick(sender: String, isMe: Boolean, event: GenericMessageEvent) { - if (isMe) { - if (ignored.remove(sender)) { - event.sendMessage("You are no longer ignored.") - } else { - ignored.add(sender) - event.sendMessage("You are now ignored.") - } - } else { - if (ignored.contains(sender)) { - event.sendMessage("You are currently ignored.") - } else { - event.sendMessage("You are not currently ignored.") - } - } - } - - private fun ignoreOp(args: String, event: GenericMessageEvent) { - if (args.isNotEmpty()) { - val nicks = args.lowercase().split(" ") - for (nick in nicks) { - val ignore = if (me == nick) { - nick.lowercase() - } else { - nick - } - if (!ignored.remove(ignore)) { - ignored.add(ignore) - } - } - } - - if (ignored.isNotEmpty()) { - event.sendMessage("The following nicks are ignored:") - event.sendList(ignored.sorted(), 8, isIndent = true) - } else { - event.sendMessage("No one is currently ${"ignored".bold()}.") - } - } - - override fun setProperty(key: String, value: String) { - super.setProperty(key, value) - if (IGNORE_PROP == key) { - ignored.addAll(value.split(LinksManager.TAG_MATCH)) - } - } - -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Info.kt b/bin/main/net/thauvin/erik/mobibot/commands/Info.kt deleted file mode 100644 index ed0b6ef..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/Info.kt +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Info.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.commands - -import net.thauvin.erik.mobibot.ReleaseInfo -import net.thauvin.erik.mobibot.Utils.capitalise -import net.thauvin.erik.mobibot.Utils.green -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.isChannelOp -import net.thauvin.erik.mobibot.Utils.plural -import net.thauvin.erik.mobibot.Utils.sendList -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.commands.links.LinksManager -import net.thauvin.erik.mobibot.commands.seen.Seen -import net.thauvin.erik.mobibot.commands.tell.Tell -import org.pircbotx.hooks.types.GenericMessageEvent -import java.lang.management.ManagementFactory -import kotlin.time.DurationUnit -import kotlin.time.toDuration - -class Info(private val tell: Tell, private val seen: Seen) : AbstractCommand() { - private val allVersions = listOf( - "${ReleaseInfo.PROJECT.capitalise()} ${ReleaseInfo.VERSION} (${ReleaseInfo.WEBSITE.green()})", - "Written by ${ReleaseInfo.AUTHOR} (${ReleaseInfo.AUTHOR_URL.green()})" - ) - override val name = "info" - override val help = listOf("To view information about the bot:", helpFormat("%c $name")) - override val isOpOnly = false - override val isPublic = true - override val isVisible = true - - companion object { - /** - * Converts milliseconds to year month week day hour and minutes. - */ - @JvmStatic - fun Long.toUptime(): String { - this.toDuration(DurationUnit.MILLISECONDS).toComponents { wholeDays, hours, minutes, seconds, _ -> - val years = wholeDays / 365 - var days = wholeDays % 365 - val months = days / 30 - days %= 30 - val weeks = days / 7 - days %= 7 - - with(StringBuffer()) { - if (years > 0) { - append(years).append(" year".plural(years)).append(' ') - } - if (months > 0) { - append(months).append(" month".plural(months)).append(' ') - } - if (weeks > 0) { - append(weeks).append(" week".plural(weeks)).append(' ') - } - if (days > 0) { - append(days).append(" day".plural(days)).append(' ') - } - if (hours > 0) { - append(hours).append(" hour".plural(hours.toLong())).append(' ') - } - - if (minutes > 0) { - append(minutes).append(" minute".plural(minutes.toLong())) - } else { - append(seconds).append(" second".plural(seconds.toLong())) - } - - return toString() - } - } - } - } - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - event.sendList(allVersions, 1) - val info = StringBuilder() - info.append("Uptime: ") - .append(ManagementFactory.getRuntimeMXBean().uptime.toUptime()) - .append(" [Entries: ") - .append(LinksManager.entries.links.size) - if (seen.isEnabled()) { - info.append(", Seen: ").append(seen.count()) - } - if (event.isChannelOp(channel)) { - if (tell.isEnabled()) { - info.append(", Messages: ").append(tell.size()) - } - if (LinksManager.socialManager.entriesCount() > 0) { - info.append(", Social: ").append(LinksManager.socialManager.entriesCount()) - } - } - info.append(", Recap: ").append(Recap.recaps.size).append(']') - event.sendMessage(info.toString()) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Me.kt b/bin/main/net/thauvin/erik/mobibot/commands/Me.kt deleted file mode 100644 index ec7823b..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/Me.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Me.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands - -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.isChannelOp -import org.pircbotx.hooks.types.GenericMessageEvent - -class Me : AbstractCommand() { - override val name = "me" - override val help = listOf("To have the bot perform an action:", helpFormat("%c $name ")) - override val isOpOnly = true - override val isPublic = false - override val isVisible = true - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - if (event.isChannelOp(channel)) { - event.bot().sendIRC().action(channel, args) - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Modules.kt b/bin/main/net/thauvin/erik/mobibot/commands/Modules.kt deleted file mode 100644 index b2293b0..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/Modules.kt +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Modules.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands - -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.isChannelOp -import net.thauvin.erik.mobibot.Utils.sendList -import org.pircbotx.hooks.types.GenericMessageEvent - -class Modules(private val modules: List, private val disabledModules: List) : AbstractCommand() { - override val name = "modules" - override val help = listOf("To view a list of enabled/disabled modules:", helpFormat("%c $name")) - override val isOpOnly = true - override val isPublic = false - override val isVisible = true - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - if (event.isChannelOp(channel)) { - if (modules.isEmpty()) { - event.respondPrivateMessage("There are no enabled modules.") - } else { - event.respondPrivateMessage("The enabled modules are: ") - event.sendList(modules, 7, isIndent = true) - } - if (disabledModules.isNotEmpty()) { - event.respondPrivateMessage("The disabled modules are: ") - event.sendList(disabledModules, 7, isIndent = true) - } - } else { - helpResponse(channel, args, event) - } - } -} - diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Msg.kt b/bin/main/net/thauvin/erik/mobibot/commands/Msg.kt deleted file mode 100644 index 20a6635..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/Msg.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Msg.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands - -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.isChannelOp -import org.pircbotx.hooks.types.GenericMessageEvent - -class Msg : AbstractCommand() { - override val name = "msg" - override val help = listOf( - "To have the bot send a private message to someone:", - helpFormat("%c $name ") - ) - override val isOpOnly = true - override val isPublic = false - override val isVisible = true - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - if (event.isChannelOp(channel)) { - val msg = args.split(" ", limit = 2) - if (args.length > 2) { - event.bot().sendIRC().message(msg[0], msg[1]) - event.respondPrivateMessage("A message was sent to ${msg[0]}") - } else { - helpResponse(channel, args, event) - } - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Nick.kt b/bin/main/net/thauvin/erik/mobibot/commands/Nick.kt deleted file mode 100644 index 85a03ab..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/Nick.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Nick.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands - -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.isChannelOp -import org.pircbotx.hooks.types.GenericMessageEvent - -class Nick : AbstractCommand() { - override val name = "nick" - override val help = listOf("To change the bot's nickname:", helpFormat("%c $name ")) - override val isOpOnly = true - override val isPublic = true - override val isVisible = true - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - if (event.isChannelOp(channel)) { - event.bot().sendIRC().changeNick(args) - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Recap.kt b/bin/main/net/thauvin/erik/mobibot/commands/Recap.kt deleted file mode 100644 index 77154c7..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/Recap.kt +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Recap.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands - -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.Utils.toUtcDateTime -import org.pircbotx.hooks.types.GenericMessageEvent -import java.time.Clock -import java.time.LocalDateTime - -class Recap : AbstractCommand() { - override val name = "recap" - override val help = listOf( - "To list the last 10 public channel messages:", - helpFormat("%c $name") - ) - override val isOpOnly = false - override val isPublic = true - override val isVisible = true - - companion object { - const val MAX_RECAPS = 10 - - @JvmField - val recaps = mutableListOf() - - /** - * Stores the last 10 public messages and actions. - */ - @JvmStatic - fun storeRecap(sender: String, message: String, isAction: Boolean) { - recaps.add( - LocalDateTime.now(Clock.systemUTC()).toUtcDateTime() - + " - $sender" + (if (isAction) " " else ": ") + message - ) - if (recaps.size > MAX_RECAPS) { - recaps.removeFirst() - } - } - } - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - if (recaps.isNotEmpty()) { - for (r in recaps) { - event.sendMessage(r) - } - } else { - event.sendMessage("Sorry, nothing to recap.") - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Say.kt b/bin/main/net/thauvin/erik/mobibot/commands/Say.kt deleted file mode 100644 index 7f76d35..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/Say.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Say.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands - -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.isChannelOp -import org.pircbotx.hooks.types.GenericMessageEvent - -class Say : AbstractCommand() { - override val name = "say" - override val help = listOf("To have the bot say something on the channel:", helpFormat("%c $name ")) - override val isOpOnly = true - override val isPublic = false - override val isVisible = true - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - if (event.isChannelOp(channel)) { - event.bot().sendIRC().message(channel, args) - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Users.kt b/bin/main/net/thauvin/erik/mobibot/commands/Users.kt deleted file mode 100644 index 33d6fef..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/Users.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Users.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands - -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.sendList -import org.pircbotx.hooks.types.GenericMessageEvent - -class Users : AbstractCommand() { - override val name = "users" - override val help = listOf("To list the users present on the channel:", helpFormat("%c $name")) - override val isOpOnly = false - override val isPublic = true - override val isVisible = true - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - val ch = event.bot().userChannelDao.getChannel(channel) - event.sendList(ch.users.map { if (it.channelsOpIn.contains(ch)) "@${it.nick}" else it.nick }, 8) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Versions.kt b/bin/main/net/thauvin/erik/mobibot/commands/Versions.kt deleted file mode 100644 index 896c569..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/Versions.kt +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Versions.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.commands - -import net.thauvin.erik.mobibot.ReleaseInfo -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.isChannelOp -import net.thauvin.erik.mobibot.Utils.sendList -import net.thauvin.erik.mobibot.Utils.toIsoLocalDate -import org.pircbotx.PircBotX -import org.pircbotx.hooks.types.GenericMessageEvent - -class Versions : AbstractCommand() { - private val allVersions = listOf( - "Version: ${ReleaseInfo.VERSION} (${ReleaseInfo.BUILDDATE.toIsoLocalDate()})", - "${System.getProperty("os.name")} ${System.getProperty("os.version")} (${System.getProperty("os.arch")})" + - ", JVM ${System.getProperty("java.runtime.version")}", - "Kotlin ${KotlinVersion.CURRENT}, PircBotX ${PircBotX.VERSION}" - ) - override val name = "versions" - override val help = listOf("To view the versions data (bot, platform, java, etc.):", helpFormat("%c $name")) - override val isOpOnly = true - override val isPublic = false - override val isVisible = true - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - if (event.isChannelOp(channel)) { - event.sendList(allVersions, 1) - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/links/Comment.kt b/bin/main/net/thauvin/erik/mobibot/commands/links/Comment.kt deleted file mode 100644 index 1443d44..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/links/Comment.kt +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Comment.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands.links - -import net.thauvin.erik.mobibot.Constants -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.isChannelOp -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.commands.AbstractCommand -import net.thauvin.erik.mobibot.entries.EntriesUtils.printComment -import net.thauvin.erik.mobibot.entries.EntriesUtils.toLinkLabel -import net.thauvin.erik.mobibot.entries.EntryLink -import org.pircbotx.hooks.types.GenericMessageEvent - -class Comment : AbstractCommand() { - override val name = COMMAND - override val help = listOf( - "To add a comment:", - helpFormat("${Constants.LINK_CMD}1:This is a comment"), - "I will reply with a label, for example: ${Constants.LINK_CMD.bold()}1.1", - "To edit a comment, use its label: ", - helpFormat("${Constants.LINK_CMD}1.1:This is an edited comment"), - "To delete a comment, use its label and a minus sign: ", - helpFormat("${Constants.LINK_CMD}1.1:-") - ) - override val isOpOnly = false - override val isPublic = true - override val isVisible = true - - companion object { - const val COMMAND = "comment" - } - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - val cmds = args.substring(1).split("[.:]".toRegex(), 3) - val entryIndex = cmds[0].toInt() - 1 - - if (entryIndex < LinksManager.entries.links.size && LinksManager.isUpToDate(event)) { - val entry: EntryLink = LinksManager.entries.links[entryIndex] - val commentIndex = cmds[1].toInt() - 1 - if (commentIndex < entry.comments.size) { - when (val cmd = cmds[2].trim()) { - "" -> showComment(entry, entryIndex, commentIndex, event) // L1.1: - "-" -> deleteComment(channel, entry, entryIndex, commentIndex, event) // L1.1:- - else -> { - if (cmd.startsWith('?')) { // L1.1:? - changeAuthor(channel, cmd, entry, entryIndex, commentIndex, event) - } else { // L1.1: - setComment(cmd, entry, entryIndex, commentIndex, event) - } - } - } - } - } - } - - override fun helpResponse(channel: String, topic: String, event: GenericMessageEvent): Boolean { - if (super.helpResponse(channel, topic, event)) { - if (event.isChannelOp(channel)) { - event.sendMessage("To change a comment's author:") - event.sendMessage(helpFormat("${Constants.LINK_CMD}1.1:?")) - } - return true - } - return false - } - - override fun matches(message: String): Boolean { - return message.matches("^${Constants.LINK_CMD}\\d+\\.\\d+:.*".toRegex()) - } - - private fun changeAuthor( - channel: String, - cmd: String, - entry: EntryLink, - entryIndex: Int, - commentIndex: Int, - event: GenericMessageEvent - ) { - if (event.isChannelOp(channel) && cmd.length > 1) { - val comment = entry.getComment(commentIndex) - comment.nick = cmd.substring(1) - event.sendMessage(printComment(entryIndex, commentIndex, comment)) - LinksManager.entries.save() - } else { - event.sendMessage("Please ask a channel op to change the author of this comment for you.") - } - } - - private fun deleteComment( - channel: String, - entry: EntryLink, - entryIndex: Int, - commentIndex: Int, - event: GenericMessageEvent - ) { - if (event.isChannelOp(channel) || event.user.nick == entry.getComment(commentIndex).nick) { - entry.deleteComment(commentIndex) - event.sendMessage("Comment ${entryIndex.toLinkLabel()}.${commentIndex + 1} removed.") - LinksManager.entries.save() - } else { - event.sendMessage("Please ask a channel op to delete this comment for you.") - } - } - - private fun setComment( - cmd: String, - entry: EntryLink, - entryIndex: Int, - commentIndex: Int, - event: GenericMessageEvent - ) { - entry.setComment(commentIndex, cmd, event.user.nick) - event.sendMessage(printComment(entryIndex, commentIndex, entry.getComment(commentIndex))) - LinksManager.entries.save() - } - - private fun showComment(entry: EntryLink, entryIndex: Int, commentIndex: Int, event: GenericMessageEvent) { - event.sendMessage(printComment(entryIndex, commentIndex, entry.getComment(commentIndex))) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/links/LinksManager.kt b/bin/main/net/thauvin/erik/mobibot/commands/links/LinksManager.kt deleted file mode 100644 index fba6b99..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/links/LinksManager.kt +++ /dev/null @@ -1,207 +0,0 @@ -/* - * LinksManager.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands.links - -import net.thauvin.erik.mobibot.Constants -import net.thauvin.erik.mobibot.Pinboard -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.Utils.today -import net.thauvin.erik.mobibot.commands.AbstractCommand -import net.thauvin.erik.mobibot.commands.Ignore.Companion.isNotIgnored -import net.thauvin.erik.mobibot.entries.Entries -import net.thauvin.erik.mobibot.entries.EntriesUtils.printLink -import net.thauvin.erik.mobibot.entries.EntriesUtils.toLinkLabel -import net.thauvin.erik.mobibot.entries.EntryLink -import net.thauvin.erik.mobibot.social.SocialManager -import org.jsoup.Jsoup -import org.pircbotx.hooks.types.GenericMessageEvent -import java.io.IOException - -class LinksManager : AbstractCommand() { - private val defaultTags: MutableList = mutableListOf() - private val keywords: MutableList = mutableListOf() - - override val name = Constants.LINK_CMD - override val help = emptyList() - override val isOpOnly = false - override val isPublic = false - override val isVisible = false - - init { - initProperties(TAGS_PROP, KEYWORDS_PROP) - } - - companion object { - val LINK_MATCH = "^[hH][tT][tT][pP](|[sS])://.*".toRegex() - const val KEYWORDS_PROP = "tags-keywords" - const val TAGS_PROP = "tags" - val TAG_MATCH = ", *| +".toRegex() - - /** - * Entries array - */ - @JvmField - val entries = Entries() - - /** - * Pinboard handler. - */ - @JvmField - val pinboard = Pinboard() - - /** - * Social Manager handler. - */ - @JvmField - val socialManager = SocialManager() - - /** - * Let the user know if the entries are too old to be modified. - */ - @JvmStatic - fun isUpToDate(event: GenericMessageEvent): Boolean { - if (entries.lastPubDate != today()) { - event.sendMessage("The links are too old to be updated.") - return false - } - return true - } - } - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - val cmds = args.split(" ".toRegex(), 2) - val sender = event.user.nick - val botNick = event.bot().nick - val login = event.user.login - - if (isNotIgnored(sender) && (cmds.size == 1 || !cmds[1].contains(botNick))) { - val link = cmds[0].trim() - if (!isDupEntry(link, event)) { - var title = "" - val tags = ArrayList(defaultTags) - if (cmds.size == 2) { - val data = cmds[1].trim().split("${Tags.COMMAND}:", limit = 2) - title = data[0].trim() - if (data.size > 1) { - tags.addAll(data[1].split(TAG_MATCH)) - } - } - - if (title.isBlank()) { - title = fetchTitle(link) - } - - if (title != Constants.NO_TITLE) { - matchTagKeywords(title, tags) - } - - // Links are old, clear them - if (entries.lastPubDate != today()) { - entries.links.clear() - } - - val entry = EntryLink(link, title, sender, login, channel, tags) - entries.links.add(entry) - val index = entries.links.lastIndexOf(entry) - event.sendMessage(printLink(index, entry)) - - pinboard.addPin(event.bot().serverHostname, entry) - - // Queue link for posting to social media. - socialManager.queueEntry(index) - - entries.save() - - if (Constants.NO_TITLE == entry.title) { - event.sendMessage("Please specify a title, by typing:") - event.sendMessage(helpFormat("${index.toLinkLabel()}:|This is the title")) - } - } - } - } - - override fun helpResponse(channel: String, topic: String, event: GenericMessageEvent): Boolean = false - - override fun matches(message: String): Boolean { - return message.matches(LINK_MATCH) - } - - internal fun fetchTitle(link: String): String { - try { - val html = Jsoup.connect(link) - .userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0") - .get() - val title = html.title() - if (title.isNotBlank()) { - return title - } - } catch (ignore: IOException) { - // Do nothing - } - return Constants.NO_TITLE - } - - private fun isDupEntry(link: String, event: GenericMessageEvent): Boolean { - synchronized(entries) { - return try { - val match = entries.links.single { it.link == link } - event.sendMessage( - "Duplicate".bold() + " >> " + printLink(entries.links.indexOf(match), match) - ) - true - } catch (ignore: NoSuchElementException) { - false - } - } - } - - internal fun matchTagKeywords(title: String, tags: MutableList) { - for (match in keywords) { - val m = Regex.escape(match) - if (title.matches("(?i).*\\b$m\\b.*".toRegex())) { - tags.add(match) - } - } - } - - override fun setProperty(key: String, value: String) { - super.setProperty(key, value) - if (KEYWORDS_PROP == key) { - keywords.addAll(value.split(TAG_MATCH)) - } else if (TAGS_PROP == key) { - defaultTags.addAll(value.split(TAG_MATCH)) - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/links/Posting.kt b/bin/main/net/thauvin/erik/mobibot/commands/links/Posting.kt deleted file mode 100644 index ff4278d..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/links/Posting.kt +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Posting.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands.links - -import net.thauvin.erik.mobibot.Constants -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.isChannelOp -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.commands.AbstractCommand -import net.thauvin.erik.mobibot.commands.links.LinksManager.Companion.entries -import net.thauvin.erik.mobibot.entries.EntriesUtils -import net.thauvin.erik.mobibot.entries.EntriesUtils.toLinkLabel -import net.thauvin.erik.mobibot.entries.EntryLink -import org.pircbotx.hooks.types.GenericMessageEvent - -class Posting : AbstractCommand() { - override val name = "posting" - override val help = listOf( - "Post a URL, by saying it on a line on its own:", - helpFormat(" [] ${Tags.COMMAND}: <+tag> [...]]"), - "I will reply with a label, for example: ${Constants.LINK_CMD.bold()}1", - "To add a title, use its label and a pipe:", - helpFormat("${Constants.LINK_CMD}1:|This is the title"), - "To add a comment:", - helpFormat("${Constants.LINK_CMD}1:This is a comment"), - "I will reply with a label, for example: ${Constants.LINK_CMD.bold()}1.1", - "To edit a comment, see: ", - helpFormat("%c ${Constants.HELP_CMD} ${Comment.COMMAND}") - ) - override val isOpOnly = false - override val isPublic = true - override val isVisible = true - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - val cmds = args.substring(1).split(":", limit = 2) - val entryIndex = cmds[0].toInt() - 1 - - if (entryIndex < entries.links.size) { - val cmd = cmds[1].trim() - if (cmd.isBlank()) { - showEntry(entryIndex, event) // L1: - } else if (LinksManager.isUpToDate(event)) { - if (cmd == "-") { - removeEntry(channel, entryIndex, event) // L1:- - } else { - when (cmd[0]) { - '|' -> changeTitle(cmd, entryIndex, event) // L1:|<title> - '=' -> changeUrl(channel, cmd, entryIndex, event) // L1:=<url> - '?' -> changeAuthor(channel, cmd, entryIndex, event) // L1:?<author> - else -> addComment(cmd, entryIndex, event) // L1:<comment> - } - } - } - } - } - - override fun matches(message: String): Boolean { - return message.matches("${Constants.LINK_CMD}\\d+:.*".toRegex()) - } - - private fun addComment(cmd: String, entryIndex: Int, event: GenericMessageEvent) { - val entry: EntryLink = entries.links[entryIndex] - val commentIndex = entry.addComment(cmd, event.user.nick) - val comment = entry.getComment(commentIndex) - event.sendMessage(EntriesUtils.printComment(entryIndex, commentIndex, comment)) - entries.save() - } - - private fun changeTitle(cmd: String, entryIndex: Int, event: GenericMessageEvent) { - if (cmd.length > 1) { - val entry: EntryLink = entries.links[entryIndex] - entry.title = cmd.substring(1).trim() - LinksManager.pinboard.updatePin(event.bot().serverHostname, entry.link, entry) - event.sendMessage(EntriesUtils.printLink(entryIndex, entry)) - entries.save() - } - } - - private fun changeUrl(channel: String, cmd: String, entryIndex: Int, event: GenericMessageEvent) { - val entry: EntryLink = entries.links[entryIndex] - if (entry.login == event.user.login || event.isChannelOp(channel)) { - val link = cmd.substring(1) - if (link.matches(LinksManager.LINK_MATCH)) { - val oldLink = entry.link - entry.link = link - LinksManager.pinboard.updatePin(event.bot().serverHostname, oldLink, entry) - event.sendMessage(EntriesUtils.printLink(entryIndex, entry)) - entries.save() - } - } - } - - private fun changeAuthor(channel: String, cmd: String, index: Int, event: GenericMessageEvent) { - if (event.isChannelOp(channel)) { - if (cmd.length > 1) { - val entry: EntryLink = entries.links[index] - entry.nick = cmd.substring(1) - LinksManager.pinboard.updatePin(event.bot().serverHostname, entry.link, entry) - event.sendMessage(EntriesUtils.printLink(index, entry)) - entries.save() - } - } else { - event.sendMessage("Please ask a channel op to change the author of this link for you.") - } - } - - private fun removeEntry(channel: String, index: Int, event: GenericMessageEvent) { - val entry: EntryLink = entries.links[index] - if (entry.login == event.user.login || event.isChannelOp(channel)) { - LinksManager.pinboard.deletePin(entry) - LinksManager.socialManager.removeEntry(index) - entries.links.removeAt(index) - event.sendMessage("Entry ${index.toLinkLabel()} removed.") - entries.save() - } else { - event.sendMessage("Please ask a channel op to remove this entry for you.") - } - } - - private fun showEntry(index: Int, event: GenericMessageEvent) { - val entry: EntryLink = entries.links[index] - event.sendMessage(EntriesUtils.printLink(index, entry)) - if (entry.tags.isNotEmpty()) { - event.sendMessage(EntriesUtils.printTags(index, entry)) - } - if (entry.comments.isNotEmpty()) { - val comments = entry.comments - for (i in comments.indices) { - event.sendMessage(EntriesUtils.printComment(index, i, comments[i])) - } - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/links/Tags.kt b/bin/main/net/thauvin/erik/mobibot/commands/links/Tags.kt deleted file mode 100644 index 1662857..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/links/Tags.kt +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Tags.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands.links - -import net.thauvin.erik.mobibot.Constants -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.isChannelOp -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.commands.AbstractCommand -import net.thauvin.erik.mobibot.entries.EntriesUtils -import net.thauvin.erik.mobibot.entries.EntryLink -import org.pircbotx.hooks.types.GenericMessageEvent - -class Tags : AbstractCommand() { - override val name = COMMAND - override val help = listOf( - "To categorize or tag a URL, use its label and a ${Constants.TAG_CMD}:", - helpFormat("${Constants.LINK_CMD}1${Constants.TAG_CMD}:<+tag|-tag> [...]") - ) - override val isOpOnly = false - override val isPublic = true - override val isVisible = true - - companion object { - const val COMMAND = "tags" - } - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - val cmds = args.substring(1).split("${Constants.TAG_CMD}:", limit = 2) - val index = cmds[0].toInt() - 1 - - if (index < LinksManager.entries.links.size && LinksManager.isUpToDate(event)) { - val cmd = cmds[1].trim() - val entry: EntryLink = LinksManager.entries.links[index] - if (cmd.isNotEmpty()) { - if (entry.login == event.user.login || event.isChannelOp(channel)) { - entry.setTags(cmd) - LinksManager.pinboard.updatePin(event.bot().serverHostname, entry.link, entry) - event.sendMessage(EntriesUtils.printTags(index, entry)) - LinksManager.entries.save() - } else { - event.sendMessage("Please ask a channel op to change the tags for you.") - } - } else { - if (entry.tags.isNotEmpty()) { - event.sendMessage(EntriesUtils.printTags(index, entry)) - } else { - event.sendMessage("The entry has no tags. Why don't add some?") - } - } - } - } - - override fun matches(message: String): Boolean { - return message.matches("^${Constants.LINK_CMD}\\d+${Constants.TAG_CMD}:.*".toRegex()) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/links/View.kt b/bin/main/net/thauvin/erik/mobibot/commands/links/View.kt deleted file mode 100644 index 825e374..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/links/View.kt +++ /dev/null @@ -1,120 +0,0 @@ -/* - * View.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands.links - -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpCmdSyntax -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.lastOrEmpty -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.commands.AbstractCommand -import net.thauvin.erik.mobibot.commands.links.LinksManager.Companion.entries -import net.thauvin.erik.mobibot.entries.EntriesUtils -import net.thauvin.erik.mobibot.entries.EntryLink -import org.pircbotx.hooks.events.PrivateMessageEvent -import org.pircbotx.hooks.types.GenericMessageEvent - -class View : AbstractCommand() { - override val name = VIEW_CMD - override val help = listOf( - "To list or search the current URL posts:", - helpFormat("%c $name [<start>] [<query>]") - ) - override val isOpOnly = false - override val isPublic = true - override val isVisible = true - - companion object { - const val MAX_ENTRIES = 6 - const val VIEW_CMD = "view" - } - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - if (entries.links.isNotEmpty()) { - val p = parseArgs(args) - showPosts(p.first, p.second, event) - } else { - event.sendMessage("There is currently nothing to view. Why don't you post something?") - } - } - - internal fun parseArgs(args: String): Pair<Int, String> { - var query = args.lowercase().trim() - var start = 0 - if (query.isEmpty() && entries.links.size > MAX_ENTRIES) { - start = entries.links.size - MAX_ENTRIES - } - if (query.matches("^\\d+(| .*)".toRegex())) { // view [<start>] [<query>] - val split = query.split(" ", limit = 2) - try { - start = split[0].toInt() - 1 - query = split.lastOrEmpty().trim() - if (start > entries.links.size) { - start = 0 - } - } catch (ignore: NumberFormatException) { - // Do nothing - } - } - return Pair(start, query) - } - - private fun showPosts(start: Int, query: String, event: GenericMessageEvent) { - var index = start - var entry: EntryLink - var sent = 0 - while (index < entries.links.size && sent < MAX_ENTRIES) { - entry = entries.links[index] - if (query.isNotBlank()) { - if (entry.matches(query)) { - event.sendMessage(EntriesUtils.printLink(index, entry, true)) - sent++ - } - } else { - event.sendMessage(EntriesUtils.printLink(index, entry, true)) - sent++ - } - index++ - if (sent == MAX_ENTRIES && index < entries.links.size) { - event.sendMessage("To view more, try: ") - event.sendMessage( - helpFormat( - helpCmdSyntax("%c $name ${index + 1} $query", event.bot().nick, event is PrivateMessageEvent) - ) - ) - } - } - if (sent == 0) { - event.sendMessage("No matches. Please try again.") - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt b/bin/main/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt deleted file mode 100644 index cfd2c27..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * NickComparator.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands.seen - -import java.io.Serializable - -class NickComparator : Comparator<String>, Serializable { - override fun compare(a: String, b: String): Int { - return a.lowercase().compareTo(b.lowercase()) - } - - companion object { - @Suppress("ConstPropertyName") - private const val serialVersionUID = 1L - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/seen/Seen.kt b/bin/main/net/thauvin/erik/mobibot/commands/seen/Seen.kt deleted file mode 100644 index c9ee0f3..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/seen/Seen.kt +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Seen.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands.seen - -import com.google.common.collect.ImmutableSortedSet -import net.thauvin.erik.mobibot.Utils -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.isChannelOp -import net.thauvin.erik.mobibot.Utils.loadSerialData -import net.thauvin.erik.mobibot.Utils.saveSerialData -import net.thauvin.erik.mobibot.Utils.sendList -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.commands.AbstractCommand -import net.thauvin.erik.mobibot.commands.Info.Companion.toUptime -import org.pircbotx.User -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.util.* - - -class Seen(private val serialObject: String) : AbstractCommand() { - private val logger: Logger = LoggerFactory.getLogger(Seen::class.java) - private val allKeyword = "all" - val seenNicks = TreeMap<String, SeenNick>(NickComparator()) - - override val name = "seen" - override val help = listOf("To view when a nickname was last seen:", helpFormat("%c $name <nick>")) - private val helpOp = help.plus( - arrayOf("To view all ${"seen".bold()} nicks:", helpFormat("%c $name $allKeyword")) - ) - override val isOpOnly = false - override val isPublic = true - override val isVisible = true - - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - if (isEnabled()) { - if (args.isNotBlank() && !args.contains(' ')) { - val ch = event.bot().userChannelDao.getChannel(channel) - if (args == allKeyword && ch.isOp(event.user) && seenNicks.isNotEmpty()) { - event.sendMessage("The ${"seen".bold()} nicks are:") - event.sendList(seenNicks.keys.toList(), 7, separator = ", ", isIndent = true) - return - } - ch.users.forEach { - if (args.equals(it.nick, true)) { - event.sendMessage("${it.nick} is on ${channel}.") - return - } - } - if (seenNicks.containsKey(args)) { - val seenNick = seenNicks.getValue(args) - val lastSeen = System.currentTimeMillis() - seenNick.lastSeen - event.sendMessage("${seenNick.nick} was last seen on $channel ${lastSeen.toUptime()} ago.") - return - } - event.sendMessage("I haven't seen $args on $channel lately.") - } else { - helpResponse(channel, args, event) - } - } - } - - fun add(nick: String) { - if (isEnabled()) { - seenNicks[nick] = SeenNick(nick, System.currentTimeMillis()) - save() - } - } - - fun add(users: ImmutableSortedSet<User>) { - if (isEnabled()) { - users.forEach { - seenNicks[it.nick] = SeenNick(it.nick, System.currentTimeMillis()) - } - save() - } - } - - fun clear() { - seenNicks.clear() - } - - fun count(): Int = seenNicks.size - - override fun helpResponse(channel: String, topic: String, event: GenericMessageEvent): Boolean { - return if (event.isChannelOp(channel)) { - for (h in helpOp) { - event.sendMessage(Utils.helpCmdSyntax(h, event.bot().nick, true)) - } - true - } else { - super.helpResponse(channel, topic, event) - } - } - - fun load() { - if (isEnabled()) { - @Suppress("UNCHECKED_CAST") - seenNicks.putAll( - loadSerialData( - serialObject, - TreeMap<String, SeenNick>(), - logger, - "seen nicknames" - ) as TreeMap<String, SeenNick> - ) - } - } - - fun save() { - saveSerialData(serialObject, seenNicks, logger, "seen nicknames") - } - - init { - load() - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt b/bin/main/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt deleted file mode 100644 index 7924977..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SeenNick.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands.seen - -import java.io.Serializable - -data class SeenNick(val nick: String, val lastSeen: Long) : Serializable { - companion object { - @Suppress("ConstPropertyName") - private const val serialVersionUID = 1L - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/tell/Tell.kt b/bin/main/net/thauvin/erik/mobibot/commands/tell/Tell.kt deleted file mode 100644 index 061ca6a..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/tell/Tell.kt +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Tell.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.commands.tell - -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpCmdSyntax -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.isChannelOp -import net.thauvin.erik.mobibot.Utils.plural -import net.thauvin.erik.mobibot.Utils.reverseColor -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.Utils.toIntOrDefault -import net.thauvin.erik.mobibot.Utils.toUtcDateTime -import net.thauvin.erik.mobibot.commands.AbstractCommand -import net.thauvin.erik.mobibot.commands.links.View -import org.pircbotx.PircBotX -import org.pircbotx.hooks.events.MessageEvent -import org.pircbotx.hooks.types.GenericMessageEvent -import org.pircbotx.hooks.types.GenericUserEvent - -/** - * The `Tell` command. - */ -class Tell(private val serialObject: String) : AbstractCommand() { - // Messages queue - private val messages: MutableList<TellMessage> = mutableListOf() - - // Maximum number of days to keep messages - private var maxDays = 7 - - // Message maximum queue size - private var maxSize = 50 - - /** - * The tell command. - */ - override val name = "tell" - - override val help = listOf( - "To send a message to someone when they join the channel:", - helpFormat("%c $name <nick> <message>"), - "To view queued and sent messages:", - helpFormat("%c $name ${View.VIEW_CMD}"), - "Messages are kept for ${maxDays.bold()}" + " day".plural(maxDays.toLong()) + '.' - ) - override val isOpOnly: Boolean = false - override val isPublic: Boolean = isEnabled() - override val isVisible: Boolean = isEnabled() - - /** - * Cleans the messages queue. - */ - private fun clean(): Boolean { - return TellManager.clean(messages, maxDays.toLong()) - } - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - if (isEnabled()) { - when { - args.isBlank() -> { - helpResponse(channel, args, event) - } - - args.startsWith(View.VIEW_CMD) -> { - if (event.isChannelOp(channel) && "${View.VIEW_CMD} $TELL_ALL_KEYWORD" == args) { - viewAll(event) - } else { - viewMessages(event) - } - } - - args.startsWith("$TELL_DEL_KEYWORD ") -> { - deleteMessage(channel, args, event) - } - - else -> { - newMessage(channel, args, event) - } - } - if (clean()) { - save() - } - } - } - - // Delete message. - private fun deleteMessage(channel: String, args: String, event: GenericMessageEvent) { - val split = args.split(" ") - if (split.size == 2) { - val id = split[1] - if (TELL_ALL_KEYWORD.equals(id, ignoreCase = true)) { - if (messages.removeIf { it.sender.equals(event.user.nick, true) && it.isReceived }) { - save() - event.sendMessage("Delivered messages have been deleted.") - } else { - event.sendMessage("No delivered messages were found.") - } - } else { - if (messages.removeIf { - it.id == id && - (it.sender.equals(event.user.nick, true) || event.isChannelOp(channel)) - }) { - save() - event.sendMessage("The message was deleted from the queue.") - } else { - event.sendMessage("The specified message [ID $id] could not be found.") - } - } - } else { - helpResponse(channel, args, event) - } - } - - override fun isEnabled(): Boolean { - return maxSize > 0 && maxDays > 0 - } - - override fun setProperty(key: String, value: String) { - super.setProperty(key, value) - if (MAX_DAYS_PROP == key) { - maxDays = value.toIntOrDefault(maxDays) - } else if (MAX_SIZE_PROP == key) { - maxSize = value.toIntOrDefault(maxSize) - } - } - - // New message. - private fun newMessage(channel: String, args: String, event: GenericMessageEvent) { - val split = args.split(" ".toRegex(), 2) - if (split.size == 2 && split[1].isNotBlank() && split[1].contains(" ")) { - if (messages.size < maxSize) { - val message = TellMessage(event.user.nick, split[0], split[1].trim()) - messages.add(message) - save() - event.sendMessage("Message [ID ${message.id}] was queued for ${message.recipient.bold()}") - } else { - event.sendMessage("Sorry, the messages queue is currently full.") - } - } else { - helpResponse(channel, args, event) - } - } - - /** - * Saves the messages queue. - */ - private fun save() { - TellManager.save(serialObject, messages) - } - - /** - * Checks and sends messages. - */ - fun send(event: GenericUserEvent) { - val nickname = event.user.nick - if (isEnabled() && nickname != event.getBot<PircBotX>().nick) { - messages.filter { it.isMatch(nickname) }.forEach { message -> - if (message.recipient.equals(nickname, ignoreCase = true) && !message.isReceived) { - if (message.sender == nickname) { - if (event !is MessageEvent) { - event.user.send().message( - "${"You".bold()} wanted me to remind you: ${message.message.reverseColor()}" - ) - message.isReceived = true - message.isNotified = true - save() - } - } else { - event.user.send().message( - "${message.sender} wanted me to tell you: ${message.message.reverseColor()}" - ) - message.isReceived = true - save() - } - } else if (message.sender.equals(nickname, ignoreCase = true) && message.isReceived - && !message.isNotified - ) { - event.user.send().message( - "Your message ${"[ID ${message.id}]".reverseColor()} was sent to " - + "${message.recipient.bold()} on ${message.receptionDate}" - ) - message.isNotified = true - save() - } - } - } - } - - /** - * Returns the messages queue size. - * - * @return The size. - */ - fun size(): Int = messages.size - - // View all messages. - private fun viewAll(event: GenericMessageEvent) { - if (messages.isNotEmpty()) { - for (message in messages) { - event.sendMessage( - "${message.sender.bold()}$ARROW${message.recipient.bold()} [ID: ${message.id}, " + - (if (message.isReceived) "DELIVERED]" else "QUEUED]") - ) - } - } else { - event.sendMessage("There are no messages in the queue.") - } - } - - // View messages. - private fun viewMessages(event: GenericMessageEvent) { - var hasMessage = false - for (message in messages.filter { it.isMatch(event.user.nick) }) { - if (!hasMessage) { - hasMessage = true - event.sendMessage("Here are your messages: ") - } - if (message.isReceived) { - event.sendMessage( - message.sender.bold() + ARROW + message.recipient.bold() + - " [${message.receptionDate.toUtcDateTime()}, ID: ${message.id.bold()}, DELIVERED]" - ) - } else { - event.sendMessage( - message.sender.bold() + ARROW + message.recipient.bold() + - " [${message.queued.toUtcDateTime()}, ID: ${message.id.bold()}, QUEUED]" - ) - } - event.sendMessage(helpFormat(message.message)) - } - if (!hasMessage) { - event.sendMessage("You have no messages in the queue.") - } else { - event.sendMessage("To delete one or all delivered messages:") - event.sendMessage( - helpFormat( - helpCmdSyntax("%c $name $TELL_DEL_KEYWORD <id|$TELL_ALL_KEYWORD>", event.bot().nick, true) - ) - ) - event.sendMessage(help.last()) - } - } - - companion object { - /** - * Max days property. - */ - const val MAX_DAYS_PROP = "tell-max-days" - - /** - * Max size property. - */ - const val MAX_SIZE_PROP = "tell-max-size" - - // Arrow - private const val ARROW = " --> " - - // All keyword - private const val TELL_ALL_KEYWORD = "all" - - //T he delete command. - private const val TELL_DEL_KEYWORD = "del" - } - - /** - * Creates a new instance. - */ - init { - initProperties(MAX_DAYS_PROP, MAX_SIZE_PROP) - - // Load the message queue - messages.addAll(TellManager.load(serialObject)) - if (clean()) { - save() - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/tell/TellManager.kt b/bin/main/net/thauvin/erik/mobibot/commands/tell/TellManager.kt deleted file mode 100644 index b65a4da..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/tell/TellManager.kt +++ /dev/null @@ -1,74 +0,0 @@ -/* - * TellManager.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.commands.tell - -import net.thauvin.erik.mobibot.Utils.loadSerialData -import net.thauvin.erik.mobibot.Utils.saveSerialData -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.time.Clock -import java.time.LocalDateTime - -/** - * The Tell Messages Manager. - */ -object TellManager { - private val logger: Logger = LoggerFactory.getLogger(TellManager::class.java) - - /** - * Cleans the messages queue. - */ - @JvmStatic - fun clean(tellMessages: MutableList<TellMessage>, tellMaxDays: Long): Boolean { - if (logger.isDebugEnabled) logger.debug("Cleaning the messages.") - val today = LocalDateTime.now(Clock.systemUTC()) - return tellMessages.removeIf { o: TellMessage -> o.queued.plusDays(tellMaxDays).isBefore(today) } - } - - /** - * Loads the messages. - */ - @JvmStatic - fun load(file: String): List<TellMessage> { - @Suppress("UNCHECKED_CAST") - return loadSerialData(file, emptyList<TellMessage>(), logger, "message queue") as List<TellMessage> - } - - /** - * Saves the messages. - */ - @JvmStatic - fun save(file: String, messages: List<TellMessage?>?) { - if (messages != null) { - saveSerialData(file, messages, logger, "messages") - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt b/bin/main/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt deleted file mode 100644 index d17fbb5..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt +++ /dev/null @@ -1,104 +0,0 @@ -/* - * TellMessage.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.commands.tell - -import java.io.Serializable -import java.time.Clock -import java.time.LocalDateTime -import java.time.format.DateTimeFormatter - -/** - * Tell Message. - */ -class TellMessage( - /** - * Returns the message's sender. - */ - val sender: String, - - /** - * Returns the message's recipient. - */ - val recipient: String, - - /** - * Returns the message text. - */ - val message: String -) : Serializable { - /** - * Returns the queued date/time. - */ - var queued: LocalDateTime = LocalDateTime.now(Clock.systemUTC()) - - /** - * Returns the message id. - */ - var id: String = queued.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) - - /** - * Returns `true` if a notification was sent. - */ - var isNotified = false - - /** - * Returns `true` if the message was received. - */ - var isReceived = false - set(value) { - if (value) { - receptionDate = LocalDateTime.now(Clock.systemUTC()) - } - field = value - } - - /** - * Returns the message creating date. - */ - var receptionDate: LocalDateTime = LocalDateTime.MIN - - /** - * Matches the message sender or recipient. - */ - fun isMatch(nick: String?): Boolean { - return sender.equals(nick, ignoreCase = true) || recipient.equals(nick, ignoreCase = true) - } - - override fun toString(): String { - return ("TellMessage{id='$id', isNotified=$isNotified, isReceived=$isReceived, message='$message', " + - "queued=$queued, received=$receptionDate, recipient='$recipient', sender='$sender'}") - } - - companion object { - @Suppress("ConstPropertyName") - private const val serialVersionUID = 2L - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/entries/Entries.kt b/bin/main/net/thauvin/erik/mobibot/entries/Entries.kt deleted file mode 100644 index e8676ec..0000000 --- a/bin/main/net/thauvin/erik/mobibot/entries/Entries.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Entries.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.entries - -import net.thauvin.erik.mobibot.Utils.today - -class Entries( - var channel: String = "", - var ircServer: String = "", - var logsDir: String = "", - var backlogs: String = "" -) { - val links = mutableListOf<EntryLink>() - - var lastPubDate = today() - - fun load() { - lastPubDate = FeedsManager.loadFeed(this) - } - - fun save() { - lastPubDate = today() - FeedsManager.saveFeed(this) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/entries/EntriesUtils.kt b/bin/main/net/thauvin/erik/mobibot/entries/EntriesUtils.kt deleted file mode 100644 index 9c09626..0000000 --- a/bin/main/net/thauvin/erik/mobibot/entries/EntriesUtils.kt +++ /dev/null @@ -1,83 +0,0 @@ -/* - * EntriesUtils.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.entries - -import net.thauvin.erik.mobibot.Constants -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.Utils.green - -/** - * Entries utilities. - */ -object EntriesUtils { - /** - * Prints an entry's comment for display on the channel. - */ - @JvmStatic - fun printComment(entryIndex: Int, commentIndex: Int, comment: EntryComment): String = - ("${entryIndex.toLinkLabel()}.${commentIndex + 1}: [${comment.nick}] ${comment.comment}") - - /** - * Prints an entry's link for display on the channel. - */ - @JvmStatic - @JvmOverloads - fun printLink(entryIndex: Int, entry: EntryLink, isView: Boolean = false): String { - val buff = StringBuilder().append(entryIndex.toLinkLabel()).append(": ") - .append('[').append(entry.nick).append(']') - if (isView && entry.comments.isNotEmpty()) { - buff.append("[+").append(entry.comments.size).append(']') - } - buff.append(' ') - with(entry) { - if (Constants.NO_TITLE == title) { - buff.append(title) - } else { - buff.append(title.bold()) - } - buff.append(" ( ").append(link.green()).append(" )") - } - return buff.toString() - } - - /** - * Prints an entry's tags/categories for display on the channel. e.g. L1T: tag1, tag2 - */ - @JvmStatic - fun printTags(entryIndex: Int, entry: EntryLink): String = - entryIndex.toLinkLabel() + "${Constants.TAG_CMD}: " + entry.formatTags(", ") - - /** - * Builds link label based on its index. e.g: L1 - */ - @JvmStatic - fun Int.toLinkLabel(): String = Constants.LINK_CMD + (this + 1) -} diff --git a/bin/main/net/thauvin/erik/mobibot/entries/EntryComment.kt b/bin/main/net/thauvin/erik/mobibot/entries/EntryComment.kt deleted file mode 100644 index e18d692..0000000 --- a/bin/main/net/thauvin/erik/mobibot/entries/EntryComment.kt +++ /dev/null @@ -1,52 +0,0 @@ -/* - * EntryComment.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.entries - -import java.io.Serializable -import java.time.LocalDateTime - -/** - * Entry comments data class. - */ -data class EntryComment(var comment: String, var nick: String) : Serializable { - /** - * Creation date. - */ - val date: LocalDateTime = LocalDateTime.now() - - override fun toString(): String = "EntryComment{comment='$comment', date=$date, nick='$nick'}" - - companion object { - // Serial version UID - @Suppress("ConstPropertyName") - private const val serialVersionUID: Long = 1L - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/entries/EntryLink.kt b/bin/main/net/thauvin/erik/mobibot/entries/EntryLink.kt deleted file mode 100644 index 4a69446..0000000 --- a/bin/main/net/thauvin/erik/mobibot/entries/EntryLink.kt +++ /dev/null @@ -1,213 +0,0 @@ -/* - * EntryLink.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.entries - -import com.rometools.rome.feed.synd.SyndCategory -import com.rometools.rome.feed.synd.SyndCategoryImpl -import net.thauvin.erik.mobibot.commands.links.LinksManager -import java.io.Serializable -import java.util.* - -/** - * The class used to store link entries. - */ -class EntryLink( - // Link's comments - val comments: MutableList<EntryComment> = mutableListOf(), - - // Tags/categories - val tags: MutableList<SyndCategory> = mutableListOf(), - - // Channel - var channel: String, - - // Creation date - var date: Date = Calendar.getInstance().time, - - // Link's URL - var link: String, - - // Author's login - var login: String = "", - - // Author's nickname - var nick: String, - - // Link's title - var title: String -) : Serializable { - /** - * Creates a new entry. - */ - constructor( - link: String, - title: String, - nick: String, - login: String, - channel: String, - tags: List<String?> - ) : this(link = link, title = title, nick = nick, login = login, channel = channel) { - setTags(tags) - } - - /** - * Creates a new entry. - */ - constructor( - link: String, - title: String, - nick: String, - channel: String, - date: Date, - tags: List<SyndCategory> - ) : this(link = link, title = title, nick = nick, channel = channel, date = Date(date.time)) { - this.tags.addAll(tags) - } - - /** - * Adds a new comment - */ - fun addComment(comment: EntryComment): Int { - comments.add(comment) - return comments.lastIndex - } - - /** - * Adds a new comment. - */ - fun addComment(comment: String, nick: String): Int { - return addComment(EntryComment(comment, nick)) - } - - /** - * Deletes a specific comment. - */ - fun deleteComment(index: Int): Boolean { - if (index < comments.size) { - comments.removeAt(index) - return true - } - return false - } - - /** - * Deletes a comment. - */ - fun deleteComment(entryComment: EntryComment): Boolean { - return comments.remove(entryComment) - } - - /** - * Formats the tags. - */ - fun formatTags(sep: String, prefix: String = ""): String { - return tags.joinToString(separator = sep, prefix = prefix) { it.name } - } - - /** - * Returns a comment. - */ - fun getComment(index: Int): EntryComment = comments[index] - - /** - * Returns true if a string is contained in the link, title, or nick. - */ - fun matches(match: String?): Boolean { - return if (match.isNullOrEmpty()) { - false - } else { - link.contains(match, true) || title.contains(match, true) || nick.contains(match, true) - } - } - - /** - * Sets a comment. - */ - fun setComment(index: Int, comment: String?, nick: String?) { - if (index < comments.size && !comment.isNullOrBlank() && !nick.isNullOrBlank()) { - comments[index] = EntryComment(comment, nick) - } - } - - /** - * Sets the tags. - */ - fun setTags(tags: String) { - setTags(tags.split(LinksManager.TAG_MATCH)) - } - - /** - * Sets the tags. - */ - private fun setTags(tags: List<String?>) { - if (tags.isNotEmpty()) { - var category: SyndCategoryImpl - for (tag in tags) { - if (!tag.isNullOrBlank()) { - val t = tag.lowercase() - val mod = t[0] - if (mod == '-') { - // Don't remove the channel tag - if (channel.substring(1) != t.substring(1)) { - category = SyndCategoryImpl() - category.name = t.substring(1) - this.tags.remove(category) - } - } else { - category = SyndCategoryImpl() - if (mod == '+') { - category.name = t.substring(1) - } else { - category.name = t - } - if (!this.tags.contains(category)) { - this.tags.add(category) - } - } - } - } - } - } - - /** - * Returns a string representation of the object. - */ - override fun toString(): String { - return ("EntryLink{channel='$channel', comments=$comments, date=$date, link='$link', login='$login'," + - "nick='$nick', tags=$tags, title='$title'}") - } - - companion object { - // Serial version UID - @Suppress("ConstPropertyName") - private const val serialVersionUID: Long = 1L - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/entries/FeedsManager.kt b/bin/main/net/thauvin/erik/mobibot/entries/FeedsManager.kt deleted file mode 100644 index f786cb2..0000000 --- a/bin/main/net/thauvin/erik/mobibot/entries/FeedsManager.kt +++ /dev/null @@ -1,187 +0,0 @@ -/* - * FeedsManager.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.entries - -import com.rometools.rome.feed.synd.* -import com.rometools.rome.io.FeedException -import com.rometools.rome.io.SyndFeedInput -import com.rometools.rome.io.SyndFeedOutput -import net.thauvin.erik.mobibot.Utils.toIsoLocalDate -import net.thauvin.erik.mobibot.Utils.today -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.io.IOException -import java.io.InputStreamReader -import java.io.OutputStreamWriter -import java.nio.charset.StandardCharsets -import java.nio.file.Files -import java.nio.file.Paths -import java.util.* -import kotlin.io.path.exists - -/** - * Manages the RSS feeds. - */ -class FeedsManager private constructor() { - companion object { - private val logger: Logger = LoggerFactory.getLogger(FeedsManager::class.java) - - // The file containing the current entries. - private const val CURRENT_XML = "current.xml" - - // The .xml extension. - private const val DOT_XML = ".xml" - - /** - * Loads the current feed. - */ - @JvmStatic - @Throws(IOException::class, FeedException::class) - fun loadFeed(entries: Entries, currentFile: String = CURRENT_XML): String { - entries.links.clear() - val xml = Paths.get("${entries.logsDir}${currentFile}") - var pubDate = today() - if (xml.exists()) { - val input = SyndFeedInput() - InputStreamReader( - Files.newInputStream(xml), StandardCharsets.UTF_8 - ).use { reader -> - val feed = input.build(reader) - pubDate = feed.publishedDate.toIsoLocalDate() - val items = feed.entries - var entry: EntryLink - for (i in items.indices.reversed()) { - with(items[i]) { - entry = EntryLink( - link, - title, - author.substring(author.lastIndexOf('(') + 1, author.length - 1), - entries.channel, - publishedDate, - categories - ) - var split: List<String> - for (comment in description.value.split("<br/>")) { - split = comment.split(": ".toRegex(), 2) - if (split.size == 2) { - entry.addComment(comment = split[1].trim(), nick = split[0].trim()) - } - } - } - entries.links.add(entry) - } - } - } else { - // Create an empty feed. - saveFeed(entries) - } - return pubDate - } - - /** - * Saves the feeds. - */ - @JvmStatic - fun saveFeed(entries: Entries, currentFile: String = CURRENT_XML) { - if (logger.isDebugEnabled) logger.debug("Saving the feeds...") - if (entries.logsDir.isNotBlank()) { - try { - val output = SyndFeedOutput() - val rss: SyndFeed = SyndFeedImpl() - val items: MutableList<SyndEntry> = mutableListOf() - var item: SyndEntry - OutputStreamWriter( - Files.newOutputStream(Paths.get("${entries.logsDir}${currentFile}")), StandardCharsets.UTF_8 - ).use { fw -> - with(rss) { - feedType = "rss_2.0" - title = "${entries.channel} IRC Links" - description = "Links from ${entries.ircServer} on ${entries.channel}" - if (entries.backlogs.isNotBlank()) link = entries.backlogs - publishedDate = Calendar.getInstance().time - language = "en" - } - val buff: StringBuilder = StringBuilder() - for (i in entries.links.indices.reversed()) { - with(entries.links[i]) { - buff.setLength(0) - buff.append("Posted by <b>") - .append(nick) - .append("</b> on <a href=\"irc://") - .append(entries.ircServer).append('/') - .append(channel) - .append("\"><b>") - .append(channel) - .append("</b></a>") - if (comments.isNotEmpty()) { - buff.append(" <br/><br/>") - for (j in comments.indices) { - if (j > 0) { - buff.append(" <br/>") - } - buff.append(comments[j].nick).append(": ").append(comments[j].comment) - } - } - item = SyndEntryImpl() - item.link = link - item.description = SyndContentImpl().apply { value = buff.toString() } - item.title = title - item.publishedDate = date - item.author = "${channel.removePrefix("#")}@${entries.ircServer} ($nick)" - item.categories = tags - items.add(item) - } - } - rss.entries = items - if (logger.isDebugEnabled) logger.debug("Writing the entries feed.") - output.output(rss, fw) - } - OutputStreamWriter( - Files.newOutputStream( - Paths.get( - entries.logsDir + today() + DOT_XML - ) - ), StandardCharsets.UTF_8 - ).use { fw -> output.output(rss, fw) } - } catch (e: FeedException) { - if (logger.isWarnEnabled) logger.warn("Unable to generate the entries feed.", e) - } catch (e: IOException) { - if (logger.isWarnEnabled) - logger.warn("An IO error occurred while generating the entries feed.", e) - } - } else { - if (logger.isWarnEnabled) { - logger.warn("Unable to generate the entries feed. A required property is missing.") - } - } - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/AbstractModule.kt b/bin/main/net/thauvin/erik/mobibot/modules/AbstractModule.kt deleted file mode 100644 index 8c8e736..0000000 --- a/bin/main/net/thauvin/erik/mobibot/modules/AbstractModule.kt +++ /dev/null @@ -1,131 +0,0 @@ -/* - * AbstractModule.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpCmdSyntax -import net.thauvin.erik.mobibot.Utils.sendMessage -import org.pircbotx.hooks.events.PrivateMessageEvent -import org.pircbotx.hooks.types.GenericMessageEvent - -/** - * The `Module` abstract class. - */ -abstract class AbstractModule { - /** - * The module name. - */ - abstract val name: String - - /** - * The module's commands, if any. - */ - @JvmField - val commands: MutableList<String> = mutableListOf() - - @JvmField - val help: MutableList<String> = mutableListOf() - val properties: MutableMap<String, String> = mutableMapOf() - - /** - * Responds to a command. - */ - abstract fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) - - /** - * Returns the module's property keys. - */ - val propertyKeys: Set<String> - get() = properties.keys - - /** - * Returns `true` if the module has properties. - */ - fun hasProperties(): Boolean { - return properties.isNotEmpty() - } - - /** - * Responds with the module's help. - */ - open fun helpResponse(event: GenericMessageEvent): Boolean { - for (h in help) { - event.sendMessage(helpCmdSyntax(h, event.bot().nick, isPrivateMsgEnabled && event is PrivateMessageEvent)) - } - return true - } - - /** - * Initializes the properties. - */ - fun initProperties(vararg keys: String) { - for (key in keys) { - properties[key] = "" - } - } - - /** - * Returns `true` if the module is enabled. - */ - val isEnabled: Boolean - get() = if (hasProperties()) { - isValidProperties - } else { - true - } - - /** - * Returns `true` if the module responds to private messages. - */ - open val isPrivateMsgEnabled: Boolean = false - - /** - * Ensures that all properties have values. - */ - open val isValidProperties: Boolean - get() { - for (s in properties.keys) { - if (properties[s].isNullOrBlank()) { - return false - } - } - return true - } - - /** - * Sets a property key and value. - */ - fun setProperty(key: String, value: String) { - if (key.isNotBlank()) { - properties[key] = value - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/Calc.kt b/bin/main/net/thauvin/erik/mobibot/modules/Calc.kt deleted file mode 100644 index b7aae28..0000000 --- a/bin/main/net/thauvin/erik/mobibot/modules/Calc.kt +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Calc.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import net.objecthunter.exp4j.ExpressionBuilder -import net.objecthunter.exp4j.tokenizer.UnknownFunctionOrVariableException -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.Utils.helpFormat -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.text.DecimalFormat - -/** - * The Calc module. - */ -class Calc : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(Calc::class.java) - - override val name = "Calc" - - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - if (args.isNotBlank()) { - try { - event.respond(calculate(args)) - } catch (e: IllegalArgumentException) { - if (logger.isWarnEnabled) logger.warn("Failed to calculate: $args", e) - event.respond("No idea. This is the kind of math I don't get.") - } catch (e: UnknownFunctionOrVariableException) { - if (logger.isWarnEnabled) logger.warn("Unable to calculate: $args", e) - event.respond("No idea. I must've some form of Dyscalculia.") - } - } else { - helpResponse(event) - } - } - - companion object { - // Calc command - private const val CALC_CMD = "calc" - - /** - * Performs a calculation. e.g.: 1 + 1 * 2 - */ - @JvmStatic - @Throws(IllegalArgumentException::class) - fun calculate(query: String): String { - val decimalFormat = DecimalFormat("#.##") - val calc = ExpressionBuilder(query).build() - return query.replace(" ", "") + " = " + decimalFormat.format(calc.evaluate()).bold() - } - } - - init { - commands.add(CALC_CMD) - help.add("To solve a mathematical calculation:") - help.add(helpFormat("%c $CALC_CMD <calculation>")) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/ChatGpt.kt b/bin/main/net/thauvin/erik/mobibot/modules/ChatGpt.kt deleted file mode 100644 index bd92332..0000000 --- a/bin/main/net/thauvin/erik/mobibot/modules/ChatGpt.kt +++ /dev/null @@ -1,176 +0,0 @@ -/* - * ChatGpt.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.modules - -import net.thauvin.erik.mobibot.Constants -import net.thauvin.erik.mobibot.Utils -import net.thauvin.erik.mobibot.Utils.sendMessage -import org.apache.commons.text.WordUtils -import org.json.JSONException -import org.json.JSONObject -import org.json.JSONWriter -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.io.IOException -import java.net.URI -import java.net.http.HttpClient -import java.net.http.HttpRequest -import java.net.http.HttpResponse - -class ChatGpt : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(ChatGpt::class.java) - - override val name = CHATGPT_NAME - - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - if (args.isNotBlank()) { - try { - val answer = chat( - args.trim(), properties[API_KEY_PROP], - properties.getOrDefault(MAX_TOKENS_PROP, "1024").toInt() - ) - if (answer.isNotBlank()) { - event.sendMessage(WordUtils.wrap(answer, 400)) - } else { - event.respond("$name is stumped.") - } - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) - e.message?.let { - event.respond(it) - } - } catch (e: NumberFormatException) { - if (logger.isErrorEnabled) logger.error("Invalid $MAX_TOKENS_PROP property.", e) - event.respond("The $name module is misconfigured.") - } - } else { - helpResponse(event) - } - } - - companion object { - /** - * The service name. - */ - const val CHATGPT_NAME = "ChatGPT" - - /** - * The API Key property. - */ - const val API_KEY_PROP = "chatgpt-api-key" - - /** - * The max tokens property. - */ - const val MAX_TOKENS_PROP = "chatgpt-max-tokens" - - // ChatGPT API URL - private const val API_URL = "https://api.openai.com/v1/completions" - - // ChatGPT command - private const val CHATGPT_CMD = "chatgpt" - - - @JvmStatic - @Throws(ModuleException::class) - fun chat(query: String, apiKey: String?, maxTokens: Int): String { - if (!apiKey.isNullOrEmpty()) { - val prompt = JSONWriter.valueToString("Q:$query\nA:") - val request = HttpRequest.newBuilder() - .uri(URI.create(API_URL)) - .header("Content-Type", "application/json") - .header("Authorization", "Bearer $apiKey") - .header("User-Agent", Constants.USER_AGENT) - .POST( - HttpRequest.BodyPublishers.ofString( - """{ - "model": "text-davinci-003", - "prompt": $prompt, - "temperature": 0, - "max_tokens": $maxTokens, - "top_p": 1, - "frequency_penalty": 0, - "presence_penalty": 0 - }""".trimIndent() - ) - ) - .build() - try { - val response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString()) - if (response.statusCode() == 200) { - try { - val jsonResponse = JSONObject(response.body()) - val choices = jsonResponse.getJSONArray("choices") - return choices.getJSONObject(0).getString("text").trim() - } catch (e: JSONException) { - throw ModuleException( - "$CHATGPT_CMD($query): JSON", - "A JSON error has occurred while conversing with $CHATGPT_NAME.", - e - ) - } - } else { - if (response.statusCode() == 429) { - throw ModuleException( - "$CHATGPT_CMD($query): Rate limit reached", - "Rate limit reached. Please try again later." - ) - } else { - throw IOException("HTTP Status Code: " + response.statusCode()) - } - } - } catch (e: IOException) { - throw ModuleException( - "$CHATGPT_CMD($query): IO", - "An IO error has occurred while conversing with $CHATGPT_NAME.", - e - ) - } - } else { - throw ModuleException("$CHATGPT_CMD($query)", "No $CHATGPT_NAME API key specified.") - } - } - } - - init { - commands.add(CHATGPT_CMD) - with(help) { - add("To get answers from $name:") - add(Utils.helpFormat("%c $CHATGPT_CMD <query>")) - add("For example:") - add(Utils.helpFormat("%c $CHATGPT_CMD explain quantum computing in simple terms")) - add(Utils.helpFormat("%c $CHATGPT_CMD how do I make an HTTP request in Javascript?")) - } - initProperties(API_KEY_PROP, MAX_TOKENS_PROP) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/CryptoPrices.kt b/bin/main/net/thauvin/erik/mobibot/modules/CryptoPrices.kt deleted file mode 100644 index d14056e..0000000 --- a/bin/main/net/thauvin/erik/mobibot/modules/CryptoPrices.kt +++ /dev/null @@ -1,159 +0,0 @@ -/* - * CryptoPrices.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import net.thauvin.erik.crypto.CryptoException -import net.thauvin.erik.crypto.CryptoPrice -import net.thauvin.erik.crypto.CryptoPrice.Companion.spotPrice -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.sendList -import net.thauvin.erik.mobibot.Utils.sendMessage -import org.json.JSONObject -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.io.IOException - -/** - * The Cryptocurrency Prices module. - */ -class CryptoPrices : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(CryptoPrices::class.java) - - override val name = "CryptoPrices" - - /** - * Returns the cryptocurrency market price from - * [Coinbase](https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-prices#get-spot-price). - */ - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - if (CURRENCIES.isEmpty()) { - try { - loadCurrencies() - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) - } - } - - val debugMessage = "crypto($cmd $args)" - if (args == CODES_KEYWORD) { - event.sendMessage("The supported currencies are:") - event.sendList(ArrayList(CURRENCIES.keys), 10, isIndent = true) - } else if (args.matches("\\w+( [a-zA-Z]{3}+)?".toRegex())) { - try { - val price = currentPrice(args.split(' ')) - val amount = try { - price.toCurrency() - } catch (ignore: IllegalArgumentException) { - price.amount - } - event.respond("${price.base} current price is $amount [${CURRENCIES[price.currency]}]") - } catch (e: CryptoException) { - if (logger.isWarnEnabled) logger.warn("$debugMessage => ${e.statusCode}", e) - e.message?.let { - event.respond(it) - } - } catch (e: IOException) { - if (logger.isErrorEnabled) logger.error(debugMessage, e) - event.respond("An IO error has occurred while retrieving the cryptocurrency market price.") - } - } else { - helpResponse(event) - } - - } - - companion object { - // Crypto command - private const val CRYPTO_CMD = "crypto" - - // Fiat Currencies - private val CURRENCIES: MutableMap<String, String> = mutableMapOf() - - // Currency codes keyword - private const val CODES_KEYWORD = "codes" - - /** - * Get current market price. - */ - @JvmStatic - fun currentPrice(args: List<String>): CryptoPrice { - return if (args.size == 2) - spotPrice(args[0], args[1]) - else - spotPrice(args[0]) - } - - /** - * For testing purposes. - */ - fun getCurrencyName(code: String): String? { - return CURRENCIES[code] - } - - /** - * Loads the Fiat currencies.. - */ - @JvmStatic - @Throws(ModuleException::class) - fun loadCurrencies() { - try { - val json = JSONObject(CryptoPrice.apiCall(listOf("currencies"))) - val data = json.getJSONArray("data") - for (i in 0 until data.length()) { - val d = data.getJSONObject(i) - CURRENCIES[d.getString("id")] = d.getString("name") - } - } catch (e: CryptoException) { - throw ModuleException( - "loadCurrencies(): CE", - "An error has occurred while retrieving the currencies table.", - e - ) - } - } - } - - init { - commands.add(CRYPTO_CMD) - with(help) { - add("To retrieve a cryptocurrency's market price:") - add(helpFormat("%c $CRYPTO_CMD <symbol> [<currency>]")) - add("For example:") - add(helpFormat("%c $CRYPTO_CMD BTC")) - add(helpFormat("%c $CRYPTO_CMD ETH EUR")) - add(helpFormat("%c $CRYPTO_CMD ETH2 GPB")) - add("To list the supported currencies:") - add(helpFormat("%c $CRYPTO_CMD $CODES_KEYWORD")) - } - loadCurrencies() - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt b/bin/main/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt deleted file mode 100644 index da0efd8..0000000 --- a/bin/main/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt +++ /dev/null @@ -1,222 +0,0 @@ -/* - * CurrencyConverter.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpCmdSyntax -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.reader -import net.thauvin.erik.mobibot.Utils.sendList -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.msg.ErrorMessage -import net.thauvin.erik.mobibot.msg.Message -import net.thauvin.erik.mobibot.msg.PublicMessage -import org.json.JSONObject -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.io.IOException -import java.net.URL -import java.text.DecimalFormat -import java.util.* - - -/** - * The CurrencyConverter module. - */ -class CurrencyConverter : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(CurrencyConverter::class.java) - - override val name = "CurrencyConverter" - - // Reload currency codes - private fun reload(apiKey: String?) { - if (!apiKey.isNullOrEmpty() && SYMBOLS.isEmpty()) { - try { - loadSymbols(apiKey) - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) - } - } - } - - /** - * Converts the specified currencies. - */ - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - reload(properties[API_KEY_PROP]) - - when { - SYMBOLS.isEmpty() -> { - event.respond(EMPTY_SYMBOLS_TABLE) - } - - args.matches("\\d+([,\\d]+)?(\\.\\d+)? [a-zA-Z]{3}+ (to|in) [a-zA-Z]{3}+".toRegex()) -> { - val msg = convertCurrency(properties[API_KEY_PROP], args) - event.respond(msg.msg) - if (msg.isError) { - helpResponse(event) - } - } - - args.contains(CODES_KEYWORD) -> { - event.sendMessage("The supported currency codes are:") - event.sendList(SYMBOLS.keys.toList(), 11, isIndent = true) - } - - else -> { - helpResponse(event) - } - } - } - - override fun helpResponse(event: GenericMessageEvent): Boolean { - reload(properties[API_KEY_PROP]) - - if (SYMBOLS.isEmpty()) { - event.sendMessage(EMPTY_SYMBOLS_TABLE) - } else { - val nick = event.bot().nick - event.sendMessage("To convert from one currency to another:") - event.sendMessage(helpFormat(helpCmdSyntax("%c $CURRENCY_CMD 100 USD to EUR", nick, isPrivateMsgEnabled))) - event.sendMessage( - helpFormat( - helpCmdSyntax("%c $CURRENCY_CMD 50,000 GBP to USD", nick, isPrivateMsgEnabled) - ) - ) - event.sendMessage("To list the supported currency codes:") - event.sendMessage( - helpFormat( - helpCmdSyntax("%c $CURRENCY_CMD $CODES_KEYWORD", nick, isPrivateMsgEnabled) - ) - ) - } - return true - } - - companion object { - /** - * The API Key property. - */ - const val API_KEY_PROP = "exchangerate-api-key" - - // Currency command - private const val CURRENCY_CMD = "currency" - - // Currency codes keyword - private const val CODES_KEYWORD = "codes" - - // Empty symbols table. - private const val EMPTY_SYMBOLS_TABLE = "Sorry, but the currency table is empty." - - // Currency symbols - private val SYMBOLS: TreeMap<String, String> = TreeMap() - - // Decimal format - private val DECIMAL_FORMAT = DecimalFormat("0.00#") - - /** - * Converts from a currency to another. - */ - @JvmStatic - fun convertCurrency(apiKey: String?, query: String): Message { - if (apiKey.isNullOrEmpty()) { - throw ModuleException("${CURRENCY_CMD}($query)", "No Exchange Rate API key specified.") - } - - val cmds = query.split(" ") - return if (cmds.size == 4) { - if (cmds[3] == cmds[1] || "0" == cmds[0]) { - PublicMessage("You're kidding, right?") - } else { - val to = cmds[1].uppercase() - val from = cmds[3].uppercase() - if (SYMBOLS.contains(to) && SYMBOLS.contains(from)) { - try { - val amt = cmds[0].replace(",", "") - val url = URL("https://v6.exchangerate-api.com/v6/$apiKey/pair/$to/$from/$amt") - val body = url.reader().body - val json = JSONObject(body) - - if (json.getString("result") == "success") { - val result = DECIMAL_FORMAT.format(json.getDouble("conversion_result")) - PublicMessage( - "${cmds[0]} ${SYMBOLS[to]} = $result ${SYMBOLS[from]}" - ) - } else { - ErrorMessage("Sorry, an error occurred while converting the currencies.") - } - } catch (ignore: IOException) { - ErrorMessage("Sorry, an IO error occurred while converting the currencies.") - } - } else { - ErrorMessage("Sounds like monopoly money to me!") - } - } - } else { - ErrorMessage("Invalid query. Let's try again.") - } - } - - /** - * Loads the currency ISO symbols. - */ - @JvmStatic - @Throws(ModuleException::class) - fun loadSymbols(apiKey: String?) { - if (!apiKey.isNullOrEmpty()) { - try { - val url = URL("https://v6.exchangerate-api.com/v6/$apiKey/codes") - val json = JSONObject(url.reader().body) - if (json.getString("result") == "success") { - val codes = json.getJSONArray("supported_codes") - for (i in 0 until codes.length()) { - val code = codes.getJSONArray(i) - SYMBOLS[code.getString(0)] = code.getString(1) - } - } - } catch (e: IOException) { - throw ModuleException( - "loadCodes(): IOE", - "An IO error has occurred while retrieving the currencies.", - e - ) - } - } - } - } - - init { - commands.add(CURRENCY_CMD) - initProperties(API_KEY_PROP) - loadSymbols(properties[ChatGpt.API_KEY_PROP]) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/Dice.kt b/bin/main/net/thauvin/erik/mobibot/modules/Dice.kt deleted file mode 100644 index 8420fb1..0000000 --- a/bin/main/net/thauvin/erik/mobibot/modules/Dice.kt +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Dice.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.Utils.helpFormat -import org.pircbotx.hooks.types.GenericMessageEvent - -/** - * The Dice module. - */ -class Dice : AbstractModule() { - override val name = "Dice" - - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - val arg = if (args.isBlank()) "2d6" else args.trim() - val match = Regex("^([1-9]|[12]\\d|3[0-2])[dD]([1-9]|[12]\\d|3[0-2])$").find(arg) - if (match != null) { - val (dice, sides) = match.destructured - event.respond("you rolled " + roll(dice.toInt(), sides.toInt())) - } else { - helpResponse(event) - } - } - - companion object { - // Dice command - private const val DICE_CMD = "dice" - - @JvmStatic - fun roll(dice: Int, sides: Int): String { - val result = StringBuilder() - var total = 0 - - repeat(dice) { - val roll = (1..sides).random() - total += roll - - if (result.isNotEmpty()) { - result.append(" + ") - } - - result.append(roll.bold()) - } - - if (dice != 1) { - result.append(" = ${total.bold()}") - } - - return result.toString() - } - } - - init { - commands.add(DICE_CMD) - help.add("To roll 2 dice with 6 sides:") - help.add(helpFormat("%c $DICE_CMD [2d6]")) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/GoogleSearch.kt b/bin/main/net/thauvin/erik/mobibot/modules/GoogleSearch.kt deleted file mode 100644 index f426d1e..0000000 --- a/bin/main/net/thauvin/erik/mobibot/modules/GoogleSearch.kt +++ /dev/null @@ -1,162 +0,0 @@ -/* - * GoogleSearch.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import net.thauvin.erik.mobibot.ReleaseInfo -import net.thauvin.erik.mobibot.Utils.capitalise -import net.thauvin.erik.mobibot.Utils.colorize -import net.thauvin.erik.mobibot.Utils.encodeUrl -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.reader -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.Utils.unescapeXml -import net.thauvin.erik.mobibot.msg.ErrorMessage -import net.thauvin.erik.mobibot.msg.Message -import net.thauvin.erik.mobibot.msg.NoticeMessage -import org.json.JSONException -import org.json.JSONObject -import org.pircbotx.Colors -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.io.IOException -import java.net.URL - -/** - * The GoogleSearch module. - */ -class GoogleSearch : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(GoogleSearch::class.java) - - override val name = "GoogleSearch" - - /** - * Searches Google. - */ - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - if (args.isNotBlank()) { - try { - val results = searchGoogle( - args, - properties[API_KEY_PROP], - properties[CSE_KEY_PROP], - event.user.nick - ) - for (msg in results) { - if (msg.isError) { - event.respond(msg.msg.colorize(msg.color)) - } else { - event.sendMessage(channel, msg) - } - } - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) - e.message?.let { - event.respond(it) - } - } - } else { - helpResponse(event) - } - } - - companion object { - // Google API Key property - const val API_KEY_PROP = "google-api-key" - - // Google Custom Search Engine ID property - const val CSE_KEY_PROP = "google-cse-cx" - - // Google command - private const val GOOGLE_CMD = "google" - - /** - * Performs a search on Google. - */ - @JvmStatic - @Throws(ModuleException::class) - fun searchGoogle( - query: String, - apiKey: String?, - cseKey: String?, - quotaUser: String = ReleaseInfo.PROJECT - ): List<Message> { - if (apiKey.isNullOrBlank() || cseKey.isNullOrBlank()) { - throw ModuleException( - "${GoogleSearch::class.java.name} is disabled.", - "${GOOGLE_CMD.capitalise()} is disabled. The API keys are missing." - ) - } - val results = mutableListOf<Message>() - if (query.isNotBlank()) { - try { - val url = URL( - "https://www.googleapis.com/customsearch/v1?key=$apiKey&cx=$cseKey" + - ""aUser=${quotaUser}&q=${query.encodeUrl()}&filter=1&num=5&alt=json" - ) - val json = JSONObject(url.reader().body) - if (json.has("items")) { - val ja = json.getJSONArray("items") - for (i in 0 until ja.length()) { - val j = ja.getJSONObject(i) - results.add(NoticeMessage(j.getString("title").unescapeXml())) - results.add(NoticeMessage(helpFormat(j.getString("link"), false), Colors.DARK_GREEN)) - } - } else if (json.has("error")) { - val error = json.getJSONObject("error") - val message = error.getString("message") - throw ModuleException("searchGoogle($query): ${error.getInt("code")} : $message", message) - } else { - results.add(ErrorMessage("No results found.", Colors.RED)) - } - } catch (e: IOException) { - throw ModuleException("searchGoogle($query): IOE", "An IO error has occurred searching Google.", e) - } catch (e: JSONException) { - throw ModuleException( - "searchGoogle($query): JSON", - "A JSON error has occurred searching Google.", - e - ) - } - } else { - results.add(ErrorMessage("Invalid query. Please try again.")) - } - return results - } - } - - init { - commands.add(GOOGLE_CMD) - help.add("To search Google:") - help.add(helpFormat("%c $GOOGLE_CMD <query>")) - initProperties(API_KEY_PROP, CSE_KEY_PROP) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/Joke.kt b/bin/main/net/thauvin/erik/mobibot/modules/Joke.kt deleted file mode 100644 index 2760fa7..0000000 --- a/bin/main/net/thauvin/erik/mobibot/modules/Joke.kt +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Joke.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import net.thauvin.erik.jokeapi.exceptions.HttpErrorException -import net.thauvin.erik.jokeapi.exceptions.JokeException -import net.thauvin.erik.jokeapi.joke -import net.thauvin.erik.jokeapi.models.Type -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.colorize -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.msg.Message -import net.thauvin.erik.mobibot.msg.PublicMessage -import org.json.JSONException -import org.pircbotx.Colors -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.io.IOException - -/** - * The Joke module. - */ -class Joke : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(Joke::class.java) - - override val name = "Joke" - - /** - * Returns a random joke from [JokeAPI](https://v2.jokeapi.dev/). - */ - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - with(event.bot()) { - try { - randomJoke().forEach { - sendIRC().notice(channel, it.msg.colorize(it.color)) - } - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) - e.message?.let { - event.respond(it) - } - } - } - } - - companion object { - // Joke command - private const val JOKE_CMD = "joke" - - /** - * Retrieves a random joke. - */ - @JvmStatic - @Throws(ModuleException::class) - fun randomJoke(): List<Message> { - return try { - val joke = joke(safe = true, type = Type.SINGLE, splitNewLine = true) - joke.joke.map { PublicMessage(it, Colors.CYAN) } - } catch (e: JokeException) { - throw ModuleException("randomJoke(): ${e.additionalInfo}", e.message, e) - } catch (e: HttpErrorException) { - throw ModuleException("randomJoke(): HTTP: ${e.statusCode}", e.message, e) - } catch (e: IOException) { - throw ModuleException("randomJoke(): IOE", "An IO error has occurred retrieving a random joke.", e) - } catch (e: JSONException) { - throw ModuleException("randomJoke(): JSON", "A parsing error has occurred retrieving a random joke.", e) - } - } - } - - init { - commands.add(JOKE_CMD) - help.add("To display a random joke:") - help.add(helpFormat("%c $JOKE_CMD")) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/Lookup.kt b/bin/main/net/thauvin/erik/mobibot/modules/Lookup.kt deleted file mode 100644 index 9ab2ead..0000000 --- a/bin/main/net/thauvin/erik/mobibot/modules/Lookup.kt +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Lookup.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import net.thauvin.erik.mobibot.Constants -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpFormat -import org.apache.commons.net.whois.WhoisClient -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.io.IOException -import java.net.InetAddress -import java.net.UnknownHostException - -/** - * The Lookup module. - */ -class Lookup : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(Lookup::class.java) - - override val name = "Lookup" - - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - if (args.matches("(\\S.)+(\\S)+".toRegex())) { - try { - event.respondWith(nslookup(args).prependIndent()) - } catch (ignore: UnknownHostException) { - if (args.matches( - ("(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)") - .toRegex() - ) - ) { - try { - val lines = whois(args) - if (lines.isNotEmpty()) { - var line: String - var hasData = false - for (rawLine in lines) { - line = rawLine.trim() - if (line.matches("^\\b(?!\\b[Cc]omment\\b)\\w+\\b: .*$".toRegex())) { - if (!hasData) { - event.respondWith(line) - hasData = true - } else { - event.bot().sendIRC().notice(event.user.nick, line) - } - } - } - } else { - event.respond("Unknown host.") - } - } catch (ioe: IOException) { - if (logger.isWarnEnabled) { - logger.warn("Unable to perform whois IP lookup: $args", ioe) - } - event.respond("Unable to perform whois IP lookup: ${ioe.message}") - } - } else { - event.respond("Unknown host.") - } - } - } else { - helpResponse(event) - } - } - - companion object { - /** - * The whois default host. - */ - const val WHOIS_HOST = "whois.arin.net" - - // Lookup command - private const val LOOKUP_CMD = "lookup" - - /** - * Performs a DNS lookup on the specified query. - */ - @JvmStatic - @Throws(UnknownHostException::class) - fun nslookup(query: String): String { - val buffer = StringBuilder() - val results = InetAddress.getAllByName(query) - var hostInfo: String - for (result in results) { - if (result.hostAddress == query) { - hostInfo = result.hostName - if (hostInfo == query) { - throw UnknownHostException() - } - } else { - hostInfo = result.hostAddress - } - if (buffer.isNotEmpty()) { - buffer.append(", ") - } - buffer.append(hostInfo) - } - return buffer.toString() - } - - /** - * Performs a whois IP query. - */ - @Throws(IOException::class) - private fun whois(query: String): List<String> { - return whois(query, WHOIS_HOST) - } - - /** - * Performs a whois IP query. - */ - @JvmStatic - @Throws(IOException::class) - fun whois(query: String, host: String): List<String> { - val whoisClient = WhoisClient() - val lines: List<String> - with(whoisClient) { - try { - defaultTimeout = Constants.CONNECT_TIMEOUT - connect(host) - soTimeout = Constants.CONNECT_TIMEOUT - setSoLinger(false, 0) - lines = if (WHOIS_HOST == host) { - query("n - $query").split("\n") - } else { - query(query).split("\n") - } - } finally { - disconnect() - } - } - return lines - } - } - - init { - commands.add(LOOKUP_CMD) - help.add("To perform a DNS lookup query:") - help.add(helpFormat("%c $LOOKUP_CMD <ip address or hostname>")) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/Mastodon.kt b/bin/main/net/thauvin/erik/mobibot/modules/Mastodon.kt deleted file mode 100644 index 3be3a5f..0000000 --- a/bin/main/net/thauvin/erik/mobibot/modules/Mastodon.kt +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Mastodon.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.modules - -import net.thauvin.erik.mobibot.Utils -import net.thauvin.erik.mobibot.Utils.prefixIfMissing -import net.thauvin.erik.mobibot.entries.EntryLink -import net.thauvin.erik.mobibot.social.SocialModule -import org.json.JSONException -import org.json.JSONObject -import org.json.JSONWriter -import java.io.IOException -import java.net.URI -import java.net.http.HttpClient -import java.net.http.HttpRequest -import java.net.http.HttpResponse - -class Mastodon : SocialModule() { - override val name = "Mastodon" - - override val handle: String? - get() = properties[HANDLE_PROP] - - override val isAutoPost: Boolean - get() = isEnabled && properties[AUTO_POST_PROP].toBoolean() - - override val isValidProperties: Boolean - get() = !(properties[INSTANCE_PROP].isNullOrBlank() || properties[ACCESS_TOKEN_PROP].isNullOrBlank()) - - /** - * Formats the entry for posting. - */ - override fun formatEntry(entry: EntryLink): String { - return "${entry.title} (via ${entry.nick} on ${entry.channel})${formatTags(entry)}\n\n${entry.link}" - } - - private fun formatTags(entry: EntryLink): String { - return entry.tags.filter { !it.name.equals(entry.channel.removePrefix("#"), true) } - .joinToString(separator = " ", prefix = "\n\n") { "#${it.name}" } - } - - /** - * Posts on Mastodon. - */ - @Throws(ModuleException::class) - override fun post(message: String, isDm: Boolean): String { - return toot( - apiKey = properties[ACCESS_TOKEN_PROP], - instance = properties[INSTANCE_PROP], - handle = handle, - message = message, - isDm = isDm - ) - } - - companion object { - // Property keys - const val ACCESS_TOKEN_PROP = "mastodon-access-token" - const val AUTO_POST_PROP = "mastodon-auto-post" - const val HANDLE_PROP = "mastodon-handle" - const val INSTANCE_PROP = "mastodon-instance" - - private const val MASTODON_CMD = "mastodon" - private const val TOOT_CMD = "toot" - - /** - * Post on Mastodon. - */ - @JvmStatic - @Throws(ModuleException::class) - fun toot(apiKey: String?, instance: String?, handle: String?, message: String, isDm: Boolean): String { - val request = HttpRequest.newBuilder() - .uri(URI.create("https://$instance/api/v1/statuses")) - .header("Content-Type", "application/json") - .header("Authorization", "Bearer $apiKey") - .POST( - HttpRequest.BodyPublishers.ofString( - JSONWriter.valueToString( - if (isDm) { - mapOf("status" to "${handle?.prefixIfMissing('@')} $message", "visibility" to "direct") - } else { - mapOf("status" to message) - } - ) - ) - ) - .build() - try { - val response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString()) - if (response.statusCode() == 200) { - return try { - val jsonResponse = JSONObject(response.body()) - if (isDm) { - jsonResponse.getString("content") - } else { - "Your message was posted to ${jsonResponse.getString("url")}" - } - } catch (e: JSONException) { - throw ModuleException("mastodonPost($message)", "A JSON error has occurred: ${e.message}", e) - } - } else { - throw IOException("Status Code: " + response.statusCode()) - } - } catch (e: IOException) { - throw ModuleException("mastodonPost($message)", "An IO error has occurred: ${e.message}", e) - } catch (e: InterruptedException) { - throw ModuleException("mastodonPost($message)", "An error has occurred: ${e.message}", e) - } - } - } - - init { - commands.add(MASTODON_CMD) - commands.add(TOOT_CMD) - help.add("To toot on Mastodon:") - help.add(Utils.helpFormat("%c $TOOT_CMD <message>")) - properties[AUTO_POST_PROP] = "false" - initProperties(ACCESS_TOKEN_PROP, HANDLE_PROP, INSTANCE_PROP) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/ModuleException.kt b/bin/main/net/thauvin/erik/mobibot/modules/ModuleException.kt deleted file mode 100644 index a7416c2..0000000 --- a/bin/main/net/thauvin/erik/mobibot/modules/ModuleException.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * ModuleException.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -/** - * The `ModuleException` class. - */ -class ModuleException @JvmOverloads constructor( - val debugMessage: String, - message: String? = null, - cause: Throwable? = null -) : Exception(message, cause) { - companion object { - @Suppress("ConstPropertyName") - private const val serialVersionUID = 1L - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/Ping.kt b/bin/main/net/thauvin/erik/mobibot/modules/Ping.kt deleted file mode 100644 index 944dbc1..0000000 --- a/bin/main/net/thauvin/erik/mobibot/modules/Ping.kt +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Ping.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpFormat -import org.pircbotx.hooks.types.GenericMessageEvent - -/** - * The Ping module. - */ -class Ping : AbstractModule() { - override val name = "Ping" - - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - event.bot().sendIRC().action(channel, randomPing()) - } - - companion object { - /** - * The ping responses. - */ - @JvmField - val PINGS = listOf( - "is barely alive.", - "is trying to stay awake.", - "has gone fishing.", - "is somewhere over the rainbow.", - "has fallen and can't get up.", - "is running. You better go chase it.", - "has just spontaneously combusted.", - "is talking to itself... don't interrupt. That's rude.", - "is bartending at an AA meeting.", - "is hibernating.", - "is saving energy: apathetic mode activated.", - "is busy. Go away!" - ) - - @JvmStatic - fun randomPing(): String { - return PINGS[PINGS.indices.random()] - } - - /** - * The ping command. - */ - private const val PING_CMD = "ping" - } - - init { - commands.add(PING_CMD) - help.add("To ping the bot:") - help.add(helpFormat("%c $PING_CMD")) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt b/bin/main/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt deleted file mode 100644 index a299d8d..0000000 --- a/bin/main/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt +++ /dev/null @@ -1,114 +0,0 @@ -/* - * RockPaperScissors.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.modules - -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.Utils.helpFormat -import org.pircbotx.hooks.types.GenericMessageEvent - - -/** - * Simple module example in Kotlin. - */ -class RockPaperScissors : AbstractModule() { - override val name = "RockPaperScissors" - - init { - with(commands) { - add(Hands.ROCK.name.lowercase()) - add(Hands.PAPER.name.lowercase()) - add(Hands.SCISSORS.name.lowercase()) - } - - with(help) { - add("To play Rock Paper Scissors:") - add( - helpFormat( - "%c ${Hands.ROCK.name.lowercase()} | ${Hands.PAPER.name.lowercase()}" - + " | ${Hands.SCISSORS.name.lowercase()}" - ) - ) - } - } - - enum class Hands(val action: String) { - ROCK("crushes") { - override fun beats(hand: Hands): Boolean { - return hand == SCISSORS - } - }, - PAPER("covers") { - override fun beats(hand: Hands): Boolean { - return hand == ROCK - } - }, - SCISSORS("cuts") { - override fun beats(hand: Hands): Boolean { - return hand == PAPER - } - }; - - abstract fun beats(hand: Hands): Boolean - } - - companion object { - // For testing. - fun winLoseOrDraw(player: String, bot: String): String { - val hand = Hands.valueOf(player.uppercase()) - val botHand = Hands.valueOf(bot.uppercase()) - - return when { - hand == botHand -> "draw" - hand.beats(botHand) -> "win" - else -> "lose" - } - } - } - - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - val hand = Hands.valueOf(cmd.uppercase()) - val botHand = Hands.entries[(0..Hands.entries.size).random()] - when { - hand == botHand -> { - event.respond("${hand.name} vs. ${botHand.name} » You ${"tie".bold()}.") - } - - hand.beats(botHand) -> { - event.respond("${hand.name.bold()} ${hand.action} ${botHand.name} » You ${"win".bold()}!") - } - - else -> { - event.respond("${botHand.name.bold()} ${botHand.action} ${hand.name} » You ${"lose".bold()}!") - } - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/StockQuote.kt b/bin/main/net/thauvin/erik/mobibot/modules/StockQuote.kt deleted file mode 100644 index dcae5e7..0000000 --- a/bin/main/net/thauvin/erik/mobibot/modules/StockQuote.kt +++ /dev/null @@ -1,236 +0,0 @@ -/* - * StockQuote.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import net.thauvin.erik.mobibot.Utils.capitalise -import net.thauvin.erik.mobibot.Utils.encodeUrl -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.reader -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.Utils.unescapeXml -import net.thauvin.erik.mobibot.msg.ErrorMessage -import net.thauvin.erik.mobibot.msg.Message -import net.thauvin.erik.mobibot.msg.NoticeMessage -import net.thauvin.erik.mobibot.msg.PublicMessage -import org.json.JSONException -import org.json.JSONObject -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.io.IOException -import java.net.URL - -/** - * The StockQuote module. - */ -class StockQuote : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(StockQuote::class.java) - - override val name = "StockQuote" - - /** - * Returns the specified stock quote from Alpha Vantage. - */ - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - if (args.isNotBlank()) { - try { - val messages = getQuote(args, properties[API_KEY_PROP]) - for (msg in messages) { - event.sendMessage(channel, msg) - } - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) - e.message?.let { - event.respond(it) - } - } - } else { - helpResponse(event) - } - } - - companion object { - /** - * The API property key. - */ - const val API_KEY_PROP = "alphavantage-api-key" - - /** - * The Invalid Symbol error string. - */ - const val INVALID_SYMBOL = "Invalid symbol." - - // API URL - private const val API_URL = "https://www.alphavantage.co/query?function=" - - // Quote command - private const val STOCK_CMD = "stock" - - @Throws(ModuleException::class) - private fun getJsonResponse(response: String, debugMessage: String): JSONObject { - return if (response.isNotBlank()) { - val json = JSONObject(response) - try { - val info = json.getString("Information") - if (info.isNotEmpty()) { - throw ModuleException(debugMessage, info.unescapeXml()) - } - } catch (ignore: JSONException) { - // Do nothing - } - try { - var error = json.getString("Note") - if (error.isNotEmpty()) { - throw ModuleException(debugMessage, error.unescapeXml()) - } - error = json.getString("Error Message") - if (error.isNotEmpty()) { - throw ModuleException(debugMessage, error.unescapeXml()) - } - } catch (ignore: JSONException) { - // Do nothing - } - json - } else { - throw ModuleException(debugMessage, "Empty Response.") - } - } - - /** - * Retrieves a stock quote. - */ - @JvmStatic - @Throws(ModuleException::class) - fun getQuote(symbol: String, apiKey: String?): List<Message> { - if (apiKey.isNullOrBlank()) { - throw ModuleException( - "${StockQuote::class.java.name} is disabled.", - "${STOCK_CMD.capitalise()} is disabled. The API key is missing." - ) - } - val messages = mutableListOf<Message>() - if (symbol.isNotBlank()) { - val debugMessage = "getQuote($symbol)" - var response: String - try { - with(messages) { - // Search for symbol/keywords - response = URL( - "${API_URL}SYMBOL_SEARCH&keywords=" + symbol.encodeUrl() + "&apikey=" - + apiKey.encodeUrl() - ).reader().body - var json = getJsonResponse(response, debugMessage) - val symbols = json.getJSONArray("bestMatches") - if (symbols.isEmpty) { - messages.add(ErrorMessage(INVALID_SYMBOL)) - } else { - val symbolInfo = symbols.getJSONObject(0) - - // Get quote for symbol - response = URL( - "${API_URL}GLOBAL_QUOTE&symbol=" - + symbolInfo.getString("1. symbol").encodeUrl() + "&apikey=" - + apiKey.encodeUrl() - ).reader().body - json = getJsonResponse(response, debugMessage) - val quote = json.getJSONObject("Global Quote") - if (quote.isEmpty) { - add(ErrorMessage(INVALID_SYMBOL)) - } else { - - add( - PublicMessage( - "Symbol: " + quote.getString("01. symbol").unescapeXml() - + " [" + symbolInfo.getString("2. name").unescapeXml() + ']' - ) - ) - - val pad = 10 - - add( - PublicMessage( - "Price:".padEnd(pad).prependIndent() - + quote.getString("05. price").unescapeXml() - ) - ) - add( - PublicMessage( - "Previous:".padEnd(pad).prependIndent() - + quote.getString("08. previous close").unescapeXml() - ) - ) - - val data = arrayOf( - "Open" to "02. open", - "High" to "03. high", - "Low" to "04. low", - "Volume" to "06. volume", - "Latest" to "07. latest trading day" - ) - - data.forEach { - add( - NoticeMessage( - "${it.first}:".padEnd(pad).prependIndent() - + quote.getString(it.second).unescapeXml() - ) - ) - } - - add( - NoticeMessage( - "Change:".padEnd(pad).prependIndent() - + quote.getString("09. change").unescapeXml() - + " [" + quote.getString("10. change percent").unescapeXml() + ']' - ) - ) - } - } - } - } catch (e: IOException) { - throw ModuleException("$debugMessage: IOE", "An IO error has occurred retrieving a stock quote.", e) - } catch (e: NullPointerException) { - throw ModuleException("$debugMessage: NPE", "An error has occurred retrieving a stock quote.", e) - } - } else { - messages.add(ErrorMessage(INVALID_SYMBOL)) - } - return messages - } - } - - init { - commands.add(STOCK_CMD) - help.add("To retrieve a stock quote:") - help.add(helpFormat("%c $STOCK_CMD <symbol|keywords>")) - initProperties(API_KEY_PROP) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/War.class b/bin/main/net/thauvin/erik/mobibot/modules/War.class deleted file mode 100644 index 6c36e541b639c5b04b624194b3b2df6b3d11ba55..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2452 zcmeHJUvm>T5MMb??6`r@5CVjMYDuZxQXf#BNMXjcP07@D7&{5m;i02DE4IR&<VrfX zdE`?u)6T$qzXso<)79MtNOEL4Q<&*PAFN&Jw7b7u?N9QbfBpUv0Pe%LB`6SBliYfC z%;Kq#9@pZT7b#!(%Ay>`AvfL=rb|#HaAuE9nHMrS@;3cF9#{gi&Cd4s0|IBCcHVv* zSS{peoj|#@(dcgWTDW2EQM=LKa!S9^Yi)K3Tuv<v4`MCszBh0R?=v}65!%iT9yeNT zG$^*(%^wLYKg|tMdeZ3s-0ZdpEaf3M)l|}0ChZOjV_t?O0yDodjqbk_QrHJLt=4uh zNK*}Y3C<H(e49sGYo*I@krZBUOU;c6r+i2Q6-`9QtWc6pwDLn9nR~P{zcuDmL=&Yg z#fsLmiq>64>sdwX+g5~z224t2sn6+w(|>E-@Qu|hu-)Xuasp7RD5G|N!YlKbK!jD! z$1&#NB*(ro|K1NL=M-@}Rzo`Cw#On~tx>g`z@XSvG>VO-YRa`1Lr#@;^}}*<X%Vc6 zCtN$kH1(0zDD#))(C21?2h6K!%iW|$<qurq0R&xc3>)$G6kUHP2)+u3S=<^GhQ@Np zcZI|b*~LsOc0&Rl^E`z7KWkQj6}YqjXW=q|bJgQyax_`&V1m6k^10q(*!hliDq!Ib z)56WO#iAVxL*Pc|pIj}-^-|Uz$nt9Kcw_>X`mwYk;u~@*jKDw*$Do9R80UIN>5;d` zt*@Do#!Kjxe)M|E_Tn&HFT)K2zno0t0~UY4o+WVYDD*9C=|k`rk2EuZQBL`fmnCP# z)nOuZfVcN=-dL$;#&b<*yc`~^y8~T2itaJf$WzPpI}poolaS{p*Y3>~_&-5MAL%+E zP#LIL2mGOM%q!!~Qg@FP(se@ycnu0;@qT+GxMn&S@0Z{<fzyYd1_BFRVGKUct_=;` z27CeW&p-)QVHW04TSYyU<xI{)C0YL@n=inrWPTbJ(fSPP1^5)b;J*M^#_=4k+)d^H zl|NwRr=<%oVD(k9?+T7{xCh{KxQgRKqF3M=P@EC?4A*DiI_hrM8p`9|zR2;`&GGgn zT9<(=L*j=(6>8}FD_p%;%$%no-W?CZ&EmEc{MR|*w%-%(Dil}H5OJ?yj!qO(fi-r? U%)mD|7N8CuN`O1~b69Tu4Ue7BiU0rr diff --git a/bin/main/net/thauvin/erik/mobibot/modules/Weather2.kt b/bin/main/net/thauvin/erik/mobibot/modules/Weather2.kt deleted file mode 100644 index 80a06fa..0000000 --- a/bin/main/net/thauvin/erik/mobibot/modules/Weather2.kt +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Weather2.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import net.aksingh.owmjapis.api.APIException -import net.aksingh.owmjapis.core.OWM -import net.aksingh.owmjapis.core.OWM.Country -import net.aksingh.owmjapis.model.CurrentWeather -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.Utils.capitalise -import net.thauvin.erik.mobibot.Utils.capitalizeWords -import net.thauvin.erik.mobibot.Utils.encodeUrl -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.msg.ErrorMessage -import net.thauvin.erik.mobibot.msg.Message -import net.thauvin.erik.mobibot.msg.NoticeMessage -import net.thauvin.erik.mobibot.msg.PublicMessage -import org.pircbotx.Colors -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import kotlin.math.roundToInt - -/** - * The `Weather2` module. - */ -class Weather2 : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(Weather2::class.java) - - override val name = "Weather" - - /** - * Fetches the weather data from a specific city. - */ - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - if (args.isNotBlank()) { - try { - val messages = getWeather(args, properties[API_KEY_PROP]) - if (messages[0].isError) { - helpResponse(event) - } else { - for (msg in messages) { - event.sendMessage(channel, msg) - } - } - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) - e.message?.let { - event.respond(it) - } - } - } else { - helpResponse(event) - } - } - - companion object { - /** - * The OpenWeatherMap API Key property. - */ - const val API_KEY_PROP = "owm-api-key" - - // Weather command - private const val WEATHER_CMD = "weather" - - /** - * Converts and rounds temperature from °F to °C. - */ - fun ftoC(d: Double): Pair<Int, Int> { - val c = (d - 32) * 5 / 9 - return d.roundToInt() to c.roundToInt() - } - - /** - * Returns a country based on its country code. Defaults to [Country.UNITED_STATES] if not found. - */ - fun getCountry(countryCode: String): Country { - for (c in Country.entries) { - if (c.value.equals(countryCode, ignoreCase = true)) { - return c - } - } - return Country.UNITED_STATES - } - - /** - * Retrieves the weather data. - */ - @JvmStatic - @Throws(ModuleException::class) - fun getWeather(query: String, apiKey: String?): List<Message> { - if (apiKey.isNullOrBlank()) { - throw ModuleException( - "${Weather2::class.java.name} is disabled.", - "${WEATHER_CMD.capitalise()} is disabled. The API key is missing." - ) - } - val owm = OWM(apiKey) - val messages = mutableListOf<Message>() - owm.unit = OWM.Unit.IMPERIAL - if (query.isNotBlank()) { - val argv = query.split(",") - if (argv.size in 1..2) { - val city = argv[0].trim() - val code: String = if (argv.size > 1 && argv[1].isNotBlank()) { - argv[1].trim() - } else { - "US" - } - try { - val country = getCountry(code) - val cwd: CurrentWeather = if (city.matches("\\d+".toRegex())) { - owm.currentWeatherByZipCode(city.toInt(), country) - } else { - owm.currentWeatherByCityName(city, country) - } - if (cwd.hasCityName()) { - messages.add( - PublicMessage( - "City: ${cwd.cityName}, " + - country.name.replace('_', ' ').capitalizeWords() + " [${country.value}]" - ) - ) - cwd.mainData?.let { - with(it) { - if (hasTemp()) { - temp?.let { t -> - val (f, c) = ftoC(t) - messages.add(PublicMessage("Temperature: ${f}°F, ${c}°C")) - } - } - if (hasHumidity()) { - humidity?.let { h -> - messages.add(NoticeMessage("Humidity: ${h.roundToInt()}%")) - } - } - } - } - if (cwd.hasWindData()) { - cwd.windData?.let { - if (it.hasSpeed()) { - it.speed?.let { s -> - val w = mphToKmh(s) - messages.add(NoticeMessage("Wind: ${w.first} mph, ${w.second} km/h")) - } - } - } - } - if (cwd.hasWeatherList()) { - val condition = StringBuilder("Condition:") - cwd.weatherList?.let { - for (w in it) { - w?.let { - condition.append(' ') - .append(w.getDescription().capitalise()) - .append('.') - } - } - messages.add(NoticeMessage(condition.toString())) - } - } - if (cwd.hasCityId()) { - cwd.cityId?.let { - if (it > 0) { - messages.add( - NoticeMessage("https://openweathermap.org/city/$it", Colors.GREEN) - ) - } else { - messages.add( - NoticeMessage( - "https://openweathermap.org/find?q=" - + "$city,${code.uppercase()}".encodeUrl(), - Colors.GREEN - ) - ) - } - } - } - } - } catch (e: APIException) { - if (e.code == 404) { - throw ModuleException( - "getWeather($query): API ${e.code}", - "The requested city was not found.", - e - ) - } else { - throw ModuleException("getWeather($query): API ${e.code}", e.message, e) - } - } catch (e: NullPointerException) { - throw ModuleException("getWeather($query): NPE", "Unable to perform weather lookup.", e) - } - } - } - if (messages.isEmpty()) { - messages.add(ErrorMessage("Invalid syntax.")) - } - return messages - } - - /** - * Converts and rounds temperature from mph to km/h. - */ - fun mphToKmh(w: Double): Pair<Int, Int> { - val kmh = w * 1.60934 - return w.roundToInt() to kmh.roundToInt() - } - } - - init { - commands.add(WEATHER_CMD) - with(help) { - add("To display weather information:") - add(helpFormat("%c $WEATHER_CMD <city> [, <country code>]")) - add("For example:") - add(helpFormat("%c $WEATHER_CMD paris, fr")) - add("The default ISO 3166 country code is ${"US".bold()}. Zip codes supported in most countries.") - } - initProperties(API_KEY_PROP) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/WolframAlpha.kt b/bin/main/net/thauvin/erik/mobibot/modules/WolframAlpha.kt deleted file mode 100644 index a72efab..0000000 --- a/bin/main/net/thauvin/erik/mobibot/modules/WolframAlpha.kt +++ /dev/null @@ -1,142 +0,0 @@ -/* - * WolframAlpha.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.modules - -import net.thauvin.erik.mobibot.Utils -import net.thauvin.erik.mobibot.Utils.encodeUrl -import net.thauvin.erik.mobibot.Utils.isHttpSuccess -import net.thauvin.erik.mobibot.Utils.reader -import net.thauvin.erik.mobibot.Utils.sendMessage -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.io.IOException -import java.net.URL - -class WolframAlpha : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(WolframAlpha::class.java) - - override val name = "WolframAlpha" - - private fun getUnits(unit: String?): String { - return if (unit?.lowercase() == METRIC) { - METRIC - } else { - IMPERIAL - } - } - - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - if (args.isNotBlank()) { - try { - val query = args.trim().split("units=", limit = 2, ignoreCase = true) - event.sendMessage( - queryWolfram( - query[0].trim(), - units = if (query.size == 2) { - getUnits(query[1].trim()) - } else { - getUnits(properties[UNITS_PROP]) - }, - appId = properties[APPID_KEY_PROP] - ) - ) - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) - e.message?.let { - event.respond(it) - } - } - } else { - helpResponse(event) - } - } - - companion object { - /** - * The Wolfram Alpha API Key property. - */ - const val APPID_KEY_PROP = "wolfram-appid" - - /** - * The Wolfram units properties - */ - const val UNITS_PROP = "wolfram-units" - - const val METRIC = "metric" - const val IMPERIAL = "imperial" - - // Wolfram command - private const val WOLFRAM_CMD = "wolfram" - - // Wolfram Alpha API URL - private const val API_URL = "http://api.wolframalpha.com/v1/spoken?appid=" - - @JvmStatic - @Throws(ModuleException::class) - fun queryWolfram(query: String, units: String = IMPERIAL, appId: String?): String { - if (!appId.isNullOrEmpty()) { - try { - val urlReader = URL("${API_URL}${appId}&units=${units}&i=" + query.encodeUrl()).reader() - if (urlReader.responseCode.isHttpSuccess()) { - return urlReader.body - } else { - throw ModuleException( - "wolfram($query): ${urlReader.responseCode} : ${urlReader.body} ", - urlReader.body.ifEmpty { - "Looks like Wolfram Alpha isn't able to answer that. (${urlReader.responseCode})" - } - ) - } - } catch (ioe: IOException) { - throw ModuleException( - "wolfram($query): IOE", "An IO Error occurred while querying Wolfram Alpha.", ioe - ) - } - } else { - throw ModuleException("wolfram($query): No API Key", "No Wolfram Alpha API key specified.") - } - } - } - - init { - commands.add(WOLFRAM_CMD) - with(help) { - add("To get answers from Wolfram Alpha:") - add(Utils.helpFormat("%c $WOLFRAM_CMD <query> [units=(${METRIC}|${IMPERIAL})]")) - add("For example:") - add(Utils.helpFormat("%c $WOLFRAM_CMD days until christmas")) - add(Utils.helpFormat("%c $WOLFRAM_CMD distance earth moon units=metric")) - } - initProperties(APPID_KEY_PROP, UNITS_PROP) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/WorldTime.kt b/bin/main/net/thauvin/erik/mobibot/modules/WorldTime.kt deleted file mode 100644 index 18072bc..0000000 --- a/bin/main/net/thauvin/erik/mobibot/modules/WorldTime.kt +++ /dev/null @@ -1,390 +0,0 @@ -/* - * WorldTime.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.sendList -import net.thauvin.erik.mobibot.Utils.sendMessage -import org.pircbotx.hooks.types.GenericMessageEvent -import java.time.ZoneId -import java.time.ZonedDateTime -import java.time.format.DateTimeFormatter -import java.time.temporal.ChronoField - -/** - * The WorldTime module. - */ -class WorldTime : AbstractModule() { - override val name = "WorldTime" - - companion object { - /** - * Beats (Internet Time) keyword - */ - const val BEATS_KEYWORD = ".beats" - - /** - * Supported countries - */ - val COUNTRIES_MAP = buildMap<String, String> { - put("AG", "America/Antigua") - put("AI", "America/Anguilla") - put("AE", "Asia/Dubai") - put("AD", "Europe/Andorra") - put("AKDT", "America/Anchorage") - put("AF", "Asia/Kabul") - put("AKST", "America/Anchorage") - put("AL", "Europe/Tirane") - put("AM", "Asia/Yerevan") - put("AO", "Africa/Luanda") - put("AQ", "Antarctica/South_Pole") - put("AR", "America/Argentina/Buenos_Aires") - put("AS", "Pacific/Pago_Pago") - put("AT", "Europe/Vienna") - put("AU", "Australia/Sydney") - put("AW", "America/Aruba") - put("AX", "Europe/Mariehamn") - put("AZ", "Asia/Baku") - put("BA", "Europe/Sarajevo") - put("BB", "America/Barbados") - put("BD", "Asia/Dhaka") - put("BE", "Europe/Brussels") - put("BEAT", BEATS_KEYWORD) - put("BF", "Africa/Ouagadougou") - put("BG", "Europe/Sofia") - put("BH", "Asia/Bahrain") - put("BI", "Africa/Bujumbura") - put("BJ", "Africa/Porto-Novo") - put("BL", "America/St_Barthelemy") - put("BM", "Atlantic/Bermuda") - put("BMT", BEATS_KEYWORD) - put("BN", "Asia/Brunei") - put("BO", "America/La_Paz") - put("BQ", "America/Kralendijk") - put("BR", "America/Sao_Paulo") - put("BS", "America/Nassau") - put("BT", "Asia/Thimphu") - put("BW", "Africa/Gaborone") - put("BY", "Europe/Minsk") - put("BZ", "America/Belize") - put("CA", "America/Montreal") - put("CC", "Indian/Cocos") - put("CD", "Africa/Kinshasa") - put("CDT", "America/Chicago") - put("CET", "CET") - put("CF", "Africa/Bangui") - put("CG", "Africa/Brazzaville") - put("CH", "Europe/Zurich") - put("CI", "Africa/Abidjan") - put("CK", "Pacific/Rarotonga") - put("CL", "America/Santiago") - put("CM", "Africa/Douala") - put("CN", "Asia/Shanghai") - put("CO", "America/Bogota") - put("CR", "America/Costa_Rica") - put("CST", "America/Chicago") - put("CU", "Cuba") - put("CV", "Atlantic/Cape_Verde") - put("CW", "America/Curacao") - put("CX", "Indian/Christmas") - put("CY", "Asia/Nicosia") - put("CZ", "Europe/Prague") - put("DE", "Europe/Berlin") - put("DJ", "Africa/Djibouti") - put("DK", "Europe/Copenhagen") - put("DM", "America/Dominica") - put("DO", "America/Santo_Domingo") - put("DZ", "Africa/Algiers") - put("EC", "Pacific/Galapagos") - put("EDT", "America/New_York") - put("EE", "Europe/Tallinn") - put("EG", "Africa/Cairo") - put("EH", "Africa/El_Aaiun") - put("ER", "Africa/Asmara") - put("ES", "Europe/Madrid") - put("EST", "America/New_York") - put("ET", "Africa/Addis_Ababa") - put("FI", "Europe/Helsinki") - put("FJ", "Pacific/Fiji") - put("FK", "Atlantic/Stanley") - put("FM", "Pacific/Yap") - put("FO", "Atlantic/Faroe") - put("FR", "Europe/Paris") - put("GA", "Africa/Libreville") - put("GB", "Europe/London") - put("GD", "America/Grenada") - put("GE", "Asia/Tbilisi") - put("GF", "America/Cayenne") - put("GG", "Europe/Guernsey") - put("GH", "Africa/Accra") - put("GI", "Europe/Gibraltar") - put("GL", "America/Thule") - put("GM", "Africa/Banjul") - put("GMT", "GMT") - put("GN", "Africa/Conakry") - put("GP", "America/Guadeloupe") - put("GQ", "Africa/Malabo") - put("GR", "Europe/Athens") - put("GS", "Atlantic/South_Georgia") - put("GT", "America/Guatemala") - put("GU", "Pacific/Guam") - put("GW", "Africa/Bissau") - put("GY", "America/Guyana") - put("HK", "Asia/Hong_Kong") - put("HN", "America/Tegucigalpa") - put("HR", "Europe/Zagreb") - put("HST", "Pacific/Honolulu") - put("HT", "America/Port-au-Prince") - put("HU", "Europe/Budapest") - put("ID", "Asia/Jakarta") - put("IE", "Europe/Dublin") - put("IL", "Asia/Tel_Aviv") - put("IM", "Europe/Isle_of_Man") - put("IN", "Asia/Kolkata") - put("IO", "Indian/Chagos") - put("IQ", "Asia/Baghdad") - put("IR", "Asia/Tehran") - put("IS", "Atlantic/Reykjavik") - put("IT", "Europe/Rome") - put("JE", "Europe/Jersey") - put("JM", "Jamaica") - put("JO", "Asia/Amman") - put("JP", "Asia/Tokyo") - put("KE", "Africa/Nairobi") - put("KG", "Asia/Bishkek") - put("KH", "Asia/Phnom_Penh") - put("KI", "Pacific/Tarawa") - put("KM", "Indian/Comoro") - put("KN", "America/St_Kitts") - put("KP", "Asia/Pyongyang") - put("KR", "Asia/Seoul") - put("KW", "Asia/Riyadh") - put("KY", "America/Cayman") - put("KZ", "Asia/Oral") - put("LA", "Asia/Vientiane") - put("LB", "Asia/Beirut") - put("LC", "America/St_Lucia") - put("LI", "Europe/Vaduz") - put("LK", "Asia/Colombo") - put("LR", "Africa/Monrovia") - put("LS", "Africa/Maseru") - put("LT", "Europe/Vilnius") - put("LU", "Europe/Luxembourg") - put("LV", "Europe/Riga") - put("LY", "Africa/Tripoli") - put("MA", "Africa/Casablanca") - put("MC", "Europe/Monaco") - put("MD", "Europe/Chisinau") - put("MDT", "America/Denver") - put("ME", "Europe/Podgorica") - put("MF", "America/Marigot") - put("MG", "Indian/Antananarivo") - put("MH", "Pacific/Majuro") - put("MK", "Europe/Skopje") - put("ML", "Africa/Timbuktu") - put("MM", "Asia/Yangon") - put("MN", "Asia/Ulaanbaatar") - put("MO", "Asia/Macau") - put("MP", "Pacific/Saipan") - put("MQ", "America/Martinique") - put("MR", "Africa/Nouakchott") - put("MS", "America/Montserrat") - put("MST", "America/Denver") - put("MT", "Europe/Malta") - put("MU", "Indian/Mauritius") - put("MV", "Indian/Maldives") - put("MW", "Africa/Blantyre") - put("MX", "America/Mexico_City") - put("MY", "Asia/Kuala_Lumpur") - put("MZ", "Africa/Maputo") - put("NA", "Africa/Windhoek") - put("NC", "Pacific/Noumea") - put("NE", "Africa/Niamey") - put("NF", "Pacific/Norfolk") - put("NG", "Africa/Lagos") - put("NI", "America/Managua") - put("NL", "Europe/Amsterdam") - put("NO", "Europe/Oslo") - put("NP", "Asia/Kathmandu") - put("NR", "Pacific/Nauru") - put("NU", "Pacific/Niue") - put("NZ", "Pacific/Auckland") - put("OM", "Asia/Muscat") - put("PA", "America/Panama") - put("PDT", "America/Los_Angeles") - put("PE", "America/Lima") - put("PF", "Pacific/Tahiti") - put("PG", "Pacific/Port_Moresby") - put("PH", "Asia/Manila") - put("PK", "Asia/Karachi") - put("PL", "Europe/Warsaw") - put("PM", "America/Miquelon") - put("PN", "Pacific/Pitcairn") - put("PR", "America/Puerto_Rico") - put("PS", "Asia/Gaza") - put("PST", "America/Los_Angeles") - put("PT", "Europe/Lisbon") - put("PW", "Pacific/Palau") - put("PY", "America/Asuncion") - put("QA", "Asia/Qatar") - put("RE", "Indian/Reunion") - put("RO", "Europe/Bucharest") - put("RS", "Europe/Belgrade") - put("RU", "Europe/Moscow") - put("RW", "Africa/Kigali") - put("SA", "Asia/Riyadh") - put("SB", "Pacific/Guadalcanal") - put("SC", "Indian/Mahe") - put("SD", "Africa/Khartoum") - put("SE", "Europe/Stockholm") - put("SG", "Asia/Singapore") - put("SH", "Atlantic/St_Helena") - put("SI", "Europe/Ljubljana") - put("SJ", "Atlantic/Jan_Mayen") - put("SK", "Europe/Bratislava") - put("SL", "Africa/Freetown") - put("SM", "Europe/San_Marino") - put("SN", "Africa/Dakar") - put("SO", "Africa/Mogadishu") - put("SR", "America/Paramaribo") - put("SS", "Africa/Juba") - put("ST", "Africa/Sao_Tome") - put("SV", "America/El_Salvador") - put("SX", "America/Lower_Princes") - put("SY", "Asia/Damascus") - put("SZ", "Africa/Mbabane") - put("TC", "America/Grand_Turk") - put("TD", "Africa/Ndjamena") - put("TF", "Indian/Kerguelen") - put("TG", "Africa/Lome") - put("TH", "Asia/Bangkok") - put("TJ", "Asia/Dushanbe") - put("TK", "Pacific/Fakaofo") - put("TL", "Asia/Dili") - put("TM", "Asia/Ashgabat") - put("TN", "Africa/Tunis") - put("TO", "Pacific/Tongatapu") - put("TR", "Europe/Istanbul") - put("TT", "America/Port_of_Spain") - put("TV", "Pacific/Funafuti") - put("TW", "Asia/Taipei") - put("TZ", "Africa/Dar_es_Salaam") - put("UA", "Europe/Kiev") - put("UG", "Africa/Kampala") - put("UK", "Europe/London") - put("UM", "Pacific/Wake") - put("US", "America/New_York") - put("UTC", "UTC") - put("UY", "America/Montevideo") - put("UZ", "Asia/Tashkent") - put("VA", "Europe/Vatican") - put("VC", "America/St_Vincent") - put("VE", "America/Caracas") - put("VG", "America/Tortola") - put("VI", "America/St_Thomas") - put("VN", "Asia/Ho_Chi_Minh") - put("VU", "Pacific/Efate") - put("WF", "Pacific/Wallis") - put("WS", "Pacific/Apia") - put("YE", "Asia/Aden") - put("YT", "Indian/Mayotte") - put("ZA", "Africa/Johannesburg") - put("ZM", "Africa/Lusaka") - put("ZULU", "Zulu") - put("ZW", "Africa/Harare") - ZoneId.getAvailableZoneIds().filter { it.length <= 3 && !containsKey(it) } - .forEach { tz -> put(tz, tz) } - } - - // The Time command - private const val TIME_CMD = "time" - - // The zones arguments - private const val ZONES_ARGS = "zones" - - // The default zone - private const val DEFAULT_ZONE = "PST" - - // Date/Time Format - private var dtf = - DateTimeFormatter.ofPattern("'The time is ${"'HH:mm'".bold()} on ${"'EEEE, d MMMM yyyy'".bold()} in '") - - /** - * Returns the current Internet (beat) Time. - */ - private fun internetTime(): String { - val zdt = ZonedDateTime.now(ZoneId.of("UTC+01:00")) - val beats = ((zdt[ChronoField.SECOND_OF_MINUTE] + zdt[ChronoField.MINUTE_OF_HOUR] * 60 - + zdt[ChronoField.HOUR_OF_DAY] * 3600) / 86.4).toInt() - return "%c%03d".format('@', beats) - } - - /** - * Returns the time for the given timezone/city. - */ - @JvmStatic - fun time(query: String = DEFAULT_ZONE): String { - val tz = COUNTRIES_MAP[(if (query.isNotBlank()) query.trim().uppercase() else DEFAULT_ZONE)] - return if (tz != null) { - if (BEATS_KEYWORD == tz) { - "The current Internet Time is ${internetTime().bold()} $BEATS_KEYWORD" - } else { - (ZonedDateTime.now().withZoneSameInstant(ZoneId.of(tz)).format(dtf) - + tz.substring(tz.lastIndexOf('/') + 1).replace('_', ' ').bold()) - } - } else { - "Unsupported country/zone. Please try again." - } - } - } - - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - if (args.equals(ZONES_ARGS, true)) { - event.sendMessage("The supported countries/zones are: ") - event.sendList(COUNTRIES_MAP.keys.sorted().map { it.padEnd(4) }, 14, isIndent = true) - } else { - event.respond(time(args)) - } - } - - override val isPrivateMsgEnabled = true - - init { - with(help) { - add("To display a country's current date/time:") - add(helpFormat("%c $TIME_CMD [<country code or zone>]")) - add("For a listing of the supported countries/zones:") - add(helpFormat("%c $TIME_CMD $ZONES_ARGS")) - } - commands.add(TIME_CMD) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/msg/ErrorMessage.kt b/bin/main/net/thauvin/erik/mobibot/msg/ErrorMessage.kt deleted file mode 100644 index 0607936..0000000 --- a/bin/main/net/thauvin/erik/mobibot/msg/ErrorMessage.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * ErrorMessage.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.msg - -/** - * The `ErrorMessage` class. - */ -class ErrorMessage @JvmOverloads constructor(msg: String, color: String = DEFAULT_COLOR) : - Message(msg, color, isError = true) diff --git a/bin/main/net/thauvin/erik/mobibot/msg/Message.kt b/bin/main/net/thauvin/erik/mobibot/msg/Message.kt deleted file mode 100644 index 23a33b9..0000000 --- a/bin/main/net/thauvin/erik/mobibot/msg/Message.kt +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Message.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.msg - -import net.thauvin.erik.semver.Constants - -/** - * The `Message` class. - */ -open class Message @JvmOverloads constructor( - var msg: String, - var color: String = DEFAULT_COLOR, - var isNotice: Boolean = false, - isError: Boolean = false, - var isPrivate: Boolean = false -) { - companion object { - var DEFAULT_COLOR = Constants.EMPTY - } - - init { - if (isError) { - isNotice = true - } - } - - /** Error flag. */ - var isError = isError - set(value) { - if (value) isNotice = true - field = value - } - - override fun toString(): String { - return "Message(color='$color', isError=$isError, isNotice=$isNotice, isPrivate=$isPrivate, msg='$msg')" - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/msg/NoticeMessage.kt b/bin/main/net/thauvin/erik/mobibot/msg/NoticeMessage.kt deleted file mode 100644 index 037d504..0000000 --- a/bin/main/net/thauvin/erik/mobibot/msg/NoticeMessage.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * NoticeMessage.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.msg - -/** - * The `NoticeMessage` class. - */ -class NoticeMessage @JvmOverloads constructor(msg: String, color: String = DEFAULT_COLOR) : - Message(msg, color, isNotice = true) - diff --git a/bin/main/net/thauvin/erik/mobibot/msg/PrivateMessage.kt b/bin/main/net/thauvin/erik/mobibot/msg/PrivateMessage.kt deleted file mode 100644 index b424fdf..0000000 --- a/bin/main/net/thauvin/erik/mobibot/msg/PrivateMessage.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * PrivateMessage.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.msg - -/** - * The `PrivateMessage` class. - */ -class PrivateMessage @JvmOverloads constructor(msg: String, color: String = DEFAULT_COLOR) : - Message(msg, color, isPrivate = true) diff --git a/bin/main/net/thauvin/erik/mobibot/msg/PublicMessage.kt b/bin/main/net/thauvin/erik/mobibot/msg/PublicMessage.kt deleted file mode 100644 index 9c5e088..0000000 --- a/bin/main/net/thauvin/erik/mobibot/msg/PublicMessage.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * PublicMessage.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.msg - -/** - * The `PublicMessage` class. - */ -class PublicMessage @JvmOverloads constructor(msg: String, color: String = DEFAULT_COLOR) : Message(msg, color) diff --git a/bin/main/net/thauvin/erik/mobibot/social/SocialManager.kt b/bin/main/net/thauvin/erik/mobibot/social/SocialManager.kt deleted file mode 100644 index 91f2dd9..0000000 --- a/bin/main/net/thauvin/erik/mobibot/social/SocialManager.kt +++ /dev/null @@ -1,116 +0,0 @@ -/* - * SocialManager.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.social - -import net.thauvin.erik.mobibot.Addons -import net.thauvin.erik.mobibot.Constants -import net.thauvin.erik.mobibot.entries.EntriesUtils.toLinkLabel -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.util.* - -/** - * Social Manager. - */ -class SocialManager { - private val entries: MutableSet<Int> = HashSet() - private val logger: Logger = LoggerFactory.getLogger(SocialManager::class.java) - private val modules = ArrayList<SocialModule>() - private val timer = Timer(true) - - /** - * Adds social modules. - */ - fun add(addons: Addons, vararg modules: SocialModule) { - modules.forEach { - if (addons.add(it)) { - this.modules.add(it) - } - } - } - - /** - * Returns the number of entries. - */ - fun entriesCount(): Int = entries.size - - /** - * Sends a social notification (dm, etc.) - */ - fun notification(msg: String) { - modules.forEach { - it.notification(msg) - } - } - - /** - * Posts to social media. - */ - fun postEntry(index: Int) { - if (entries.contains(index)) { - modules.forEach { - it.postEntry(index) - } - entries.remove(index) - } - } - - /** - * Queues an entry for posting to social media. - */ - fun queueEntry(index: Int) { - if (modules.isNotEmpty()) { - entries.add(index) - if (logger.isDebugEnabled) { - logger.debug("Scheduling {} for posting on social media.", index.toLinkLabel()) - } - timer.schedule(SocialTimer(this, index), Constants.TIMER_DELAY * 60L * 1000L) - } - } - - /** - * Removes entries from queue. - */ - fun removeEntry(index: Int) { - entries.remove(index) - } - - /** - * Posts all entries on shutdown. - */ - fun shutdown() { - timer.cancel() - entries.forEach { - postEntry(it) - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/social/SocialModule.kt b/bin/main/net/thauvin/erik/mobibot/social/SocialModule.kt deleted file mode 100644 index b594670..0000000 --- a/bin/main/net/thauvin/erik/mobibot/social/SocialModule.kt +++ /dev/null @@ -1,96 +0,0 @@ -/* - * SocialModule.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.social - -import net.thauvin.erik.mobibot.commands.links.LinksManager -import net.thauvin.erik.mobibot.entries.EntriesUtils.toLinkLabel -import net.thauvin.erik.mobibot.entries.EntryLink -import net.thauvin.erik.mobibot.modules.AbstractModule -import net.thauvin.erik.mobibot.modules.ModuleException -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory - -abstract class SocialModule : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(SocialManager::class.java) - - abstract val handle: String? - abstract val isAutoPost: Boolean - - abstract fun formatEntry(entry: EntryLink): String - - /** - * Sends a DM. - */ - fun notification(msg: String) { - if (isEnabled && !handle.isNullOrBlank()) { - try { - post(message = msg, isDm = true) - if (logger.isDebugEnabled) logger.debug("Notified $handle on $name: $msg") - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn("Failed to notify $handle on $name: $msg", e) - } - } - } - - abstract fun post(message: String, isDm: Boolean): String - - /** - * Post entry to social media. - */ - fun postEntry(index: Int) { - if (isAutoPost && LinksManager.entries.links.size >= index) { - try { - if (logger.isDebugEnabled) { - logger.debug("Posting {} to $name.", index.toLinkLabel()) - } - post(message = formatEntry(LinksManager.entries.links[index]), isDm = false) - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn( - "Failed to post entry ${index.toLinkLabel()} on $name.", - e - ) - } - } - } - - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - try { - event.respond(post("$args (by ${event.user.nick} on $channel)", false)) - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) - e.message?.let { - event.respond(it) - } - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/social/SocialTimer.kt b/bin/main/net/thauvin/erik/mobibot/social/SocialTimer.kt deleted file mode 100644 index 3fd315e..0000000 --- a/bin/main/net/thauvin/erik/mobibot/social/SocialTimer.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * SocialTimer.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.social - -import java.util.* - -class SocialTimer(private var socialManager: SocialManager, private var index: Int) : TimerTask() { - override fun run() { - socialManager.postEntry(index) - } -} diff --git a/bin/test/current.xml b/bin/test/current.xml deleted file mode 100644 index 535a400..0000000 --- a/bin/test/current.xml +++ /dev/null @@ -1,67 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ current.xml - ~ - ~ Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - ~ - ~ Redistribution and use in source and binary forms, with or without - ~ modification, are permitted provided that the following conditions are met: - ~ - ~ Redistributions of source code must retain the above copyright notice, this - ~ list of conditions and the following disclaimer. - ~ - ~ Redistributions in binary form must reproduce the above copyright notice, - ~ this list of conditions and the following disclaimer in the documentation - ~ and/or other materials provided with the distribution. - ~ - ~ Neither the name of this project nor the names of its contributors may be - ~ used to endorse or promote products derived from this software without - ~ specific prior written permission. - ~ - ~ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - ~ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - ~ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - ~ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - ~ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - ~ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - ~ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - ~ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - ~ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - ~ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - --> - -<rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"> - <channel> - <title>#mobibot IRC Links - https://www.mobitopia.org/mobibot/logs - Links from irc.example.com on #mobibot - en - Sun, 31 Oct 2021 21:45:11 GMT - 2021-10-31T21:45:11Z - en - - Example 2 - https://www.example.com/2 - Posted by <b>Skynx</b> on <a href="irc://irc.libera.chat/#mobibot"><b>#mobibot</b></a> - tag2-1 - tag2-2 - Sun, 31 Oct 2021 21:45:11 GMT - https://www.foo.com - mobibot@irc.libera.chat (Skynx) - 2021-10-31T00:01:00Z - - - Example 1 - https://www.example.com/1 - Posted by <b>ErikT</b> on <a href="irc://irc.libera.chat/#mobibot"><b>#mobibot</b></a> - <br/><br/>ErikT: This is comment 1. <br/>Skynx: This is comment 2. - - tag1-1 - tag1-2 - Sun, 31 Oct 2021 21:43:15 GMT - https://www.example.com/ - mobibot@irc.libera.chat (ErikT) - 2021-10-31T00:00:00Z - - - diff --git a/bin/test/net/thauvin/erik/mobibot/AddonsTest.kt b/bin/test/net/thauvin/erik/mobibot/AddonsTest.kt deleted file mode 100644 index afb8ce6..0000000 --- a/bin/test/net/thauvin/erik/mobibot/AddonsTest.kt +++ /dev/null @@ -1,86 +0,0 @@ -/* - * AddonsTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot - -import assertk.assertThat -import assertk.assertions.containsExactly -import assertk.assertions.isEqualTo -import assertk.assertions.size -import net.thauvin.erik.mobibot.commands.ChannelFeed -import net.thauvin.erik.mobibot.commands.Cycle -import net.thauvin.erik.mobibot.commands.Die -import net.thauvin.erik.mobibot.commands.Ignore -import net.thauvin.erik.mobibot.commands.links.Comment -import net.thauvin.erik.mobibot.commands.links.View -import net.thauvin.erik.mobibot.modules.* -import kotlin.test.Test -import java.util.* - -class AddonsTest { - private val p = Properties().apply { - put("disabled-modules", "war,dice Lookup") - put("disabled-commands", "View | comment") - } - private val addons = Addons(p) - - @Test - fun addTest() { - // Modules - addons.add(Joke()) - addons.add(RockPaperScissors()) - addons.add(War()) - addons.add(Dice()) - addons.add(Lookup()) - assertThat(addons::modules).size().isEqualTo(2) - assertThat(addons.names.modules, "names.modules").containsExactly("Joke", "RockPaperScissors") - - // Commands - addons.add(View()) - addons.add(Comment()) - addons.add(Cycle()) - addons.add(Die()) // invisible - addons.add(ChannelFeed("channel")) // no properties, disabled - p[Ignore.IGNORE_PROP] = "nick" - addons.add(Ignore()) - assertThat(addons::commands).size().isEqualTo(3) - - assertThat(addons.names.ops, "names.ops").containsExactly("cycle") - - assertThat(addons.names.commands, "names.command").containsExactly( - "joke", - "rock", - "paper", - "scissors", - "ignore" - ) - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/ExceptionSanitizer.kt b/bin/test/net/thauvin/erik/mobibot/ExceptionSanitizer.kt deleted file mode 100644 index a3994ec..0000000 --- a/bin/test/net/thauvin/erik/mobibot/ExceptionSanitizer.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * ExceptionSanitizer.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot - -import net.thauvin.erik.mobibot.Utils.obfuscate -import net.thauvin.erik.mobibot.Utils.replaceEach -import net.thauvin.erik.mobibot.modules.ModuleException - -object ExceptionSanitizer { - /** - * Returns a sanitized exception to avoid displaying api keys, etc. in CI logs. - */ - fun ModuleException.sanitize(vararg sanitize: String): ModuleException { - val search = sanitize.filter { it.isNotBlank() }.toTypedArray() - if (search.isNotEmpty()) { - val obfuscate = search.map { it.obfuscate() }.toTypedArray() - with(this) { - if (!cause?.message.isNullOrBlank()) { - return ModuleException( - debugMessage, - cause?.javaClass?.name + ": " + cause?.message?.replaceEach(search, obfuscate), - this - ) - } else if (!message.isNullOrBlank()) { - return ModuleException(debugMessage, message?.replaceEach(search, obfuscate), this) - } - } - } - return this - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/FeedReaderTest.kt b/bin/test/net/thauvin/erik/mobibot/FeedReaderTest.kt deleted file mode 100644 index 6e5fa8f..0000000 --- a/bin/test/net/thauvin/erik/mobibot/FeedReaderTest.kt +++ /dev/null @@ -1,78 +0,0 @@ -/* - * FeedReaderTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot - -import assertk.all -import assertk.assertFailure -import assertk.assertThat -import assertk.assertions.* -import com.rometools.rome.io.FeedException -import net.thauvin.erik.mobibot.FeedReader.Companion.readFeed -import net.thauvin.erik.mobibot.msg.Message -import kotlin.test.Test -import java.io.IOException -import java.net.MalformedURLException -import java.net.UnknownHostException - -/** - * The `FeedReader Test` class. - */ -class FeedReaderTest { - @Test - fun readFeedTest() { - var messages = readFeed("https://feeds.thauvin.net/ethauvin") - assertThat(messages, "messages").all { - size().isEqualTo(10) - index(1).prop(Message::msg).contains("erik.thauvin.net") - } - - messages = readFeed("https://lorem-rss.herokuapp.com/feed?length=0") - assertThat(messages, "messages").index(0).prop(Message::msg).contains("nothing") - - messages = readFeed("https://lorem-rss.herokuapp.com/feed?length=84", 42) - assertThat(messages, "messages").size().isEqualTo(84) - messages.forEachIndexed { i, m -> - if (i % 2 == 0) { - assertThat(m, "messages($i)").prop(Message::msg).startsWith("Lorem ipsum") - } else { - assertThat(m, "messages($i)").prop(Message::msg).contains("http://example.com/test/") - } - } - - assertFailure { readFeed("blah") }.isInstanceOf(MalformedURLException::class.java) - - assertFailure { readFeed("https://www.example.com") }.isInstanceOf(FeedException::class.java) - - assertFailure { readFeed("https://www.thauvin.net/foo") }.isInstanceOf(IOException::class.java) - - assertFailure { readFeed("https://www.examplesfoo.com/") }.isInstanceOf(UnknownHostException::class.java) - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/LocalProperties.kt b/bin/test/net/thauvin/erik/mobibot/LocalProperties.kt deleted file mode 100644 index 1384a72..0000000 --- a/bin/test/net/thauvin/erik/mobibot/LocalProperties.kt +++ /dev/null @@ -1,85 +0,0 @@ -/* - * LocalProperties.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot - -import org.testng.annotations.BeforeSuite -import java.io.IOException -import java.net.InetAddress -import java.net.UnknownHostException -import java.nio.file.Files -import java.nio.file.Paths -import java.util.* - -/** - * Access to `local.properties`. - */ -open class LocalProperties { - @BeforeSuite(alwaysRun = true) - fun loadProperties() { - val localPath = Paths.get("local.properties") - if (Files.exists(localPath)) { - try { - Files.newInputStream(localPath).use { stream -> localProps.load(stream) } - } catch (ignore: IOException) { - // Do nothing - } - } - } - - companion object { - private val localProps = Properties() - - fun getHostName(): String { - val ciName = System.getenv("CI_NAME") - return ciName ?: try { - InetAddress.getLocalHost().hostName - } catch (ignore: UnknownHostException) { - "Unknown Host" - } - } - - fun getProperty(key: String): String { - return if (localProps.containsKey(key)) { - localProps.getProperty(key) - } else { - val env = System.getenv(keyToEnv(key)) - env?.let { - localProps.setProperty(key, env) - } - env - } - } - - private fun keyToEnv(key: String): String { - return key.replace('-', '_').uppercase() - } - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/PinboardTest.kt b/bin/test/net/thauvin/erik/mobibot/PinboardTest.kt deleted file mode 100644 index b527fc5..0000000 --- a/bin/test/net/thauvin/erik/mobibot/PinboardTest.kt +++ /dev/null @@ -1,81 +0,0 @@ -/* - * PinboardTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot - -import net.thauvin.erik.mobibot.Utils.encodeUrl -import net.thauvin.erik.mobibot.Utils.reader -import net.thauvin.erik.mobibot.entries.EntryLink -import org.testng.Assert.assertFalse -import org.testng.Assert.assertTrue -import kotlin.test.Test -import java.net.URL - -class PinboardTest : LocalProperties() { - private val pinboard = Pinboard() - - @Test - fun testPinboard() { - val apiToken = getProperty("pinboard-api-token") - val url = "https://www.example.com/${(1000..5000).random()}" - val ircServer = "irc.test.com" - val entry = EntryLink(url, "Test Example", "ErikT", "", "#mobitopia", listOf("test")) - - pinboard.setApiToken(apiToken) - - pinboard.addPin(ircServer, entry) - assertTrue(validatePin(apiToken, url = entry.link, entry.title, entry.nick, entry.channel), "addPin") - - entry.link = "https://www.example.com/${(5001..9999).random()}" - pinboard.updatePin(ircServer, url, entry) - assertTrue(validatePin(apiToken, url = entry.link, ircServer), "updatePin") - - entry.title = "Foo Title" - pinboard.updatePin(ircServer, entry.link, entry) - assertTrue(validatePin(apiToken, url = entry.link, entry.title), "updatePin(${entry.title}") - - pinboard.deletePin(entry) - assertFalse(validatePin(apiToken, url = entry.link), "deletePin") - } - - private fun validatePin(apiToken: String, url: String, vararg matches: String): Boolean { - val response = - URL("https://api.pinboard.in/v1/posts/get?auth_token=${apiToken}&tag=test&" + url.encodeUrl()).reader().body - - matches.forEach { - if (!response.contains(it)) { - return false - } - } - - return response.contains(url) - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/UtilsTest.kt b/bin/test/net/thauvin/erik/mobibot/UtilsTest.kt deleted file mode 100644 index 7b7ba8c..0000000 --- a/bin/test/net/thauvin/erik/mobibot/UtilsTest.kt +++ /dev/null @@ -1,278 +0,0 @@ -/* - * UtilsTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot - -import assertk.all -import assertk.assertThat -import assertk.assertions.isEqualTo -import assertk.assertions.length -import net.thauvin.erik.mobibot.Utils.appendIfMissing -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.Utils.capitalise -import net.thauvin.erik.mobibot.Utils.capitalizeWords -import net.thauvin.erik.mobibot.Utils.colorize -import net.thauvin.erik.mobibot.Utils.cyan -import net.thauvin.erik.mobibot.Utils.encodeUrl -import net.thauvin.erik.mobibot.Utils.getIntProperty -import net.thauvin.erik.mobibot.Utils.green -import net.thauvin.erik.mobibot.Utils.helpCmdSyntax -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.lastOrEmpty -import net.thauvin.erik.mobibot.Utils.obfuscate -import net.thauvin.erik.mobibot.Utils.plural -import net.thauvin.erik.mobibot.Utils.reader -import net.thauvin.erik.mobibot.Utils.red -import net.thauvin.erik.mobibot.Utils.replaceEach -import net.thauvin.erik.mobibot.Utils.reverseColor -import net.thauvin.erik.mobibot.Utils.toIntOrDefault -import net.thauvin.erik.mobibot.Utils.toIsoLocalDate -import net.thauvin.erik.mobibot.Utils.toUtcDateTime -import net.thauvin.erik.mobibot.Utils.today -import net.thauvin.erik.mobibot.Utils.underline -import net.thauvin.erik.mobibot.Utils.unescapeXml -import net.thauvin.erik.mobibot.msg.Message.Companion.DEFAULT_COLOR -import org.pircbotx.Colors -import org.testng.annotations.BeforeClass -import kotlin.test.Test -import java.io.File -import java.io.IOException -import java.net.URL -import java.time.LocalDateTime -import java.util.* - -/** - * The `Utils Test` class. - */ -class UtilsTest { - private val ascii = - " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" - private val cal = Calendar.getInstance() - private val localDateTime = LocalDateTime.of(1952, 2, 17, 12, 30, 0) - private val test = "This is a test." - - @BeforeClass - fun setUp() { - cal[1952, Calendar.FEBRUARY, 17, 12, 30] = 0 - } - - @Test - fun testAppendIfMissing() { - val dir = "dir" - val sep = '/' - val url = "https://erik.thauvin.net" - assertThat(dir.appendIfMissing(File.separatorChar), "appendIfMissing(dir)") - .isEqualTo(dir + File.separatorChar) - assertThat(url.appendIfMissing(sep), "appendIfMissing(url)").isEqualTo("$url$sep") - assertThat("$url$sep".appendIfMissing(sep), "appendIfMissing($url$sep)").isEqualTo("$url$sep") - } - - @Test - fun testBold() { - assertThat(1.bold(), "bold(1)").isEqualTo(Colors.BOLD + "1" + Colors.BOLD) - assertThat(2L.bold(), "bold(2L)").isEqualTo(Colors.BOLD + "2" + Colors.BOLD) - assertThat(ascii.bold(), "ascii.bold()").isEqualTo(Colors.BOLD + ascii + Colors.BOLD) - assertThat("test".bold(), "test.bold()").isEqualTo(Colors.BOLD + "test" + Colors.BOLD) - } - - - @Test - fun testCapitalise() { - assertThat("test".capitalise(), "capitalize(test)").isEqualTo("Test") - assertThat("Test".capitalise(), "capitalize(Test)").isEqualTo("Test") - assertThat(test.capitalise(), "capitalize($test)").isEqualTo(test) - assertThat("".capitalise(), "capitalize()").isEqualTo("") - } - - @Test - fun textCapitaliseWords() { - assertThat(test.capitalizeWords(), "captiatlizeWords(test)").isEqualTo("This Is A Test.") - assertThat("Already Capitalized".capitalizeWords(), "already capitalized") - .isEqualTo("Already Capitalized") - assertThat(" a test ".capitalizeWords(), "with spaces").isEqualTo(" A Test ") - } - - @Test - fun testColorize() { - assertThat(ascii.colorize(Colors.REVERSE), "reverse.colorize()").isEqualTo( - Colors.REVERSE + ascii + Colors.REVERSE - ) - assertThat(ascii.colorize(Colors.RED), "red.colorize()") - .isEqualTo(Colors.RED + ascii + Colors.NORMAL) - assertThat(ascii.colorize(Colors.BOLD), "colorized(bold)") - .isEqualTo(Colors.BOLD + ascii + Colors.BOLD) - assertThat(null.colorize(Colors.RED), "null.colorize()").isEqualTo("") - assertThat("".colorize(Colors.RED), "colorize()").isEqualTo("") - assertThat(ascii.colorize(DEFAULT_COLOR), "ascii.colorize()").isEqualTo(ascii) - assertThat(" ".colorize(Colors.NORMAL), "blank.colorize()") - .isEqualTo(Colors.NORMAL + " " + Colors.NORMAL) - } - - @Test - fun testCyan() { - assertThat(ascii.cyan()).isEqualTo(Colors.CYAN + ascii + Colors.NORMAL) - } - - @Test - fun testEncodeUrl() { - assertThat("Hello Günter".encodeUrl()).isEqualTo("Hello%20G%C3%BCnter") - } - - @Test - fun testGetIntProperty() { - val p = Properties() - p["one"] = "1" - p["two"] = "two" - assertThat(p.getIntProperty("one", 9), "getIntProperty(one)").isEqualTo(1) - assertThat(p.getIntProperty("two", 2), "getIntProperty(two)").isEqualTo(2) - assertThat(p.getIntProperty("foo", 3), "getIntProperty(foo)").isEqualTo(3) - } - - @Test - fun testGreen() { - assertThat(ascii.green()).isEqualTo(Colors.DARK_GREEN + ascii + Colors.NORMAL) - } - - @Test - fun testHelpCmdSyntax() { - val bot = "mobibot" - assertThat(helpCmdSyntax("%c $test %n $test", bot, false), "helpCmdSyntax(private)") - .isEqualTo("$bot: $test $bot $test") - assertThat(helpCmdSyntax("%c %n $test %c $test %n", bot, true), "helpCmdSyntax(public)") - .isEqualTo("/msg $bot $bot $test /msg $bot $test $bot") - } - - @Test - fun testHelpFormat() { - assertThat(helpFormat(test, isBold = true, isIndent = false), "helpFormat(bold)") - .isEqualTo("${Colors.BOLD}$test${Colors.BOLD}") - assertThat(helpFormat(test, isBold = false, isIndent = true), "helpFormat(indent)") - .isEqualTo(test.prependIndent()) - assertThat(helpFormat(test, isBold = true, isIndent = true), "helpFormat(bold,indent)") - .isEqualTo(test.colorize(Colors.BOLD).prependIndent()) - - } - - @Test - fun testIsoLocalDate() { - assertThat(cal.time.toIsoLocalDate(), "isoLocalDate(date)").isEqualTo("1952-02-17") - assertThat(localDateTime.toIsoLocalDate(), "isoLocalDate(localDate)").isEqualTo("1952-02-17") - } - - @Test - fun testLastOrEmpty() { - val two = listOf("1", "2") - assertThat(two.lastOrEmpty(), "lastOrEmpty(1,2)").isEqualTo("2") - val one = listOf("1") - assertThat(one.lastOrEmpty(), "lastOrEmpty(1)").isEqualTo("") - } - - @Test - fun testObfuscate() { - assertThat(ascii.obfuscate(), "obfuscate()").all { - length().isEqualTo(ascii.length) - isEqualTo(("x".repeat(ascii.length))) - } - assertThat(" ".obfuscate(), "obfuscate(blank)").isEqualTo(" ") - } - - @Test - fun testPlural() { - val week = "week" - val weeks = "weeks" - - for (i in -1..3) { - assertThat(week.plural(i.toLong()), "plural($i)").isEqualTo(if (i > 1) weeks else week) - } - } - - @Test - fun testReplaceEach() { - val search = arrayOf("one", "two", "three") - val replace = arrayOf("1", "2", "3") - assertThat(search.joinToString(",").replaceEach(search, replace), "replaceEach(1,2,3") - .isEqualTo(replace.joinToString(",")) - - assertThat(test.replaceEach(search, replace), "replaceEach(nothing)").isEqualTo(test) - - assertThat(test.replaceEach(arrayOf("t", "e"), arrayOf("", "E")), "replaceEach($test)") - .isEqualTo(test.replace("t", "").replace("e", "E")) - - assertThat(test.replaceEach(search, emptyArray()), "replaceEach(search, empty)") - .isEqualTo(test) - } - - @Test - fun testRed() { - assertThat(ascii.red()).isEqualTo(ascii.colorize(Colors.RED)) - } - - @Test - fun testReverseColor() { - assertThat(ascii.reverseColor()).isEqualTo(Colors.REVERSE + ascii + Colors.REVERSE) - } - - @Test - fun testToday() { - assertThat(today()).isEqualTo(LocalDateTime.now().toIsoLocalDate()) - } - - @Test - fun testToIntOrDefault() { - assertThat("10".toIntOrDefault(1), "toIntOrDefault(10, 1)").isEqualTo(10) - assertThat("a".toIntOrDefault(2), "toIntOrDefault(a, 2)").isEqualTo(2) - } - - @Test - fun testUnderline() { - assertThat(ascii.underline()).isEqualTo(ascii.colorize(Colors.UNDERLINE)) - } - - @Test - fun testUnescapeXml() { - assertThat("<a name="test & ''">".unescapeXml()).isEqualTo( - "" - ) - } - - @Test - @Throws(IOException::class) - fun testUrlReader() { - val reader = URL("https://postman-echo.com/status/200").reader() - assertThat(reader.body).isEqualTo("{\n \"status\": 200\n}") - assertThat(reader.responseCode).isEqualTo(200) - } - - @Test - fun testUtcDateTime() { - assertThat(cal.time.toUtcDateTime(), "utcDateTime(date)").isEqualTo("1952-02-17 12:30") - assertThat(localDateTime.toUtcDateTime(), "utcDateTime(localDate)").isEqualTo("1952-02-17 12:30") - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/commands/InfoTest.kt b/bin/test/net/thauvin/erik/mobibot/commands/InfoTest.kt deleted file mode 100644 index 99ba951..0000000 --- a/bin/test/net/thauvin/erik/mobibot/commands/InfoTest.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * InfoTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands - -import assertk.assertThat -import assertk.assertions.isEqualTo -import net.thauvin.erik.mobibot.commands.Info.Companion.toUptime -import kotlin.test.Test - -class InfoTest { - @Test - fun testToUptime() { - assertThat( - 547800300076L.toUptime(), - "upTime(full)" - ).isEqualTo("17 years 4 months 2 weeks 1 day 6 hours 45 minutes") - assertThat(24300000L.toUptime(), "upTime(hours minutes)").isEqualTo("6 hours 45 minutes") - assertThat(110700000L.toUptime(), "upTime(days hours minutes)").isEqualTo("1 day 6 hours 45 minutes") - assertThat( - 1320300000L.toUptime(), - "upTime(weeks days hours minutes)" - ).isEqualTo("2 weeks 1 day 6 hours 45 minutes") - assertThat(2700000L.toUptime(), "upTime(45 minutes)").isEqualTo("45 minutes") - assertThat(60000L.toUptime(), "upTime(1 minute)").isEqualTo("1 minute") - assertThat(59000L.toUptime(), "upTime(59 seconds)").isEqualTo("59 seconds") - assertThat(0L.toUptime(), "upTime(0 second)").isEqualTo("0 second") - - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/commands/RecapTest.kt b/bin/test/net/thauvin/erik/mobibot/commands/RecapTest.kt deleted file mode 100644 index b6fbbff..0000000 --- a/bin/test/net/thauvin/erik/mobibot/commands/RecapTest.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * RecapTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands - -import assertk.all -import assertk.assertThat -import assertk.assertions.isEqualTo -import assertk.assertions.matches -import assertk.assertions.prop -import assertk.assertions.size -import kotlin.test.Test - -class RecapTest { - @Test - fun storeRecapTest() { - for (i in 1..20) { - Recap.storeRecap("sender$i", "test $i", false) - } - assertThat(Recap.recaps, "Recap.recaps").all { - size().isEqualTo(Recap.MAX_RECAPS) - prop(MutableList::first) - .matches("[1-2]\\d{3}-[01]\\d-[0-3]\\d [0-2]\\d:[0-6]\\d - sender11: test 11".toRegex()) - prop(MutableList::last) - .matches("[1-2]\\d{3}-[01]\\d-[0-3]\\d [0-2]\\d:[0-6]\\d - sender20: test 20".toRegex()) - } - - Recap.storeRecap("sender", "test action", true) - assertThat(Recap.recaps.last()) - .matches("[1-2]\\d{3}-[01]\\d-[0-3]\\d [0-2]\\d:[0-6]\\d - sender test action".toRegex()) - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt b/bin/test/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt deleted file mode 100644 index fa2bb70..0000000 --- a/bin/test/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt +++ /dev/null @@ -1,77 +0,0 @@ -/* - * LinksManagerTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands.links - -import assertk.all -import assertk.assertThat -import assertk.assertions.contains -import assertk.assertions.isEqualTo -import assertk.assertions.isTrue -import assertk.assertions.size -import net.thauvin.erik.mobibot.Constants -import kotlin.test.Test - -class LinksManagerTest { - private val linksManager = LinksManager() - - @Test - fun fetchTitle() { - assertThat(linksManager.fetchTitle("https://erik.thauvin.net/"), "fetchTitle(Erik)").contains("Erik's Weblog") - assertThat( - linksManager.fetchTitle("https://www.google.com/foo"), - "fetchTitle(Foo)" - ).isEqualTo(Constants.NO_TITLE) - } - - @Test - fun testMatches() { - assertThat(linksManager.matches("https://www.example.com/"), "matches(url)").isTrue() - assertThat(linksManager.matches("HTTP://erik.thauvin.net/blog/ Erik's Weblog"), "matches(HTTP)").isTrue() - } - - @Test - fun matchTagKeywordsTest() { - linksManager.setProperty(LinksManager.KEYWORDS_PROP, "key1 key2,key3") - val tags = mutableListOf() - - linksManager.matchTagKeywords("Test title with key2", tags) - assertThat(tags, "tags").contains("key2") - tags.clear() - - linksManager.matchTagKeywords("Test key3 title with key1", tags) - assertThat(tags, "tags(key1, key3)").all { - contains("key1") - contains("key3") - size().isEqualTo(2) - } - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/commands/links/ViewTest.kt b/bin/test/net/thauvin/erik/mobibot/commands/links/ViewTest.kt deleted file mode 100644 index e315891..0000000 --- a/bin/test/net/thauvin/erik/mobibot/commands/links/ViewTest.kt +++ /dev/null @@ -1,111 +0,0 @@ -/* - * ViewTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands.links - -import assertk.all -import assertk.assertThat -import assertk.assertions.isEqualTo -import assertk.assertions.prop -import net.thauvin.erik.mobibot.entries.EntryLink -import kotlin.test.Test - -class ViewTest { - @Test - fun testParseArgs() { - val view = View() - - for (i in 1..10) { - LinksManager.entries.links.add( - EntryLink( - "https://www.example.com/$i", - "Example $i", - "nick$i", - "login$i", - "#channel", - emptyList() - ) - ) - } - - assertThat(view.parseArgs("1"), "parseArgs(1)").all { - prop(Pair::first).isEqualTo(0) - prop(Pair::second).isEqualTo("") - } - - assertThat(view.parseArgs("2 foo"), "parseArgs(2, foo)").all { - prop(Pair::first).isEqualTo(1) - prop(Pair::second).isEqualTo("foo") - } - - assertThat(view.parseArgs("3 FOO"), "parseArgs(3, FOO)").all { - prop(Pair::first).isEqualTo(2) - prop(Pair::second).isEqualTo("foo") - } - - assertThat(view.parseArgs(" 4 foo bar "), "parseArgs( 4 foo bar )").all { - prop(Pair::first).isEqualTo(3) - prop(Pair::second).isEqualTo("foo bar") - } - - assertThat(view.parseArgs("foo bar"), "parseArgs(foo bar)").all { - prop(Pair::first).isEqualTo(0) - prop(Pair::second).isEqualTo("foo bar") - } - - assertThat(view.parseArgs("${Int.MAX_VALUE}1"), "parseArgs(overflow)").all { - prop(Pair::first).isEqualTo(0) - prop(Pair::second).isEqualTo("${Int.MAX_VALUE}1") - } - - assertThat(view.parseArgs("1a"), "parseArgs(1a)").all { - prop(Pair::first).isEqualTo(0) - prop(Pair::second).isEqualTo("1a") - } - - assertThat(view.parseArgs("20"), "parseArgs(20)").all { - prop(Pair::first).isEqualTo(0) - prop(Pair::second).isEqualTo("") - } - - assertThat(view.parseArgs(""), "parseArgs()").all { - prop(Pair::first).isEqualTo(LinksManager.entries.links.size - View.MAX_ENTRIES) - prop(Pair::second).isEqualTo("") - } - - LinksManager.entries.links.clear() - - assertThat(view.parseArgs("4"), "parseArgs(4)").all { - prop(Pair::first).isEqualTo(0) - prop(Pair::second).isEqualTo("") - } - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt b/bin/test/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt deleted file mode 100644 index 37b884b..0000000 --- a/bin/test/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt +++ /dev/null @@ -1,85 +0,0 @@ -/* - * SeenTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands.seen - -import assertk.all -import assertk.assertThat -import assertk.assertions.* -import org.testng.annotations.AfterClass -import org.testng.annotations.BeforeClass -import kotlin.test.Test -import kotlin.io.path.deleteIfExists -import kotlin.io.path.fileSize - -class SeenTest { - private val tmpFile = kotlin.io.path.createTempFile(suffix = ".ser") - private val seen = Seen(tmpFile.toAbsolutePath().toString()) - private val nick = "ErikT" - - @BeforeClass - fun saveTest() { - seen.add("ErikT") - assertThat(tmpFile.fileSize(), "tmpFile.size").isGreaterThan(0) - } - - @AfterClass(alwaysRun = true) - fun afterClass() { - tmpFile.deleteIfExists() - } - - @Test(priority = 1, groups = ["commands"]) - fun loadTest() { - seen.clear() - assertThat(seen::seenNicks).isEmpty() - seen.load() - assertThat(seen::seenNicks).key(nick).isNotNull() - } - - @Test - fun addTest() { - val last = seen.seenNicks[nick]?.lastSeen - seen.add(nick.lowercase()) - assertThat(seen).all { - prop(Seen::seenNicks).size().isEqualTo(1) - prop(Seen::seenNicks).key(nick).isNotNull().prop(SeenNick::lastSeen).isNotEqualTo(last) - prop(Seen::seenNicks).key(nick).isNotNull().prop(SeenNick::nick).isNotNull().isEqualTo(nick.lowercase()) - } - } - - @Test(priority = 10, groups = ["commands"]) - fun clearTest() { - seen.clear() - seen.save() - seen.load() - assertThat(seen::seenNicks).size().isEqualTo(0) - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt b/bin/test/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt deleted file mode 100644 index cc09237..0000000 --- a/bin/test/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt +++ /dev/null @@ -1,72 +0,0 @@ -/* - * TellMessageTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.commands.tell - -import assertk.all -import assertk.assertThat -import assertk.assertions.isEqualTo -import assertk.assertions.isFalse -import assertk.assertions.isTrue -import assertk.assertions.prop -import kotlin.test.Test -import java.time.Duration -import java.time.LocalDateTime -import java.time.temporal.Temporal - -/** - * The `TellMessageTest` class. - */ -class TellMessageTest { - private fun isValidDate(date: Temporal): Boolean { - return Duration.between(date, LocalDateTime.now()).toMinutes() < 1 - } - - @Test - fun testTellMessage() { - val message = "Test message." - val recipient = "recipient" - val sender = "sender" - val tellMessage = TellMessage(sender, recipient, message) - assertThat(tellMessage).all { - prop(TellMessage::sender).isEqualTo(sender) - prop(TellMessage::recipient).isEqualTo(recipient) - prop(TellMessage::message).isEqualTo(message) - } - assertThat(isValidDate(tellMessage.queued), "isValidDate()").isTrue() - assertThat(tellMessage.isMatch(sender), "isMatch(sender)").isTrue() - assertThat(tellMessage.isMatch(recipient), "isMatch(recipient)").isTrue() - assertThat(tellMessage.isMatch("foo"), "isMatch(foo)").isFalse() - tellMessage.isReceived = false - assertThat(tellMessage.receptionDate, "receptionDate").isEqualTo(LocalDateTime.MIN) - tellMessage.isReceived = true - assertThat(isValidDate(tellMessage.receptionDate), "isValidDate(creationDate)").isTrue() - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt b/bin/test/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt deleted file mode 100644 index 5acba78..0000000 --- a/bin/test/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt +++ /dev/null @@ -1,87 +0,0 @@ -/* - * TellMessagesMgrTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands.tell - -import assertk.all -import assertk.assertThat -import assertk.assertions.* -import org.testng.annotations.AfterClass -import org.testng.annotations.BeforeClass -import kotlin.test.Test -import java.time.LocalDateTime -import kotlin.io.path.createTempFile -import kotlin.io.path.deleteIfExists -import kotlin.io.path.fileSize - -class TellMessagesMgrTest { - private val testFile = createTempFile(suffix = ".ser") - private val maxDays = 10L - private val testMessages = mutableListOf().apply { - for (i in 0..5) { - this.add(i, TellMessage("sender$i", "recipient$i", "message $i")) - } - } - - @BeforeClass - fun saveTest() { - TellManager.save(testFile.toAbsolutePath().toString(), testMessages) - assertThat(testFile.fileSize()).isGreaterThan(0) - } - - @AfterClass - fun afterClass() { - testFile.deleteIfExists() - } - - @Test - fun cleanTest() { - testMessages.add(TellMessage("sender", "recipient", "message").apply { - queued = LocalDateTime.now().minusDays(maxDays) - }) - val size = testMessages.size - assertThat(TellManager.clean(testMessages, maxDays + 2), "clean(maxDays=${maxDays + 2})").isFalse() - assertThat(TellManager.clean(testMessages, maxDays), "clean(maxDays=$maxDays)").isTrue() - assertThat(testMessages, "testMessages").size().isEqualTo(size - 1) - } - - @Test - fun loadTest() { - val messages = TellManager.load(testFile.toAbsolutePath().toString()) - for (i in messages.indices) { - assertThat(messages).index(i).all { - prop(TellMessage::sender).isEqualTo(testMessages[i].sender) - prop(TellMessage::recipient).isEqualTo(testMessages[i].recipient) - prop(TellMessage::message).isEqualTo(testMessages[i].message) - } - } - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt b/bin/test/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt deleted file mode 100644 index 0ad26b5..0000000 --- a/bin/test/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt +++ /dev/null @@ -1,91 +0,0 @@ -/* - * EntriesUtilsTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.entries - -import assertk.assertThat -import assertk.assertions.contains -import assertk.assertions.isEqualTo -import net.thauvin.erik.mobibot.Constants -import net.thauvin.erik.mobibot.entries.EntriesUtils.printComment -import net.thauvin.erik.mobibot.entries.EntriesUtils.printLink -import net.thauvin.erik.mobibot.entries.EntriesUtils.printTags -import net.thauvin.erik.mobibot.entries.EntriesUtils.toLinkLabel -import kotlin.test.Test - -class EntriesUtilsTest { - private val comment = EntryComment("comment", "nick") - private val links = buildList { - for (i in 0..5) { - add( - EntryLink( - "https://www.mobitopia.org/$i", - "Mobitopia$i", - "Skynx$i", - "JimH$i", - "#mobitopia$i", - listOf("tag1", "tag2", "tag3", "TAG4", "Tag5") - ) - ) - } - } - - @Test - fun printCommentTest() { - assertThat(printComment(0, 0, comment)).isEqualTo("${Constants.LINK_CMD}1.1: [nick] comment") - } - - @Test - fun printLinkTest() { - for (i in links.indices) { - assertThat( - printLink(i - 1, links[i]), "link $i" - ).isEqualTo("L$i: [Skynx$i] \u0002Mobitopia$i\u0002 ( \u000303https://www.mobitopia.org/$i\u000F )") - } - - assertThat(links.first().addComment(comment), "addComment()").isEqualTo(0) - assertThat(printLink(0, links.first(), isView = true), "printLink(isView=true)").contains("[+1]") - } - - @Test - fun printTagsTest() { - for (i in links.indices) { - assertThat( - printTags(i - 1, links[i]), "tag $i" - ).isEqualTo("L${i}T: tag1, tag2, tag3, tag4, tag5") - } - } - - @Test - fun toLinkLabelTest() { - assertThat(1.toLinkLabel()).isEqualTo("${Constants.LINK_CMD}2") - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt b/bin/test/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt deleted file mode 100644 index f421099..0000000 --- a/bin/test/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt +++ /dev/null @@ -1,133 +0,0 @@ -/* - * EntryLinkTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.entries - -import assertk.all -import assertk.assertThat -import assertk.assertions.* -import com.rometools.rome.feed.synd.SyndCategory -import com.rometools.rome.feed.synd.SyndCategoryImpl -import kotlin.test.Test -import java.security.SecureRandom -import java.util.* - -/** - * The `EntryUtilsTest` class. - * - * @author [Erik C. Thauvin](https://erik.thauvin.net/) - * @created 2019-04-19 - * @since 1.0 - */ -class EntryLinkTest { - private val entryLink = EntryLink( - "https://www.mobitopia.org/", "Mobitopia", "Skynx", "JimH", "#mobitopia", - listOf("tag1", "tag2", "tag3", "TAG4", "Tag5") - ) - - @Test - fun testAddDeleteComment() { - var i = 0 - while (i < 5) { - entryLink.addComment("c$i", "u$i") - i++ - } - assertThat(entryLink.comments, "comments").size().isEqualTo(i) - i = 0 - for (comment in entryLink.comments) { - assertThat(comment).all { - prop(EntryComment::comment).isEqualTo("c$i") - prop(EntryComment::nick).isEqualTo("u$i") - } - i++ - } - - val r = SecureRandom() - while (entryLink.comments.size > 0) { - entryLink.deleteComment(r.nextInt(entryLink.comments.size)) - } - assertThat(entryLink.comments, "hasComments()").isEmpty() - entryLink.addComment("nothing", "nobody") - entryLink.setComment(0, "something", "somebody") - val comment = entryLink.getComment(0) - assertThat(comment, "comment[first]").all { - prop(EntryComment::nick).isEqualTo("somebody") - prop(EntryComment::comment).isEqualTo("something") - } - assertThat(entryLink.deleteComment(comment), "deleteComment").isTrue() - assertThat(entryLink.deleteComment(comment), "comment is already deleted").isFalse() - } - - @Test - fun testConstructor() { - val tags = listOf(SyndCategoryImpl().apply { name = "tag1" }, SyndCategoryImpl().apply { name = "tag2" }) - val link = EntryLink("link", "title", "nick", "channel", Date(), tags) - assertThat(link, "link").all { - prop(EntryLink::tags).size().isEqualTo(tags.size) - prop(EntryLink::tags).index(0).prop(SyndCategory::getName).isEqualTo("tag1") - } - } - - @Test - fun testMatches() { - assertThat(entryLink.matches("mobitopia"), "matches(mobitopia)").isTrue() - assertThat(entryLink.matches("skynx"), "match(nick)").isTrue() - assertThat(entryLink.matches("www.mobitopia.org"), "matches(url)").isTrue() - assertThat(entryLink.matches("foo"), "matches(foo)").isFalse() - assertThat(entryLink.matches(""), "matches(empty)").isFalse() - assertThat(entryLink.matches(null), "matches(null)").isFalse() - } - - - @Test - fun testTags() { - val tags: List = entryLink.tags - for ((i, tag) in tags.withIndex()) { - assertThat(tag.name, "tag.name($i)").isEqualTo("tag${i + 1}") - } - assertThat(entryLink::tags).size().isEqualTo(5) - entryLink.setTags("-tag5, tag4") - entryLink.setTags("+mobitopia") - entryLink.setTags("-mobitopia") - assertThat( - entryLink.formatTags(","), - "formatTags(',')" - ).isEqualTo("tag1,tag2,tag3,tag4,mobitopia") - entryLink.setTags("-tag4 tag5") - assertThat( - entryLink.formatTags(" ", ","), "formatTag(' ',',')" - ).isEqualTo(",tag1 tag2 tag3 mobitopia tag5") - val size = entryLink.tags.size - entryLink.setTags("") - assertThat(entryLink.tags, "setTags('')").size().isEqualTo(size) - entryLink.setTags(" ") - assertThat(entryLink.tags, "setTags(' ')").size().isEqualTo(size) - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt b/bin/test/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt deleted file mode 100644 index 1611009..0000000 --- a/bin/test/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt +++ /dev/null @@ -1,115 +0,0 @@ -/* - * FeedMgrTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.entries - -import assertk.all -import assertk.assertThat -import assertk.assertions.* -import net.thauvin.erik.mobibot.Utils.today -import org.testng.annotations.BeforeSuite -import kotlin.test.Test -import java.nio.file.Paths -import java.util.* -import kotlin.io.path.deleteIfExists -import kotlin.io.path.fileSize -import kotlin.io.path.name - -class FeedMgrTest { - private val entries = Entries() - private val channel = "mobibot" - - @BeforeSuite(alwaysRun = true) - fun beforeSuite() { - entries.logsDir = "src/test/resources/" - entries.ircServer = "irc.example.com" - entries.channel = channel - entries.backlogs = "https://www.mobitopia.org/mobibot/logs" - } - - @Test - fun testFeedMgr() { - // Load the feed - assertThat(FeedsManager.loadFeed(entries), "loadFeed()").isEqualTo("2021-10-31") - - assertThat(entries.links, "entries.links").size().isEqualTo(2) - entries.links.forEachIndexed { i, entryLink -> - assertThat(entryLink, "entryLink[${i + 1}]").all { - prop(EntryLink::title).isEqualTo("Example ${i + 1}") - prop(EntryLink::link).isEqualTo("https://www.example.com/${i + 1}") - prop(EntryLink::channel).isEqualTo(channel) - } - entryLink.tags.forEachIndexed { y, tag -> - assertThat(tag.name, "tag${i + 1}-${y + 1}").isEqualTo("tag${i + 1}-${y + 1}") - } - } - - with(entries.links.first()) { - assertThat(nick, "nick[first]").isEqualTo("ErikT") - assertThat(date, "date[first]").isEqualTo(Date(1635638400000L)) - assertThat(comments.first(), "comments[first]").all { - prop(EntryComment::comment).endsWith("comment 1.") - prop(EntryComment::nick).isEqualTo("ErikT") - } - assertThat(comments.last(), "comments[last]").all { - prop(EntryComment::comment).endsWith("comment 2.") - prop(EntryComment::nick).isEqualTo("Skynx") - } - } - - assertThat(entries.links, "links").index(1).all { - prop(EntryLink::nick).isEqualTo("Skynx") - prop(EntryLink::date).isEqualTo(Date(1635638460000L)) - } - - val currentFile = Paths.get("${entries.logsDir}test.xml") - val backlogFile = Paths.get("${entries.logsDir}${today()}.xml") - - // Save the feed - FeedsManager.saveFeed(entries, currentFile.name) - - assertThat(currentFile, "currentFile").exists() - assertThat(backlogFile, "backlogFile").exists() - - assertThat(currentFile.fileSize(), "currentFile == backlogFile").isEqualTo(backlogFile.fileSize()) - - // Load the test feed - entries.links.clear() - FeedsManager.loadFeed(entries, currentFile.name) - - entries.links.forEachIndexed { i, entryLink -> - assertThat(entryLink.title, "entryLink.title[${i + 1}]").isEqualTo("Example ${i + 1}") - } - - assertThat(currentFile.deleteIfExists(), "currentFile.deleteIfExists()").isTrue() - assertThat(backlogFile.deleteIfExists(), "backlogFile.deleteIfExists()").isTrue() - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/CalcTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/CalcTest.kt deleted file mode 100644 index 3bd4c0f..0000000 --- a/bin/test/net/thauvin/erik/mobibot/modules/CalcTest.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * CalcTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import assertk.assertFailure -import assertk.assertThat -import assertk.assertions.isEqualTo -import assertk.assertions.isInstanceOf -import net.objecthunter.exp4j.tokenizer.UnknownFunctionOrVariableException -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.modules.Calc.Companion.calculate -import kotlin.test.Test - -/** - * The `CalcTest` class. - */ -class CalcTest { - @Test - fun testCalculate() { - assertThat(calculate("1 + 1"), "calculate(1+1)").isEqualTo("1+1 = ${2.bold()}") - assertThat(calculate("1 -3"), "calculate(1-3)").isEqualTo("1-3 = ${(-2).bold()}") - assertThat(calculate("pi+π+e+φ"), "calculate(pi+π+e+φ)").isEqualTo("pi+π+e+φ = ${"10.62".bold()}") - assertFailure { calculate("one + one") }.isInstanceOf(UnknownFunctionOrVariableException::class.java) - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/ChatGptTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/ChatGptTest.kt deleted file mode 100644 index 085f228..0000000 --- a/bin/test/net/thauvin/erik/mobibot/modules/ChatGptTest.kt +++ /dev/null @@ -1,62 +0,0 @@ -/* - * ChatGptTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import assertk.assertFailure -import assertk.assertThat -import assertk.assertions.contains -import assertk.assertions.hasNoCause -import assertk.assertions.isInstanceOf -import net.thauvin.erik.mobibot.LocalProperties -import kotlin.test.Test - -class ChatGptTest : LocalProperties() { - @Test - fun testApiKey() { - assertFailure { ChatGpt.chat("1 gallon to liter", "", 0) } - .isInstanceOf(ModuleException::class.java) - .hasNoCause() - } - - @Test(groups = ["modules", "no-ci"]) - fun testChat() { - val apiKey = getProperty(ChatGpt.API_KEY_PROP) - assertThat( - ChatGpt.chat("how do I make an HTTP request in Javascript?", apiKey, 100) - ).contains("XMLHttpRequest") - assertThat( - ChatGpt.chat("how do I encode a URL in java?", apiKey, 60) - ).contains("URLEncoder") - - assertFailure { ChatGpt.chat("1 liter to gallon", apiKey, 0) } - .isInstanceOf(ModuleException::class.java) - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt deleted file mode 100644 index d0ecbc9..0000000 --- a/bin/test/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt +++ /dev/null @@ -1,78 +0,0 @@ -/* - * CryptoPricesTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import assertk.all -import assertk.assertThat -import assertk.assertions.isEqualTo -import assertk.assertions.isGreaterThan -import assertk.assertions.prop -import net.thauvin.erik.crypto.CryptoPrice -import net.thauvin.erik.mobibot.modules.CryptoPrices.Companion.currentPrice -import net.thauvin.erik.mobibot.modules.CryptoPrices.Companion.getCurrencyName -import net.thauvin.erik.mobibot.modules.CryptoPrices.Companion.loadCurrencies -import org.testng.annotations.BeforeClass -import kotlin.test.Test - -/** - * The `CryptoPricesTest` class. - */ -class CryptoPricesTest { - @BeforeClass - @Throws(ModuleException::class) - fun before() { - loadCurrencies() - } - - @Test - @Throws(ModuleException::class) - fun testMarketPrice() { - var price = currentPrice(listOf("BTC")) - assertThat(price, "currentPrice(BTC)").all { - prop(CryptoPrice::base).isEqualTo("BTC") - prop(CryptoPrice::currency).isEqualTo("USD") - prop(CryptoPrice::amount).transform { it.signum() }.isGreaterThan(0) - } - - price = currentPrice(listOf("ETH", "EUR")) - assertThat(price, "currentPrice(ETH, EUR)").all { - prop(CryptoPrice::base).isEqualTo("ETH") - prop(CryptoPrice::currency).isEqualTo("EUR") - prop(CryptoPrice::amount).transform { it.signum() }.isGreaterThan(0) - } - } - - @Test - fun testGetCurrencyName() { - assertThat(getCurrencyName("USD"), "USD").isEqualTo("United States Dollar") - assertThat(getCurrencyName("EUR"), "EUR").isEqualTo("Euro") - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt deleted file mode 100644 index 8d8c997..0000000 --- a/bin/test/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt +++ /dev/null @@ -1,85 +0,0 @@ -/* - * CurrencyConverterTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import assertk.all -import assertk.assertThat -import assertk.assertions.contains -import assertk.assertions.isInstanceOf -import assertk.assertions.matches -import assertk.assertions.prop -import net.thauvin.erik.mobibot.LocalProperties -import net.thauvin.erik.mobibot.modules.CurrencyConverter.Companion.convertCurrency -import net.thauvin.erik.mobibot.modules.CurrencyConverter.Companion.loadSymbols -import net.thauvin.erik.mobibot.msg.ErrorMessage -import net.thauvin.erik.mobibot.msg.Message -import net.thauvin.erik.mobibot.msg.PublicMessage -import org.testng.annotations.BeforeClass -import kotlin.test.Test - - -/** - * The `CurrencyConvertTest` class. - */ -class CurrencyConverterTest : LocalProperties() { - - @BeforeClass - @Throws(ModuleException::class) - fun before() { - val apiKey = getProperty(CurrencyConverter.API_KEY_PROP) - loadSymbols(apiKey) - } - - @Test - fun testConvertCurrency() { - val apiKey = getProperty(CurrencyConverter.API_KEY_PROP) - assertThat( - convertCurrency(apiKey, "100 USD to EUR").msg, - "convertCurrency(100 USD to EUR)" - ).matches("100 United States Dollar = \\d{2,3}\\.\\d{2,3} Euro".toRegex()) - assertThat( - convertCurrency(apiKey, "1 USD to GBP").msg, - "convertCurrency(1 USD to BGP)" - ).matches("1 United States Dollar = 0\\.\\d{2,3} Pound Sterling".toRegex()) - assertThat( - convertCurrency(apiKey, "100,000.00 CAD to USD").msg, - "convertCurrency(100,000.00 GBP to USD)" - ).matches("100,000.00 Canadian Dollar = \\d+\\.\\d{2,3} United States Dollar".toRegex()) - assertThat(convertCurrency(apiKey, "100 USD to USD"), "convertCurrency(100 USD to USD)").all { - prop(Message::msg).contains("You're kidding, right?") - isInstanceOf(PublicMessage::class.java) - } - assertThat(convertCurrency(apiKey, "100 USD"), "convertCurrency(100 USD)").all { - prop(Message::msg).contains("Invalid query.") - isInstanceOf(ErrorMessage::class.java) - } - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/DiceTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/DiceTest.kt deleted file mode 100644 index 8bafede..0000000 --- a/bin/test/net/thauvin/erik/mobibot/modules/DiceTest.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * DiceTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.modules - - -import assertk.assertThat -import assertk.assertions.isEqualTo -import assertk.assertions.matches -import kotlin.test.Test - -class DiceTest { - @Test - fun testRoll() { - assertThat(Dice.roll(1, 1), "roll(1d1)").isEqualTo("\u00021\u0002") - assertThat(Dice.roll(2, 1), "roll(2d1)") - .isEqualTo("\u00021\u0002 + \u00021\u0002 = \u00022\u0002") - assertThat(Dice.roll(5, 1), "roll(5d1)") - .isEqualTo("\u00021\u0002 + \u00021\u0002 + \u00021\u0002 + \u00021\u0002 + \u00021\u0002 = \u00025\u0002") - assertThat(Dice.roll(2, 6), "roll(2d6)") - .matches("\u0002[1-6]\u0002 \\+ \u0002[1-6]\u0002 = \u0002[1-9][0-2]?\u0002".toRegex()) - assertThat(Dice.roll(3, 7), "roll(3d7)") - .matches("\u0002[1-7]\u0002 \\+ \u0002[1-7]\u0002 \\+ \u0002[1-7]\u0002 = \u0002\\d{1,2}\u0002".toRegex()) - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt deleted file mode 100644 index 85c990c..0000000 --- a/bin/test/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt +++ /dev/null @@ -1,95 +0,0 @@ -/* - * GoogleSearchTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import assertk.all -import assertk.assertFailure -import assertk.assertThat -import assertk.assertions.* -import net.thauvin.erik.mobibot.ExceptionSanitizer.sanitize -import net.thauvin.erik.mobibot.LocalProperties -import net.thauvin.erik.mobibot.modules.GoogleSearch.Companion.searchGoogle -import net.thauvin.erik.mobibot.msg.ErrorMessage -import net.thauvin.erik.mobibot.msg.Message -import kotlin.test.Test - -/** - * The `GoogleSearchTest` class. - */ -class GoogleSearchTest : LocalProperties() { - @Test - fun testAPIKeys() { - assertThat( - searchGoogle("", "apikey", "cssKey").first(), - "searchGoogle(empty)" - ).isInstanceOf(ErrorMessage::class.java) - - assertFailure { searchGoogle("test", "", "apiKey") } - .isInstanceOf(ModuleException::class.java).hasNoCause() - - assertFailure { searchGoogle("test", "apiKey", "") } - .isInstanceOf(ModuleException::class.java).hasNoCause() - - assertFailure { searchGoogle("test", "apiKey", "cssKey") } - .isInstanceOf(ModuleException::class.java) - .hasMessage("API key not valid. Please pass a valid API key.") - } - - @Test\n@DisableOnCi - @Throws(ModuleException::class) - fun testSearchGoogle() { - val apiKey = getProperty(GoogleSearch.API_KEY_PROP) - val cseKey = getProperty(GoogleSearch.CSE_KEY_PROP) - - try { - var query = "mobibot" - var messages = searchGoogle(query, apiKey, cseKey) - assertThat(messages, "searchGoogle($query)").all { - isNotEmpty() - index(0).prop(Message::msg).contains(query, true) - } - - query = "adadflkjl" - messages = searchGoogle(query, apiKey, cseKey) - assertThat(messages, "searchGoogle($query)").index(0).all { - isInstanceOf(ErrorMessage::class.java) - prop(Message::msg).isEqualTo("No results found.") - } - } catch (e: ModuleException) { - // Avoid displaying api keys in CI logs - if ("true" == System.getenv("CI")) { - throw e.sanitize(apiKey, cseKey) - } else { - throw e - } - } - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/JokeTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/JokeTest.kt deleted file mode 100644 index 0af8e75..0000000 --- a/bin/test/net/thauvin/erik/mobibot/modules/JokeTest.kt +++ /dev/null @@ -1,57 +0,0 @@ -/* - * JokeTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import assertk.all -import assertk.assertThat -import assertk.assertions.* -import net.thauvin.erik.mobibot.modules.Joke.Companion.randomJoke -import net.thauvin.erik.mobibot.msg.Message -import net.thauvin.erik.mobibot.msg.PublicMessage -import kotlin.test.Test - -/** - * The `JokeTest` class. - */ -class JokeTest { - @Test - @Throws(ModuleException::class) - fun testRandomJoke() { - val joke = randomJoke() - assertThat(joke, "randomJoke()").all { - size().isGreaterThan(0) - each { - it.isInstanceOf(PublicMessage::class.java) - it.prop(Message::msg).doesNotContain("\n") - } - } - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/LookupTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/LookupTest.kt deleted file mode 100644 index a3fc226..0000000 --- a/bin/test/net/thauvin/erik/mobibot/modules/LookupTest.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * LookupTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import assertk.assertThat -import assertk.assertions.any -import assertk.assertions.contains -import net.thauvin.erik.mobibot.modules.Lookup.Companion.nslookup -import net.thauvin.erik.mobibot.modules.Lookup.Companion.whois -import kotlin.test.Test - -/** - * The `Lookup Test` class. - */ -class LookupTest { - @Test - @Throws(Exception::class) - fun testLookup() { - var result = nslookup("apple.com") - assertThat(result, "lookup(apple.com)").contains("17.253.144.10") - - result = nslookup("204.122.16.136") - assertThat(result, "lookup(204.122.16.136)").contains("nix3.thauvin.us") - } - - @Test - @Throws(Exception::class) - fun testWhois() { - val result = whois("17.178.96.59", Lookup.WHOIS_HOST) - assertThat(result, "whois(17.178.96.59").any { it.contains("Apple Inc.") } - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/MastodonTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/MastodonTest.kt deleted file mode 100644 index f4b5e99..0000000 --- a/bin/test/net/thauvin/erik/mobibot/modules/MastodonTest.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * MastodonTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import assertk.assertThat -import assertk.assertions.contains -import net.thauvin.erik.mobibot.LocalProperties -import net.thauvin.erik.mobibot.modules.Mastodon.Companion.toot -import kotlin.test.Test - -class MastodonTest : LocalProperties() { - @Test - @Throws(ModuleException::class) - fun testToot() { - val msg = "Testing Mastodon API from ${getHostName()}" - assertThat( - toot( - getProperty(Mastodon.ACCESS_TOKEN_PROP), - getProperty(Mastodon.INSTANCE_PROP), - getProperty(Mastodon.HANDLE_PROP), - msg, - true - ) - ).contains(msg) - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt deleted file mode 100644 index 1416eec..0000000 --- a/bin/test/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt +++ /dev/null @@ -1,105 +0,0 @@ -/* - * ModuleExceptionTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import assertk.all -import assertk.assertThat -import assertk.assertions.* -import net.thauvin.erik.mobibot.ExceptionSanitizer.sanitize -import org.testng.annotations.DataProvider -import kotlin.test.Test -import java.io.IOException -import java.lang.reflect.Method - -/** - * The `ModuleExceptionTest` class. - */ -class ModuleExceptionTest { - companion object { - const val DEBUG_MESSAGE = "debugMessage" - const val MESSAGE = "message" - } - - @DataProvider(name = "dp") - fun createData(@Suppress("UNUSED_PARAMETER") m: Method?): Array> { - return arrayOf( - arrayOf(ModuleException(DEBUG_MESSAGE, MESSAGE, IOException("URL http://foobar.com"))), - arrayOf(ModuleException(DEBUG_MESSAGE, MESSAGE, IOException("URL http://foobar.com?"))), - arrayOf(ModuleException(DEBUG_MESSAGE, MESSAGE)) - ) - } - - @Test(dataProvider = "dp") - fun testGetDebugMessage(e: ModuleException) { - assertThat(e::debugMessage).isEqualTo(DEBUG_MESSAGE) - } - - @Test(dataProvider = "dp") - fun testGetMessage(e: ModuleException) { - assertThat(e).hasMessage(MESSAGE) - } - - @Test - fun testSanitizeMessage() { - val apiKey = "1234567890" - var e = ModuleException(DEBUG_MESSAGE, MESSAGE, IOException("URL http://foo.com?apiKey=$apiKey&userID=me")) - assertThat( - e.sanitize(apiKey, "", "me").message, "ModuleException(debugMessage, message, IOException(url))" - ).isNotNull().all { - contains("xxxxxxxxxx", "userID=xx", "java.io.IOException") - doesNotContain(apiKey, "me") - } - - e = ModuleException(DEBUG_MESSAGE, MESSAGE, null) - assertThat(e.sanitize(apiKey), "ModuleException(debugMessage, message, null)").hasMessage(MESSAGE) - - e = ModuleException(DEBUG_MESSAGE, MESSAGE, IOException()) - assertThat(e.sanitize(apiKey), "ModuleException(debugMessage, message, IOException())").hasMessage(MESSAGE) - - e = ModuleException(DEBUG_MESSAGE, apiKey) - assertThat(e.sanitize(apiKey).message, "ModuleException(debugMessage, apiKey)").isNotNull() - .doesNotContain(apiKey) - - val msg: String? = null - e = ModuleException(DEBUG_MESSAGE, msg, IOException(msg)) - assertThat(e.sanitize(apiKey).message, "ModuleException(debugMessage, msg, IOException(msg))").isNull() - - e = ModuleException(DEBUG_MESSAGE, msg, IOException("foo is $apiKey")) - assertThat( - e.sanitize(" ", apiKey, "foo").message, - "ModuleException(debugMessage, msg, IOException(foo is $apiKey))" - ).isNotNull().all { - doesNotContain(apiKey) - endsWith("xxx is xxxxxxxxxx") - } - assertThat(e.sanitize(), "exception should be unchanged").isEqualTo(e) - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/PingTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/PingTest.kt deleted file mode 100644 index d1399e0..0000000 --- a/bin/test/net/thauvin/erik/mobibot/modules/PingTest.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * PingTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import assertk.assertThat -import assertk.assertions.contains -import assertk.assertions.isNotEmpty -import net.thauvin.erik.mobibot.modules.Ping.Companion.randomPing -import kotlin.test.Test - -/** - * The `PingTest` class. - */ -class PingTest { - @Test - fun testPingsArray() { - assertThat(Ping.PINGS, "Ping.PINGS").isNotEmpty() - } - - @Test - fun testRandomPing() { - for (i in 0..9) { - assertThat(Ping.PINGS, "Ping.PINGS[$i]").contains(randomPing()) - } - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt deleted file mode 100644 index f836b0e..0000000 --- a/bin/test/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * RockPaperScissorsTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.modules - -import assertk.assertThat -import assertk.assertions.isEqualTo -import net.thauvin.erik.mobibot.modules.RockPaperScissors.Companion.winLoseOrDraw -import kotlin.test.Test - -class RockPaperScissorsTest { - @Test - fun testWinLoseOrDraw() { - assertThat(winLoseOrDraw("scissors", "paper"), "scissors vs. paper").isEqualTo("win") - assertThat(winLoseOrDraw("paper", "rock"), "paper vs. rock").isEqualTo("win") - assertThat(winLoseOrDraw("rock", "scissors"), "rock vs. scissors").isEqualTo("win") - assertThat(winLoseOrDraw("paper", "scissors"), "paper vs. scissors").isEqualTo("lose") - assertThat(winLoseOrDraw("rock", "paper"), "rock vs. paper").isEqualTo("lose") - assertThat(winLoseOrDraw("scissors", "rock"), "scissors vs. rock").isEqualTo("lose") - assertThat(winLoseOrDraw("scissors", "scissors"), "scissors vs. scissors").isEqualTo("draw") - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt deleted file mode 100644 index d96812b..0000000 --- a/bin/test/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt +++ /dev/null @@ -1,85 +0,0 @@ -/* - * StockQuoteTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import assertk.all -import assertk.assertFailure -import assertk.assertThat -import assertk.assertions.* -import net.thauvin.erik.mobibot.ExceptionSanitizer.sanitize -import net.thauvin.erik.mobibot.LocalProperties -import net.thauvin.erik.mobibot.modules.StockQuote.Companion.getQuote -import net.thauvin.erik.mobibot.msg.ErrorMessage -import net.thauvin.erik.mobibot.msg.Message -import kotlin.test.Test - -/** - * The `StockQuoteTest` class. - */ -class StockQuoteTest : LocalProperties() { - private fun buildMatch(label: String): String { - return "${label}:[ ]+[0-9.]+".prependIndent() - } - - @Test - @Throws(ModuleException::class) - fun testGetQuote() { - val apiKey = getProperty(StockQuote.API_KEY_PROP) - try { - var symbol = "apple inc" - val messages = getQuote(symbol, apiKey) - assertThat(messages, "response not empty").isNotEmpty() - assertThat(messages, "getQuote($symbol)").index(0).prop(Message::msg).matches("Symbol: AAPL .*".toRegex()) - assertThat(messages, "getQuote($symbol)").index(1).prop(Message::msg).matches(buildMatch("Price").toRegex()) - assertThat(messages, "getQuote($symbol)").index(2).prop(Message::msg) - .matches(buildMatch("Previous").toRegex()) - assertThat(messages, "getQuote($symbol)").index(3).prop(Message::msg).matches(buildMatch("Open").toRegex()) - - symbol = "blahfoo" - assertThat(getQuote(symbol, apiKey).first(), "getQuote($symbol)").all { - isInstanceOf(ErrorMessage::class.java) - prop(Message::msg).isEqualTo(StockQuote.INVALID_SYMBOL) - } - assertThat(getQuote("", "apikey").first(), "getQuote(empty)").all { - isInstanceOf(ErrorMessage::class.java) - prop(Message::msg).isEqualTo(StockQuote.INVALID_SYMBOL) - } - assertFailure { getQuote("test", "") }.isInstanceOf(ModuleException::class.java).hasNoCause() - } catch (e: ModuleException) { - // Avoid displaying api keys in CI logs - if ("true" == System.getenv("CI")) { - throw e.sanitize(apiKey) - } else { - throw e - } - } - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/Weather2Test.kt b/bin/test/net/thauvin/erik/mobibot/modules/Weather2Test.kt deleted file mode 100644 index 66f4d22..0000000 --- a/bin/test/net/thauvin/erik/mobibot/modules/Weather2Test.kt +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Weather2Test.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import assertk.all -import assertk.assertFailure -import assertk.assertThat -import assertk.assertions.* -import net.aksingh.owmjapis.api.APIException -import net.aksingh.owmjapis.core.OWM -import net.thauvin.erik.mobibot.LocalProperties -import net.thauvin.erik.mobibot.modules.Weather2.Companion.API_KEY_PROP -import net.thauvin.erik.mobibot.modules.Weather2.Companion.ftoC -import net.thauvin.erik.mobibot.modules.Weather2.Companion.getCountry -import net.thauvin.erik.mobibot.modules.Weather2.Companion.getWeather -import net.thauvin.erik.mobibot.modules.Weather2.Companion.mphToKmh -import net.thauvin.erik.mobibot.msg.Message -import kotlin.test.Test - -/** - * The `Weather2Test` class. - */ -class Weather2Test : LocalProperties() { - @Test - fun testFtoC() { - val t = ftoC(32.0) - assertThat(t.second, "32 °F is 0 °C").isEqualTo(0) - } - - @Test - fun testGetCountry() { - assertThat(getCountry("foo"), "foo is not a valid country").isEqualTo(OWM.Country.UNITED_STATES) - assertThat(getCountry("fr"), "country should France").isEqualTo(OWM.Country.FRANCE) - - val country = OWM.Country.entries.toTypedArray() - repeat(3) { - val rand = country[(country.indices).random()] - assertThat(getCountry(rand.value), rand.name).isEqualTo(rand) - } - } - - @Test - fun testMphToKmh() { - val w = mphToKmh(0.62) - assertThat(w.second, "0.62 mph is 1 km/h").isEqualTo(1) - } - - @Test - @Throws(ModuleException::class) - fun testWeather() { - var query = "98204" - var messages = getWeather(query, getProperty(API_KEY_PROP)) - assertThat(messages, "getWeather($query)").index(0).prop(Message::msg).all { - contains("Everett, United States") - contains("US") - } - assertThat(messages, "getWeather($query)").index(messages.size - 1).prop(Message::msg).endsWith("98204%2CUS") - - query = "San Francisco" - messages = getWeather(query, getProperty(API_KEY_PROP)) - assertThat(messages, "getWeather($query)").index(0).prop(Message::msg).all { - contains("San Francisco") - contains("US") - } - assertThat(messages, "getWeather($query)").index(messages.size - 1).prop(Message::msg).endsWith("5391959") - - query = "London, GB" - messages = getWeather(query, getProperty(API_KEY_PROP)) - assertThat(messages, "getWeather($query)").index(0).prop(Message::msg).all { - contains("London, United Kingdom") - contains("GB") - } - assertThat(messages, "getWeather($query)").index(messages.size - 1).prop(Message::msg).endsWith("2643743") - - try { - query = "Foo, US" - getWeather(query, getProperty(API_KEY_PROP)) - } catch (e: ModuleException) { - assertThat(e.cause, "getWeather($query)").isNotNull().isInstanceOf(APIException::class.java) - } - - query = "test" - assertFailure { getWeather(query, "") }.isInstanceOf(ModuleException::class.java).hasNoCause() - assertFailure { getWeather(query, null) }.isInstanceOf(ModuleException::class.java).hasNoCause() - - messages = getWeather("", "apikey") - assertThat(messages, "getWeather(empty)").index(0).prop(Message::isError).isTrue() - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt deleted file mode 100644 index 855522c..0000000 --- a/bin/test/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt +++ /dev/null @@ -1,77 +0,0 @@ -/* - * WolframAlphaTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.modules - -import assertk.assertFailure -import assertk.assertThat -import assertk.assertions.contains -import assertk.assertions.hasMessage -import assertk.assertions.isInstanceOf -import net.thauvin.erik.mobibot.ExceptionSanitizer.sanitize -import net.thauvin.erik.mobibot.LocalProperties -import net.thauvin.erik.mobibot.modules.WolframAlpha.Companion.queryWolfram -import kotlin.test.Test - -class WolframAlphaTest : LocalProperties() { - @Test - fun testAppId() { - assertFailure { queryWolfram("1 gallon to liter", appId = "DEMO") } - .isInstanceOf(ModuleException::class.java) - .hasMessage("Error 1: Invalid appid") - - assertFailure { queryWolfram("1 gallon to liter", appId = "") } - .isInstanceOf(ModuleException::class.java) - } - - @Test(groups = ["modules", "no-ci"]) - @Throws(ModuleException::class) - fun queryWolframTest() { - val apiKey = getProperty(WolframAlpha.APPID_KEY_PROP) - try { - var query = "SFO to SEA" - assertThat(queryWolfram(query, appId = apiKey), "queryWolfram($query)").contains("miles") - - query = "SFO to LAX" - assertThat( - queryWolfram(query, WolframAlpha.METRIC, apiKey), - "queryWolfram($query)" - ).contains("kilometers") - } catch (e: ModuleException) { - // Avoid displaying api key in CI logs - if ("true" == System.getenv("CI")) { - throw e.sanitize(apiKey) - } else { - throw e - } - } - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/WordTimeTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/WordTimeTest.kt deleted file mode 100644 index 7931f33..0000000 --- a/bin/test/net/thauvin/erik/mobibot/modules/WordTimeTest.kt +++ /dev/null @@ -1,70 +0,0 @@ -/* - * WordTimeTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import assertk.assertThat -import assertk.assertions.endsWith -import assertk.assertions.matches -import assertk.assertions.startsWith -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.modules.WorldTime.Companion.BEATS_KEYWORD -import net.thauvin.erik.mobibot.modules.WorldTime.Companion.COUNTRIES_MAP -import net.thauvin.erik.mobibot.modules.WorldTime.Companion.time -import org.pircbotx.Colors -import kotlin.test.Test -import java.time.ZoneId - -/** - * The `WordTimeTest` class. - */ -class WordTimeTest { - @Test - fun testTime() { - assertThat(time(), "time()").matches( - ("The time is ${Colors.BOLD}\\d{1,2}:\\d{2}${Colors.BOLD} " + - "on ${Colors.BOLD}\\w+, \\d{1,2} \\w+ \\d{4}${Colors.BOLD} " + - "in ${Colors.BOLD}Los Angeles${Colors.BOLD}").toRegex() - ) - assertThat(time(""), "time()").endsWith("Los Angeles".bold()) - assertThat(time("PST"), "time(PST)").endsWith("Los Angeles".bold()) - assertThat(time("GB"), "time(GB)").endsWith("London".bold()) - assertThat(time("FR"), "time(FR)").endsWith("Paris".bold()) - assertThat(time("BLAH"), "time(BLAH)").startsWith("Unsupported") - assertThat(time("BEAT"), "time($BEATS_KEYWORD)").matches("[\\w ]+ .?@\\d{3}+.? .beats".toRegex()) - } - - @Test - fun testZones() { - COUNTRIES_MAP.filter { it.value != BEATS_KEYWORD }.forEach { - assertThat(ZoneId.of(it.value)) - } - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/msg/MessageTest.kt b/bin/test/net/thauvin/erik/mobibot/msg/MessageTest.kt deleted file mode 100644 index 32a0495..0000000 --- a/bin/test/net/thauvin/erik/mobibot/msg/MessageTest.kt +++ /dev/null @@ -1,109 +0,0 @@ -/* - * MessageTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.msg - -import assertk.all -import assertk.assertThat -import assertk.assertions.isFalse -import assertk.assertions.isTrue -import assertk.assertions.prop -import kotlin.test.Test - -class MessageTest { - @Test - fun testConstructor() { - var msg = Message("foo") - - msg.isError = true - assertThat(msg.isNotice, "message is notice").isTrue() - - msg = Message("foo", isError = true) - assertThat(msg.isNotice, "message is notice too").isTrue() - } - - @Test - fun testErrorMessage() { - val msg = ErrorMessage("foo") - assertThat(msg).all { - prop(Message::isError).isTrue() - prop(Message::isNotice).isTrue() - prop(Message::isPrivate).isFalse() - } - } - - @Test - fun testIsError() { - val msg = Message("foo") - msg.isError = true - assertThat(msg).all { - prop(Message::isError).isTrue() - prop(Message::isNotice).isTrue() - prop(Message::isPrivate).isFalse() - } - msg.isError = false - assertThat(msg).all { - prop(Message::isError).isFalse() - prop(Message::isNotice).isTrue() - prop(Message::isPrivate).isFalse() - } - } - - @Test - fun testNoticeMessage() { - val msg = NoticeMessage("food") - assertThat(msg).all { - prop(Message::isError).isFalse() - prop(Message::isNotice).isTrue() - prop(Message::isPrivate).isFalse() - } - } - - @Test - fun testPrivateMessage() { - val msg = PrivateMessage("foo") - assertThat(msg).all { - prop(Message::isPrivate).isTrue() - prop(Message::isError).isFalse() - prop(Message::isNotice).isFalse() - } - } - - @Test - fun testPublicMessage() { - val msg = PublicMessage("foo") - assertThat(msg).all { - prop(Message::isError).isFalse() - prop(Message::isNotice).isFalse() - prop(Message::isPrivate).isFalse() - } - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt b/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt index 88634ae..01f14f3 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt @@ -14,11 +14,11 @@ import java.time.ZoneId */ object ReleaseInfo { const val PROJECT = "mobibot" - const val VERSION = "0.8.0-rc+20231110234054" + const val VERSION = "0.8.0-rc+20231111131146" @JvmField val BUILD_DATE: LocalDateTime = LocalDateTime.ofInstant( - Instant.ofEpochMilli(1699688454937L), ZoneId.systemDefault() + Instant.ofEpochMilli(1699737106723L), ZoneId.systemDefault() ) const val WEBSITE = "https://www.mobitopia.org/mobibot/" diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml deleted file mode 100644 index 16644cc..0000000 --- a/src/main/resources/log4j2.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From a40d20458bbd889ff195cb5108640cdcfa993ff8 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 12 Nov 2023 14:19:38 -0800 Subject: [PATCH 742/844] Updated copyright --- .github/workflows/{gradle.yml => bld.yml} | 0 .idea/copyright/BSD_3.xml | 2 +- .idea/libraries/bld.xml | 3 +- .idea/misc.xml | 11 ++++++ .../java/net/thauvin/erik/MobibotBuild.java | 3 +- .../kotlin/net/thauvin/erik/mobibot/Addons.kt | 2 +- .../net/thauvin/erik/mobibot/Constants.kt | 2 +- .../net/thauvin/erik/mobibot/FeedReader.kt | 2 +- .../net/thauvin/erik/mobibot/Mobibot.kt | 2 +- .../net/thauvin/erik/mobibot/Pinboard.kt | 2 +- .../net/thauvin/erik/mobibot/ReleaseInfo.kt | 35 +++++++++++++++++-- .../kotlin/net/thauvin/erik/mobibot/Utils.kt | 2 +- .../erik/mobibot/commands/AbstractCommand.kt | 2 +- .../erik/mobibot/commands/ChannelFeed.kt | 2 +- .../thauvin/erik/mobibot/commands/Cycle.kt | 2 +- .../net/thauvin/erik/mobibot/commands/Die.kt | 2 +- .../thauvin/erik/mobibot/commands/Ignore.kt | 2 +- .../net/thauvin/erik/mobibot/commands/Info.kt | 2 +- .../net/thauvin/erik/mobibot/commands/Me.kt | 2 +- .../thauvin/erik/mobibot/commands/Modules.kt | 2 +- .../net/thauvin/erik/mobibot/commands/Msg.kt | 2 +- .../net/thauvin/erik/mobibot/commands/Nick.kt | 2 +- .../thauvin/erik/mobibot/commands/Recap.kt | 2 +- .../net/thauvin/erik/mobibot/commands/Say.kt | 2 +- .../thauvin/erik/mobibot/commands/Users.kt | 2 +- .../thauvin/erik/mobibot/commands/Versions.kt | 2 +- .../erik/mobibot/commands/links/Comment.kt | 2 +- .../mobibot/commands/links/LinksManager.kt | 2 +- .../erik/mobibot/commands/links/Posting.kt | 2 +- .../erik/mobibot/commands/links/Tags.kt | 2 +- .../erik/mobibot/commands/links/View.kt | 2 +- .../mobibot/commands/seen/NickComparator.kt | 2 +- .../erik/mobibot/commands/seen/Seen.kt | 2 +- .../erik/mobibot/commands/seen/SeenNick.kt | 2 +- .../erik/mobibot/commands/tell/Tell.kt | 2 +- .../erik/mobibot/commands/tell/TellManager.kt | 2 +- .../erik/mobibot/commands/tell/TellMessage.kt | 2 +- .../thauvin/erik/mobibot/entries/Entries.kt | 2 +- .../erik/mobibot/entries/EntriesUtils.kt | 2 +- .../erik/mobibot/entries/EntryComment.kt | 2 +- .../thauvin/erik/mobibot/entries/EntryLink.kt | 2 +- .../erik/mobibot/entries/FeedsManager.kt | 2 +- .../erik/mobibot/modules/AbstractModule.kt | 2 +- .../net/thauvin/erik/mobibot/modules/Calc.kt | 2 +- .../thauvin/erik/mobibot/modules/ChatGpt.kt | 2 +- .../erik/mobibot/modules/CryptoPrices.kt | 2 +- .../erik/mobibot/modules/CurrencyConverter.kt | 2 +- .../net/thauvin/erik/mobibot/modules/Dice.kt | 2 +- .../erik/mobibot/modules/GoogleSearch.kt | 2 +- .../net/thauvin/erik/mobibot/modules/Joke.kt | 2 +- .../thauvin/erik/mobibot/modules/Lookup.kt | 2 +- .../thauvin/erik/mobibot/modules/Mastodon.kt | 2 +- .../erik/mobibot/modules/ModuleException.kt | 2 +- .../net/thauvin/erik/mobibot/modules/Ping.kt | 2 +- .../erik/mobibot/modules/RockPaperScissors.kt | 2 +- .../erik/mobibot/modules/StockQuote.kt | 2 +- .../net/thauvin/erik/mobibot/modules/War.kt | 2 +- .../thauvin/erik/mobibot/modules/Weather2.kt | 2 +- .../erik/mobibot/modules/WolframAlpha.kt | 2 +- .../thauvin/erik/mobibot/modules/WorldTime.kt | 2 +- .../thauvin/erik/mobibot/msg/ErrorMessage.kt | 2 +- .../net/thauvin/erik/mobibot/msg/Message.kt | 2 +- .../thauvin/erik/mobibot/msg/NoticeMessage.kt | 2 +- .../erik/mobibot/msg/PrivateMessage.kt | 2 +- .../thauvin/erik/mobibot/msg/PublicMessage.kt | 2 +- .../erik/mobibot/social/SocialManager.kt | 2 +- .../erik/mobibot/social/SocialModule.kt | 2 +- .../erik/mobibot/social/SocialTimer.kt | 2 +- .../net/thauvin/erik/mobibot/AddonsTest.kt | 2 +- .../net/thauvin/erik/mobibot/DisableOnCi.kt | 2 +- .../erik/mobibot/DisableOnCiCondition.kt | 2 +- .../erik/mobibot/ExceptionSanitizer.kt | 2 +- .../thauvin/erik/mobibot/FeedReaderTest.kt | 2 +- .../thauvin/erik/mobibot/LocalProperties.kt | 2 +- .../net/thauvin/erik/mobibot/PinboardTest.kt | 2 +- .../net/thauvin/erik/mobibot/UtilsTest.kt | 2 +- .../thauvin/erik/mobibot/commands/InfoTest.kt | 2 +- .../erik/mobibot/commands/RecapTest.kt | 2 +- .../commands/links/LinksManagerTest.kt | 2 +- .../erik/mobibot/commands/links/ViewTest.kt | 2 +- .../erik/mobibot/commands/seen/SeenTest.kt | 2 +- .../mobibot/commands/tell/TellMessageTest.kt | 2 +- .../commands/tell/TellMessagesMgrTest.kt | 2 +- .../erik/mobibot/entries/EntriesUtilsTest.kt | 2 +- .../erik/mobibot/entries/EntryLinkTest.kt | 2 +- .../erik/mobibot/entries/FeedMgrTest.kt | 2 +- .../thauvin/erik/mobibot/modules/CalcTest.kt | 2 +- .../erik/mobibot/modules/ChatGptTest.kt | 2 +- .../erik/mobibot/modules/CryptoPricesTest.kt | 2 +- .../mobibot/modules/CurrencyConverterTest.kt | 2 +- .../thauvin/erik/mobibot/modules/DiceTest.kt | 2 +- .../erik/mobibot/modules/GoogleSearchTest.kt | 2 +- .../thauvin/erik/mobibot/modules/JokeTest.kt | 2 +- .../erik/mobibot/modules/LookupTest.kt | 2 +- .../erik/mobibot/modules/MastodonTest.kt | 2 +- .../mobibot/modules/ModuleExceptionTest.kt | 2 +- .../thauvin/erik/mobibot/modules/PingTest.kt | 2 +- .../mobibot/modules/RockPaperScissorsTest.kt | 2 +- .../erik/mobibot/modules/StockQuoteTest.kt | 2 +- .../erik/mobibot/modules/Weather2Test.kt | 2 +- .../erik/mobibot/modules/WolframAlphaTest.kt | 2 +- .../erik/mobibot/modules/WordTimeTest.kt | 2 +- .../thauvin/erik/mobibot/msg/MessageTest.kt | 2 +- 103 files changed, 146 insertions(+), 102 deletions(-) rename .github/workflows/{gradle.yml => bld.yml} (100%) diff --git a/.github/workflows/gradle.yml b/.github/workflows/bld.yml similarity index 100% rename from .github/workflows/gradle.yml rename to .github/workflows/bld.yml diff --git a/.idea/copyright/BSD_3.xml b/.idea/copyright/BSD_3.xml index 275eca9..3c57002 100644 --- a/.idea/copyright/BSD_3.xml +++ b/.idea/copyright/BSD_3.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/.idea/libraries/bld.xml b/.idea/libraries/bld.xml index cf75013..ca84ff0 100644 --- a/.idea/libraries/bld.xml +++ b/.idea/libraries/bld.xml @@ -6,6 +6,7 @@ + @@ -14,4 +15,4 @@ - \ No newline at end of file + diff --git a/.idea/misc.xml b/.idea/misc.xml index e853f87..8232032 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -6,6 +6,17 @@ + diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index 9b6b32a..e7dbde3 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -1,7 +1,7 @@ /* * MobibotBuild.java * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -89,6 +89,7 @@ public class MobibotBuild extends Project { .include(dependency("org.apache.logging.log4j", "log4j-api", log4j)) .include(dependency("org.apache.logging.log4j", "log4j-core", log4j)) .include(dependency("org.apache.logging.log4j", "log4j-slf4j2-impl", log4j)) + // Misc. .include(dependency("com.rometools", "rome", "2.1.0")) .include(dependency("com.squareup.okhttp3", "okhttp", "4.12.0")) .include(dependency("net.aksingh", "owm-japis", "2.5.3.0")) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt index c6f16cb..2c5f05d 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt @@ -1,7 +1,7 @@ /* * Addons.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt index ea89f4c..98ef74a 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt @@ -1,7 +1,7 @@ /* * Constants.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt b/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt index 371b523..d82f011 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt @@ -1,7 +1,7 @@ /* * FeedReader.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt index 47dd7c2..ac4d6af 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt @@ -1,7 +1,7 @@ /* * Mobibot.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt index ac01b0a..7cb5aed 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt @@ -1,7 +1,7 @@ /* * Pinboard.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt b/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt index 01f14f3..7a3d41c 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt @@ -1,3 +1,34 @@ +/* + * ReleaseInfo.kt + * + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + /* * This file is automatically generated * Do not modify! -- ALL CHANGES WILL BE ERASED! @@ -14,11 +45,11 @@ import java.time.ZoneId */ object ReleaseInfo { const val PROJECT = "mobibot" - const val VERSION = "0.8.0-rc+20231111131146" + const val VERSION = "0.8.0-rc+20231111131825" @JvmField val BUILD_DATE: LocalDateTime = LocalDateTime.ofInstant( - Instant.ofEpochMilli(1699737106723L), ZoneId.systemDefault() + Instant.ofEpochMilli(1699737505341L), ZoneId.systemDefault() ) const val WEBSITE = "https://www.mobitopia.org/mobibot/" diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt index d69c0c5..e4760d2 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt @@ -1,7 +1,7 @@ /* * Utils.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/AbstractCommand.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/AbstractCommand.kt index e0b091a..5f79472 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/AbstractCommand.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/AbstractCommand.kt @@ -1,7 +1,7 @@ /* * AbstractCommand.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/ChannelFeed.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/ChannelFeed.kt index 9084660..038e378 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/ChannelFeed.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/ChannelFeed.kt @@ -1,7 +1,7 @@ /* * ChannelFeed.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Cycle.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Cycle.kt index 18a8b1d..9608ca8 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Cycle.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Cycle.kt @@ -1,7 +1,7 @@ /* * Cycle.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Die.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Die.kt index c1708a9..f271bfa 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Die.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Die.kt @@ -1,7 +1,7 @@ /* * Die.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt index 8d2b154..d083c10 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt @@ -1,7 +1,7 @@ /* * Ignore.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Info.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Info.kt index 8ee8c4f..ed0b6ef 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Info.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Info.kt @@ -1,7 +1,7 @@ /* * Info.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Me.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Me.kt index f2a13ba..ec7823b 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Me.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Me.kt @@ -1,7 +1,7 @@ /* * Me.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Modules.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Modules.kt index 1aaefd7..b2293b0 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Modules.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Modules.kt @@ -1,7 +1,7 @@ /* * Modules.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Msg.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Msg.kt index 0f492c9..20a6635 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Msg.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Msg.kt @@ -1,7 +1,7 @@ /* * Msg.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Nick.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Nick.kt index 41b2c4b..85a03ab 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Nick.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Nick.kt @@ -1,7 +1,7 @@ /* * Nick.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Recap.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Recap.kt index 0159017..77154c7 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Recap.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Recap.kt @@ -1,7 +1,7 @@ /* * Recap.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Say.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Say.kt index 1f89982..7f76d35 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Say.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Say.kt @@ -1,7 +1,7 @@ /* * Say.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Users.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Users.kt index 4a881a7..33d6fef 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Users.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Users.kt @@ -1,7 +1,7 @@ /* * Users.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Versions.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Versions.kt index a8300f0..802bbde 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Versions.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Versions.kt @@ -1,7 +1,7 @@ /* * Versions.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Comment.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Comment.kt index 90d8bb3..1443d44 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Comment.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Comment.kt @@ -1,7 +1,7 @@ /* * Comment.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManager.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManager.kt index 2d7add6..fba6b99 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManager.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManager.kt @@ -1,7 +1,7 @@ /* * LinksManager.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Posting.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Posting.kt index dca99cf..ff4278d 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Posting.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Posting.kt @@ -1,7 +1,7 @@ /* * Posting.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Tags.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Tags.kt index c59cad9..1662857 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Tags.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Tags.kt @@ -1,7 +1,7 @@ /* * Tags.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/View.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/View.kt index 1626a58..825e374 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/View.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/View.kt @@ -1,7 +1,7 @@ /* * View.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt index 2a3856b..cfd2c27 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt @@ -1,7 +1,7 @@ /* * NickComparator.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt index 83083fd..c9ee0f3 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt @@ -1,7 +1,7 @@ /* * Seen.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt index 1445f9f..7924977 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt @@ -1,7 +1,7 @@ /* * SeenNick.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt index e9d18ae..061ca6a 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt @@ -1,7 +1,7 @@ /* * Tell.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellManager.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellManager.kt index 229bc5f..b65a4da 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellManager.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellManager.kt @@ -1,7 +1,7 @@ /* * TellManager.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt index cc48d59..d17fbb5 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt @@ -1,7 +1,7 @@ /* * TellMessage.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/Entries.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/Entries.kt index 15506e0..e8676ec 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/Entries.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/Entries.kt @@ -1,7 +1,7 @@ /* * Entries.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt index 6e58fd9..9c09626 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt @@ -1,7 +1,7 @@ /* * EntriesUtils.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryComment.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryComment.kt index c0cc2a8..e18d692 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryComment.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryComment.kt @@ -1,7 +1,7 @@ /* * EntryComment.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt index 8098bbf..4a69446 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt @@ -1,7 +1,7 @@ /* * EntryLink.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt index e7017ab..f786cb2 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt @@ -1,7 +1,7 @@ /* * FeedsManager.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/AbstractModule.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/AbstractModule.kt index 8dcf6d8..8c8e736 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/AbstractModule.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/AbstractModule.kt @@ -1,7 +1,7 @@ /* * AbstractModule.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Calc.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Calc.kt index 9003783..b7aae28 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Calc.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Calc.kt @@ -1,7 +1,7 @@ /* * Calc.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt index 09791a8..bd92332 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt @@ -1,7 +1,7 @@ /* * ChatGpt.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt index 4464732..4614a4c 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt @@ -1,7 +1,7 @@ /* * CryptoPrices.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt index 954f4d1..da0efd8 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt @@ -1,7 +1,7 @@ /* * CurrencyConverter.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Dice.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Dice.kt index 84f2280..8420fb1 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Dice.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Dice.kt @@ -1,7 +1,7 @@ /* * Dice.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt index a9b15a5..f426d1e 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt @@ -1,7 +1,7 @@ /* * GoogleSearch.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Joke.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Joke.kt index 91b9ad2..2760fa7 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Joke.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Joke.kt @@ -1,7 +1,7 @@ /* * Joke.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Lookup.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Lookup.kt index eecc55e..9ab2ead 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Lookup.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Lookup.kt @@ -1,7 +1,7 @@ /* * Lookup.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Mastodon.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Mastodon.kt index 1141c0e..3be3a5f 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Mastodon.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Mastodon.kt @@ -1,7 +1,7 @@ /* * Mastodon.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ModuleException.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ModuleException.kt index 9a0e641..a7416c2 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ModuleException.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ModuleException.kt @@ -1,7 +1,7 @@ /* * ModuleException.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Ping.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Ping.kt index 86b311a..944dbc1 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Ping.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Ping.kt @@ -1,7 +1,7 @@ /* * Ping.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt index d224568..a299d8d 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt @@ -1,7 +1,7 @@ /* * RockPaperScissors.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt index 6b591cd..dcae5e7 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt @@ -1,7 +1,7 @@ /* * StockQuote.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/War.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/War.kt index 0c64465..8799279 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/War.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/War.kt @@ -1,7 +1,7 @@ /* * War.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt index 83eba95..80a06fa 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt @@ -1,7 +1,7 @@ /* * Weather2.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt index 8d9c4e6..a72efab 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt @@ -1,7 +1,7 @@ /* * WolframAlpha.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WorldTime.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WorldTime.kt index 0c379b3..18072bc 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WorldTime.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WorldTime.kt @@ -1,7 +1,7 @@ /* * WorldTime.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/ErrorMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/ErrorMessage.kt index b9f5212..0607936 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/ErrorMessage.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/msg/ErrorMessage.kt @@ -1,7 +1,7 @@ /* * ErrorMessage.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/Message.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/Message.kt index 84e3a1e..d41ec8c 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/Message.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/msg/Message.kt @@ -1,7 +1,7 @@ /* * Message.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/NoticeMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/NoticeMessage.kt index 2be52aa..037d504 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/NoticeMessage.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/msg/NoticeMessage.kt @@ -1,7 +1,7 @@ /* * NoticeMessage.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/PrivateMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/PrivateMessage.kt index 8d34d28..b424fdf 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/PrivateMessage.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/msg/PrivateMessage.kt @@ -1,7 +1,7 @@ /* * PrivateMessage.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/PublicMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/PublicMessage.kt index 9e67ecb..9c5e088 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/PublicMessage.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/msg/PublicMessage.kt @@ -1,7 +1,7 @@ /* * PublicMessage.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialManager.kt b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialManager.kt index 3fb3874..91f2dd9 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialManager.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialManager.kt @@ -1,7 +1,7 @@ /* * SocialManager.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialModule.kt b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialModule.kt index 47a33d9..b594670 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialModule.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialModule.kt @@ -1,7 +1,7 @@ /* * SocialModule.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialTimer.kt b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialTimer.kt index e779a3c..3fd315e 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialTimer.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialTimer.kt @@ -1,7 +1,7 @@ /* * SocialTimer.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt index 7f65548..9dd6034 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt @@ -1,7 +1,7 @@ /* * AddonsTest.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCi.kt b/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCi.kt index 01d98ca..2fbcb71 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCi.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCi.kt @@ -1,7 +1,7 @@ /* * DisableOnCi.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCiCondition.kt b/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCiCondition.kt index 24f1ca0..1d9baf4 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCiCondition.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCiCondition.kt @@ -1,7 +1,7 @@ /* * DisableOnCiCondition.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/ExceptionSanitizer.kt b/src/test/kotlin/net/thauvin/erik/mobibot/ExceptionSanitizer.kt index b02188e..a3994ec 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/ExceptionSanitizer.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/ExceptionSanitizer.kt @@ -1,7 +1,7 @@ /* * ExceptionSanitizer.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt index cfc3d4e..46f9368 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt @@ -1,7 +1,7 @@ /* * FeedReaderTest.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/LocalProperties.kt b/src/test/kotlin/net/thauvin/erik/mobibot/LocalProperties.kt index 95b6c08..c039d74 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/LocalProperties.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/LocalProperties.kt @@ -1,7 +1,7 @@ /* * LocalProperties.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/PinboardTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/PinboardTest.kt index cf9d59a..3b81950 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/PinboardTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/PinboardTest.kt @@ -1,7 +1,7 @@ /* * PinboardTest.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt index a024cff..682b350 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt @@ -1,7 +1,7 @@ /* * UtilsTest.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/InfoTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/InfoTest.kt index 33a411f..99ba951 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/InfoTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/InfoTest.kt @@ -1,7 +1,7 @@ /* * InfoTest.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/RecapTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/RecapTest.kt index 34dce0e..b6fbbff 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/RecapTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/RecapTest.kt @@ -1,7 +1,7 @@ /* * RecapTest.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt index eea09db..fa2bb70 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt @@ -1,7 +1,7 @@ /* * LinksManagerTest.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/ViewTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/ViewTest.kt index b5028e3..e315891 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/ViewTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/ViewTest.kt @@ -1,7 +1,7 @@ /* * ViewTest.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt index 331f97c..52810eb 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt @@ -1,7 +1,7 @@ /* * SeenTest.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt index f2c6f35..b28c45a 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt @@ -1,7 +1,7 @@ /* * TellMessageTest.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt index 9ab1bce..e3c9c1f 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt @@ -1,7 +1,7 @@ /* * TellMessagesMgrTest.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt index 8e9bd6f..0ad26b5 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt @@ -1,7 +1,7 @@ /* * EntriesUtilsTest.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt index 495ed15..5028e6e 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt @@ -1,7 +1,7 @@ /* * EntryLinkTest.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt index de6075d..b56e6ed 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt @@ -1,7 +1,7 @@ /* * FeedMgrTest.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt index 6df5616..3bd4c0f 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt @@ -1,7 +1,7 @@ /* * CalcTest.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt index 00fa43f..dc1133a 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt @@ -1,7 +1,7 @@ /* * ChatGptTest.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt index 9847080..3eaa4c5 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt @@ -1,7 +1,7 @@ /* * CryptoPricesTest.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt index 57affe5..a177715 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt @@ -1,7 +1,7 @@ /* * CurrencyConverterTest.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/DiceTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/DiceTest.kt index 0aaacb9..8bafede 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/DiceTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/DiceTest.kt @@ -1,7 +1,7 @@ /* * DiceTest.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt index b0c154a..93c2560 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt @@ -1,7 +1,7 @@ /* * GoogleSearchTest.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/JokeTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/JokeTest.kt index 9b8dcb3..0af8e75 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/JokeTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/JokeTest.kt @@ -1,7 +1,7 @@ /* * JokeTest.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt index e67c8ad..a3fc226 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt @@ -1,7 +1,7 @@ /* * LookupTest.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt index d189d75..f4b5e99 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt @@ -1,7 +1,7 @@ /* * MastodonTest.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt index 9dda5b3..efc267a 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt @@ -1,7 +1,7 @@ /* * ModuleExceptionTest.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/PingTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/PingTest.kt index a6ff707..d1399e0 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/PingTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/PingTest.kt @@ -1,7 +1,7 @@ /* * PingTest.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt index fb8865b..f836b0e 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt @@ -1,7 +1,7 @@ /* * RockPaperScissorsTest.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt index ae8cff2..d96812b 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt @@ -1,7 +1,7 @@ /* * StockQuoteTest.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt index e135866..66f4d22 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt @@ -1,7 +1,7 @@ /* * Weather2Test.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt index 417f9fc..5faffc2 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt @@ -1,7 +1,7 @@ /* * WolframAlphaTest.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt index 5c8cc84..35368b2 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt @@ -1,7 +1,7 @@ /* * WordTimeTest.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/msg/MessageTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/msg/MessageTest.kt index 477c1a4..32a0495 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/msg/MessageTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/msg/MessageTest.kt @@ -1,7 +1,7 @@ /* * MessageTest.kt * - * Copyright 2021-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: From 44c1e8db3e98a238d462721f27ce82330acab99a Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 12 Nov 2023 16:06:40 -0800 Subject: [PATCH 743/844] Fixed bld-ci badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fbcacc2..041f0dc 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) [![Kotlin](https://img.shields.io/badge/kotlin-1.9.20-7f52ff.svg)](https://kotlinlang.org) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ethauvin_mobibot&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=ethauvin_mobibot) -[![GitHub CI](https://github.com/ethauvin/mobibot/actions/workflows/gradle.yml/badge.svg)](https://github.com/ethauvin/mobibot/actions/workflows/gradle.yml) +[![GitHub CI](https://github.com/ethauvin/mobibot/actions/workflows/bld.yml/badge.svg)](https://github.com/ethauvin/mobibot/actions/workflows/bld.yml) [![CircleCI](https://circleci.com/gh/ethauvin/mobibot/tree/master.svg?style=shield)](https://circleci.com/gh/ethauvin/mobibot/tree/master) Some very basic instructions: From e34ea334d66885c7e2a06df7103fc58247282496 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sat, 25 Nov 2023 18:08:13 -0800 Subject: [PATCH 744/844] Added detekt extension --- README.md | 2 +- config/detekt/baseline.xml | 31 ++++++------- lib/bld/bld-wrapper.properties | 4 +- release_info.txt | 1 + .../java/net/thauvin/erik/MobibotBuild.java | 43 +++++++++++++------ .../net/thauvin/erik/mobibot/Constants.kt | 2 +- .../net/thauvin/erik/mobibot/ReleaseInfo.kt | 36 ++-------------- .../thauvin/erik/mobibot/commands/Ignore.kt | 1 - .../net/thauvin/erik/mobibot/DisableOnCi.kt | 2 +- .../thauvin/erik/mobibot/FeedReaderTest.kt | 3 -- .../net/thauvin/erik/mobibot/UtilsTest.kt | 3 -- .../erik/mobibot/commands/seen/SeenTest.kt | 14 +++--- .../mobibot/commands/tell/TellMessageTest.kt | 3 -- .../erik/mobibot/entries/EntryLinkTest.kt | 7 --- .../thauvin/erik/mobibot/modules/CalcTest.kt | 3 -- .../erik/mobibot/modules/ChatGptTest.kt | 4 +- .../erik/mobibot/modules/CryptoPricesTest.kt | 3 -- .../mobibot/modules/CurrencyConverterTest.kt | 4 -- .../erik/mobibot/modules/GoogleSearchTest.kt | 7 +-- .../thauvin/erik/mobibot/modules/JokeTest.kt | 3 -- .../erik/mobibot/modules/LookupTest.kt | 3 -- .../mobibot/modules/ModuleExceptionTest.kt | 3 -- .../thauvin/erik/mobibot/modules/PingTest.kt | 3 -- .../erik/mobibot/modules/StockQuoteTest.kt | 3 -- .../erik/mobibot/modules/Weather2Test.kt | 3 -- .../erik/mobibot/modules/WolframAlphaTest.kt | 4 +- .../erik/mobibot/modules/WordTimeTest.kt | 3 -- 27 files changed, 68 insertions(+), 130 deletions(-) diff --git a/README.md b/README.md index 041f0dc..fe1920f 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # mobibot [![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) -[![Kotlin](https://img.shields.io/badge/kotlin-1.9.20-7f52ff.svg)](https://kotlinlang.org) +[![Kotlin](https://img.shields.io/badge/kotlin-1.9.21-7f52ff.svg)](https://kotlinlang.org) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ethauvin_mobibot&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=ethauvin_mobibot) [![GitHub CI](https://github.com/ethauvin/mobibot/actions/workflows/bld.yml/badge.svg)](https://github.com/ethauvin/mobibot/actions/workflows/bld.yml) [![CircleCI](https://circleci.com/gh/ethauvin/mobibot/tree/master.svg?style=shield)](https://circleci.com/gh/ethauvin/mobibot/tree/master) diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml index 5c6be73..641e97c 100644 --- a/config/detekt/baseline.xml +++ b/config/detekt/baseline.xml @@ -1,15 +1,15 @@ - + - + CyclomaticComplexMethod:FeedsManager.kt$FeedsManager.Companion$@JvmStatic fun saveFeed(entries: Entries, currentFile: String = CURRENT_XML) - CyclomaticComplexMethod:Weather2.kt$Weather2.Companion$@JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message> + CyclomaticComplexMethod:Weather2.kt$Weather2.Companion$@JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message> LongMethod:FeedsManager.kt$FeedsManager.Companion$@JvmStatic fun saveFeed(entries: Entries, currentFile: String = CURRENT_XML) - LongMethod:Mobibot.kt$Mobibot.Companion$@JvmStatic @Throws(Exception::class) fun main(args: Array<String>) - LongMethod:StockQuote.kt$StockQuote.Companion$@JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List<Message> - LongMethod:Weather2.kt$Weather2.Companion$@JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message> + LongMethod:Mobibot.kt$Mobibot.Companion$@JvmStatic @Throws(Exception::class) fun main(args: Array<String>) + LongMethod:StockQuote.kt$StockQuote.Companion$@JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List<Message> + LongMethod:Weather2.kt$Weather2.Companion$@JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message> LongParameterList:Comment.kt$Comment$( channel: String, cmd: String, entry: EntryLink, entryIndex: Int, commentIndex: Int, event: GenericMessageEvent ) - LongParameterList:EntryLink.kt$EntryLink$( // Link's comments val comments: MutableList<EntryComment> = mutableListOf(), // Tags/categories val tags: MutableList<SyndCategory> = mutableListOf(), // Channel var channel: String, // Creation date var date: Date = Calendar.getInstance().time, // Link's URL var link: String, // Author's login var login: String = "", // Author's nickname var nick: String, // Link's title var title: String ) + LongParameterList:EntryLink.kt$EntryLink$( // Link's comments val comments: MutableList<EntryComment> = mutableListOf(), // Tags/categories val tags: MutableList<SyndCategory> = mutableListOf(), // Channel var channel: String, // Creation date var date: Date = Calendar.getInstance().time, // Link's URL var link: String, // Author's login var login: String = "", // Author's nickname var nick: String, // Link's title var title: String ) MagicNumber:ChatGpt.kt$ChatGpt$400 MagicNumber:ChatGpt.kt$ChatGpt.Companion$200 MagicNumber:ChatGpt.kt$ChatGpt.Companion$429 @@ -52,22 +52,22 @@ NestedBlockDepth:Comment.kt$Comment$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) NestedBlockDepth:CurrencyConverter.kt$CurrencyConverter.Companion$@JvmStatic @Throws(ModuleException::class) fun loadSymbols(apiKey: String?) NestedBlockDepth:CurrencyConverter.kt$CurrencyConverter.Companion$@JvmStatic fun convertCurrency(apiKey: String?, query: String): Message - NestedBlockDepth:EntryLink.kt$EntryLink$private fun setTags(tags: List<String?>) + NestedBlockDepth:EntryLink.kt$EntryLink$private fun setTags(tags: List<String?>) NestedBlockDepth:FeedsManager.kt$FeedsManager.Companion$@JvmStatic @Throws(IOException::class, FeedException::class) fun loadFeed(entries: Entries, currentFile: String = CURRENT_XML): String NestedBlockDepth:FeedsManager.kt$FeedsManager.Companion$@JvmStatic fun saveFeed(entries: Entries, currentFile: String = CURRENT_XML) NestedBlockDepth:GoogleSearch.kt$GoogleSearch$override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) - NestedBlockDepth:GoogleSearch.kt$GoogleSearch.Companion$@JvmStatic @Throws(ModuleException::class) fun searchGoogle( query: String, apiKey: String?, cseKey: String?, quotaUser: String = ReleaseInfo.PROJECT ): List<Message> + NestedBlockDepth:GoogleSearch.kt$GoogleSearch.Companion$@JvmStatic @Throws(ModuleException::class) fun searchGoogle( query: String, apiKey: String?, cseKey: String?, quotaUser: String = ReleaseInfo.PROJECT ): List<Message> NestedBlockDepth:LinksManager.kt$LinksManager$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) NestedBlockDepth:Lookup.kt$Lookup$override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) NestedBlockDepth:Mastodon.kt$Mastodon.Companion$@JvmStatic @Throws(ModuleException::class) fun toot(apiKey: String?, instance: String?, handle: String?, message: String, isDm: Boolean): String NestedBlockDepth:Posting.kt$Posting$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) NestedBlockDepth:Seen.kt$Seen$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) - NestedBlockDepth:StockQuote.kt$StockQuote.Companion$@JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List<Message> + NestedBlockDepth:StockQuote.kt$StockQuote.Companion$@JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List<Message> NestedBlockDepth:Tell.kt$Tell$fun send(event: GenericUserEvent) NestedBlockDepth:Utils.kt$Utils$@JvmStatic fun loadSerialData(file: String, default: Any, logger: Logger, description: String): Any NestedBlockDepth:Utils.kt$Utils$@JvmStatic fun saveSerialData(file: String, data: Any, logger: Logger, description: String) NestedBlockDepth:Weather2.kt$Weather2$override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) - NestedBlockDepth:Weather2.kt$Weather2.Companion$@JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message> + NestedBlockDepth:Weather2.kt$Weather2.Companion$@JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message> ReturnCount:Addons.kt$Addons$fun exec(channel: String, cmd: String, args: String, event: GenericMessageEvent): Boolean ReturnCount:Addons.kt$Addons$fun help(channel: String, topic: String, event: GenericMessageEvent): Boolean ReturnCount:ExceptionSanitizer.kt$ExceptionSanitizer$fun ModuleException.sanitize(vararg sanitize: String): ModuleException @@ -76,18 +76,19 @@ SwallowedException:StockQuoteTest.kt$StockQuoteTest$e: ModuleException SwallowedException:WolframAlphaTest.kt$WolframAlphaTest$e: ModuleException ThrowsCount:ChatGpt.kt$ChatGpt.Companion$@JvmStatic @Throws(ModuleException::class) fun chat(query: String, apiKey: String?, maxTokens: Int): String - ThrowsCount:GoogleSearch.kt$GoogleSearch.Companion$@JvmStatic @Throws(ModuleException::class) fun searchGoogle( query: String, apiKey: String?, cseKey: String?, quotaUser: String = ReleaseInfo.PROJECT ): List<Message> - ThrowsCount:Joke.kt$Joke.Companion$@JvmStatic @Throws(ModuleException::class) fun randomJoke(): List<Message> + ThrowsCount:GoogleSearch.kt$GoogleSearch.Companion$@JvmStatic @Throws(ModuleException::class) fun searchGoogle( query: String, apiKey: String?, cseKey: String?, quotaUser: String = ReleaseInfo.PROJECT ): List<Message> + ThrowsCount:Joke.kt$Joke.Companion$@JvmStatic @Throws(ModuleException::class) fun randomJoke(): List<Message> ThrowsCount:Mastodon.kt$Mastodon.Companion$@JvmStatic @Throws(ModuleException::class) fun toot(apiKey: String?, instance: String?, handle: String?, message: String, isDm: Boolean): String - ThrowsCount:StockQuote.kt$StockQuote.Companion$@JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List<Message> + ThrowsCount:StockQuote.kt$StockQuote.Companion$@JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List<Message> ThrowsCount:StockQuote.kt$StockQuote.Companion$@Throws(ModuleException::class) private fun getJsonResponse(response: String, debugMessage: String): JSONObject - ThrowsCount:Weather2.kt$Weather2.Companion$@JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message> + ThrowsCount:Weather2.kt$Weather2.Companion$@JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message> ThrowsCount:WolframAlpha.kt$WolframAlpha.Companion$@JvmStatic @Throws(ModuleException::class) fun queryWolfram(query: String, units: String = IMPERIAL, appId: String?): String TooGenericExceptionCaught:StockQuote.kt$StockQuote.Companion$e: NullPointerException TooGenericExceptionCaught:Weather2.kt$Weather2.Companion$e: NullPointerException TooManyFunctions:EntryLink.kt$EntryLink : Serializable TooManyFunctions:Mobibot.kt$Mobibot : ListenerAdapter TooManyFunctions:Tell.kt$Tell : AbstractCommand + UtilityClassWithPublicConstructor:LocalProperties.kt$LocalProperties WildcardImport:AddonsTest.kt$import net.thauvin.erik.mobibot.modules.* WildcardImport:EntryLinkTest.kt$import assertk.assertions.* WildcardImport:FeedMgrTest.kt$import assertk.assertions.* diff --git a/lib/bld/bld-wrapper.properties b/lib/bld/bld-wrapper.properties index 8375666..e219f09 100644 --- a/lib/bld/bld-wrapper.properties +++ b/lib/bld/bld-wrapper.properties @@ -1,9 +1,9 @@ bld.downloadExtensionJavadoc=false bld.downloadExtensionSources=true bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.1 -bld.extensions=com.uwyn.rife2:bld-generated-version:0.9.3-SNAPSHOT +bld.extensions=com.uwyn.rife2:bld-generated-version:0.9.3 bld.extensions-kotlin=com.uwyn.rife2:bld-kotlin:0.9.0-SNAPSHOT -bld.extensions-pmd=com.uwyn.rife2:bld-testng:0.9.2 +bld.extensions-detekt=com.uwyn.rife2:bld-detekt:0.9.0-SNAPSHOT bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES bld.downloadLocation= bld.sourceDirectories= diff --git a/release_info.txt b/release_info.txt index f5efde2..b00e5ba 100644 --- a/release_info.txt +++ b/release_info.txt @@ -17,6 +17,7 @@ object {{v className/}} { const val VERSION = "{{v version/}}" @JvmField + @Suppress("MagicNumber") val BUILD_DATE: LocalDateTime = LocalDateTime.ofInstant( Instant.ofEpochMilli({{v epoch/}}L), ZoneId.systemDefault() ) diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index e7dbde3..d1c489a 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -35,9 +35,10 @@ import rife.bld.BuildCommand; import rife.bld.Project; import rife.bld.dependencies.Repository; import rife.bld.extension.CompileKotlinOperation; -import rife.bld.extension.CompileKotlinOptions; +import rife.bld.extension.DetektOperation; import rife.bld.extension.GeneratedVersionOperation; import rife.bld.extension.JacocoReportOperation; +import rife.bld.operations.exceptions.ExitStatusException; import rife.tools.FileUtils; import rife.tools.exceptions.FileUtilsErrorException; @@ -68,12 +69,13 @@ public class MobibotBuild extends Project { autoDownloadPurge = true; repositories = List.of(MAVEN_LOCAL, MAVEN_CENTRAL, new Repository("https://jitpack.io")); - var log4j = version(2, 21, 1); + var log4j = version(2, 22, 0); + var kotlin = version(1, 9, 21); scope(compile) // PircBotX .include(dependency("com.github.pircbotx", "pircbotx", "2.3.1")) // Commons (mostly for PircBotX) - .include(dependency("org.apache.commons", "commons-lang3", "3.13.0")) + .include(dependency("org.apache.commons", "commons-lang3", "3.14.0")) .include(dependency("org.apache.commons", "commons-text", "1.11.0")) .include(dependency("commons-codec", "commons-codec", "1.16.0")) .include(dependency("commons-net", "commons-net", "3.10.0")) @@ -81,7 +83,10 @@ public class MobibotBuild extends Project { .include(dependency("com.google.code.gson", "gson", "2.10.1")) .include(dependency("com.google.guava", "guava", "32.1.3-jre")) // Kotlin - .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", version(1, 9, 20))) + .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlin)) + .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-common", kotlin)) + .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-jdk7", kotlin)) + .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-jdk8", kotlin)) .include(dependency("org.jetbrains.kotlinx", "kotlinx-coroutines-core", "1.7.3")) .include(dependency("org.jetbrains.kotlinx", "kotlinx-cli-jvm", "0.3.6")) // Logging @@ -97,13 +102,13 @@ public class MobibotBuild extends Project { .include(dependency("org.json", "json", "20231013")) .include(dependency("org.jsoup", "jsoup", "1.16.2")) // Thauvin - .include(dependency("net.thauvin.erik", "cryptoprice", "1.0.1")) - .include(dependency("net.thauvin.erik", "jokeapi", "0.9.0")) - .include(dependency("net.thauvin.erik", "pinboard-poster", "1.1.0")) + .include(dependency("net.thauvin.erik", "cryptoprice", "1.0.2-SNAPSHOT")) + .include(dependency("net.thauvin.erik", "jokeapi", "0.9.1-SNAPSHOT")) + .include(dependency("net.thauvin.erik", "pinboard-poster", "1.1.1-SNAPSHOT")) .include(dependency("net.thauvin.erik.urlencoder", "urlencoder-lib-jvm", "1.4.0")); scope(test) .include(dependency("com.willowtreeapps.assertk", "assertk-jvm", version(0, 27, 0))) - .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", version(1, 9, 20))) + .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", version(1, 9, 21))) .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 10, 1))) .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 10, 1))); @@ -132,11 +137,6 @@ public class MobibotBuild extends Project { releaseInfo(); new CompileKotlinOperation() .fromProject(this) - .compileOptions( - new CompileKotlinOptions() - .jdkRelease(javaRelease) - .verbose(true) - ) .execute(); } @@ -150,6 +150,23 @@ public class MobibotBuild extends Project { FileUtils.copy(new File(buildDistDirectory(), jarFileName()), new File(deploy, "mobibot.jar")); } + @BuildCommand(summary = "Checks source with Detekt") + public void detekt() throws ExitStatusException, IOException, InterruptedException { + new DetektOperation() + .fromProject(this) + .baseline("config/detekt/baseline.xml") + .execute(); + } + + @BuildCommand(value = "detekt-baseline", summary = "Creates the Detekt baseline") + public void detektBaseline() throws ExitStatusException, IOException, InterruptedException { + new DetektOperation() + .fromProject(this) + .baseline("config/detekt/baseline.xml") + .createBaseline(true) + .execute(); + } + @BuildCommand(summary = "Generates JaCoCo Reports") public void jacoco() throws IOException { new JacocoReportOperation() diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt index 98ef74a..d037e44 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt @@ -63,7 +63,7 @@ object Constants { * User-Agent */ const val USER_AGENT = - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36" + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36" /** * The help command. diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt b/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt index 7a3d41c..fbdfe48 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt @@ -1,34 +1,3 @@ -/* - * ReleaseInfo.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - /* * This file is automatically generated * Do not modify! -- ALL CHANGES WILL BE ERASED! @@ -45,11 +14,12 @@ import java.time.ZoneId */ object ReleaseInfo { const val PROJECT = "mobibot" - const val VERSION = "0.8.0-rc+20231111131825" + const val VERSION = "0.8.0-rc+20231125180722" @JvmField + @Suppress("MagicNumber") val BUILD_DATE: LocalDateTime = LocalDateTime.ofInstant( - Instant.ofEpochMilli(1699737505341L), ZoneId.systemDefault() + Instant.ofEpochMilli(1700964443060L), ZoneId.systemDefault() ) const val WEBSITE = "https://www.mobitopia.org/mobibot/" diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt index d083c10..2109693 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt @@ -143,5 +143,4 @@ class Ignore : AbstractCommand() { ignored.addAll(value.split(LinksManager.TAG_MATCH)) } } - } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCi.kt b/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCi.kt index 2fbcb71..22b0146 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCi.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCi.kt @@ -41,4 +41,4 @@ import org.junit.jupiter.api.extension.ExtendWith @Target(AnnotationTarget.TYPE, AnnotationTarget.FUNCTION) @Retention(AnnotationRetention.RUNTIME) @ExtendWith(DisableOnCiCondition::class) -annotation class DisabledOnCi +annotation class DisableOnCi diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt index 46f9368..bf4408f 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt @@ -42,9 +42,6 @@ import java.net.MalformedURLException import java.net.UnknownHostException import kotlin.test.Test -/** - * The `FeedReader Test` class. - */ class FeedReaderTest { @Test fun readFeedTest() { diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt index 682b350..a65b3a5 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt @@ -68,9 +68,6 @@ import java.time.LocalDateTime import java.util.* import kotlin.test.Test -/** - * The `Utils Test` class. - */ class UtilsTest { private val ascii = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt index 52810eb..62a1db7 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt @@ -48,18 +48,18 @@ class SeenTest { seen.clear() assertThat(seen::seenNicks).isEmpty() seen.load() - assertThat(seen::seenNicks).key(nick).isNotNull() + assertThat(seen::seenNicks).key(NICK).isNotNull() } @Test @Order(2) fun addTest() { - val last = seen.seenNicks[nick]?.lastSeen - seen.add(nick.lowercase()) + val last = seen.seenNicks[NICK]?.lastSeen + seen.add(NICK.lowercase()) assertThat(seen).all { prop(Seen::seenNicks).size().isEqualTo(1) - prop(Seen::seenNicks).key(nick).isNotNull().prop(SeenNick::lastSeen).isNotEqualTo(last) - prop(Seen::seenNicks).key(nick).isNotNull().prop(SeenNick::nick).isNotNull().isEqualTo(nick.lowercase()) + prop(Seen::seenNicks).key(NICK).isNotNull().prop(SeenNick::lastSeen).isNotEqualTo(last) + prop(Seen::seenNicks).key(NICK).isNotNull().prop(SeenNick::nick).isNotNull().isEqualTo(NICK.lowercase()) } } @@ -75,12 +75,12 @@ class SeenTest { companion object { private val tmpFile = kotlin.io.path.createTempFile(suffix = ".ser") private val seen = Seen(tmpFile.toAbsolutePath().toString()) - private const val nick = "ErikT" + private const val NICK = "ErikT" @JvmStatic @BeforeClass fun beforeClass() { - seen.add(nick) + seen.add(NICK) assertThat(tmpFile.fileSize(), "tmpFile.size").isGreaterThan(0) } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt index b28c45a..69bc2e9 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt @@ -41,9 +41,6 @@ import java.time.LocalDateTime import java.time.temporal.Temporal import kotlin.test.Test -/** - * The `TellMessageTest` class. - */ class TellMessageTest { private fun isValidDate(date: Temporal): Boolean { return Duration.between(date, LocalDateTime.now()).toMinutes() < 1 diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt index 5028e6e..3a3bdda 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt @@ -39,13 +39,6 @@ import java.security.SecureRandom import java.util.* import kotlin.test.Test -/** - * The `EntryUtilsTest` class. - * - * @author [Erik C. Thauvin](https://erik.thauvin.net/) - * @created 2019-04-19 - * @since 1.0 - */ class EntryLinkTest { private val entryLink = EntryLink( "https://www.mobitopia.org/", "Mobitopia", "Skynx", "JimH", "#mobitopia", diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt index 3bd4c0f..04afe8c 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt @@ -39,9 +39,6 @@ import net.thauvin.erik.mobibot.Utils.bold import net.thauvin.erik.mobibot.modules.Calc.Companion.calculate import kotlin.test.Test -/** - * The `CalcTest` class. - */ class CalcTest { @Test fun testCalculate() { diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt index dc1133a..603c353 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt @@ -35,7 +35,7 @@ import assertk.assertThat import assertk.assertions.contains import assertk.assertions.hasNoCause import assertk.assertions.isInstanceOf -import net.thauvin.erik.mobibot.DisabledOnCi +import net.thauvin.erik.mobibot.DisableOnCi import net.thauvin.erik.mobibot.LocalProperties import kotlin.test.Test @@ -48,7 +48,7 @@ class ChatGptTest : LocalProperties() { } @Test - @DisabledOnCi + @DisableOnCi fun testChat() { val apiKey = getProperty(ChatGpt.API_KEY_PROP) assertThat( diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt index 3eaa4c5..10b3a43 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt @@ -41,9 +41,6 @@ import net.thauvin.erik.mobibot.modules.CryptoPrices.Companion.getCurrencyName import net.thauvin.erik.mobibot.modules.CryptoPrices.Companion.loadCurrencies import kotlin.test.Test -/** - * The `CryptoPricesTest` class. - */ class CryptoPricesTest { init { loadCurrencies() diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt index a177715..8ab64c0 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt @@ -44,10 +44,6 @@ import net.thauvin.erik.mobibot.msg.Message import net.thauvin.erik.mobibot.msg.PublicMessage import kotlin.test.Test - -/** - * The `CurrencyConvertTest` class. - */ class CurrencyConverterTest : LocalProperties() { init { val apiKey = getProperty(CurrencyConverter.API_KEY_PROP) diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt index 93c2560..4942266 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt @@ -34,7 +34,7 @@ import assertk.all import assertk.assertFailure import assertk.assertThat import assertk.assertions.* -import net.thauvin.erik.mobibot.DisabledOnCi +import net.thauvin.erik.mobibot.DisableOnCi import net.thauvin.erik.mobibot.ExceptionSanitizer.sanitize import net.thauvin.erik.mobibot.LocalProperties import net.thauvin.erik.mobibot.modules.GoogleSearch.Companion.searchGoogle @@ -42,9 +42,6 @@ import net.thauvin.erik.mobibot.msg.ErrorMessage import net.thauvin.erik.mobibot.msg.Message import kotlin.test.Test -/** - * The `GoogleSearchTest` class. - */ class GoogleSearchTest : LocalProperties() { @Test fun testAPIKeys() { @@ -65,7 +62,7 @@ class GoogleSearchTest : LocalProperties() { } @Test - @DisabledOnCi + @DisableOnCi @Throws(ModuleException::class) fun testSearchGoogle() { val apiKey = getProperty(GoogleSearch.API_KEY_PROP) diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/JokeTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/JokeTest.kt index 0af8e75..441d435 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/JokeTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/JokeTest.kt @@ -38,9 +38,6 @@ import net.thauvin.erik.mobibot.msg.Message import net.thauvin.erik.mobibot.msg.PublicMessage import kotlin.test.Test -/** - * The `JokeTest` class. - */ class JokeTest { @Test @Throws(ModuleException::class) diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt index a3fc226..8699c0f 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt @@ -37,9 +37,6 @@ import net.thauvin.erik.mobibot.modules.Lookup.Companion.nslookup import net.thauvin.erik.mobibot.modules.Lookup.Companion.whois import kotlin.test.Test -/** - * The `Lookup Test` class. - */ class LookupTest { @Test @Throws(Exception::class) diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt index efc267a..416b3ab 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt @@ -39,9 +39,6 @@ import org.junit.jupiter.params.provider.MethodSource import java.io.IOException import kotlin.test.Test -/** - * The `ModuleExceptionTest` class. - */ class ModuleExceptionTest { companion object { const val DEBUG_MESSAGE = "debugMessage" diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/PingTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/PingTest.kt index d1399e0..bbf9eb1 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/PingTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/PingTest.kt @@ -36,9 +36,6 @@ import assertk.assertions.isNotEmpty import net.thauvin.erik.mobibot.modules.Ping.Companion.randomPing import kotlin.test.Test -/** - * The `PingTest` class. - */ class PingTest { @Test fun testPingsArray() { diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt index d96812b..0816b17 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt @@ -41,9 +41,6 @@ import net.thauvin.erik.mobibot.msg.ErrorMessage import net.thauvin.erik.mobibot.msg.Message import kotlin.test.Test -/** - * The `StockQuoteTest` class. - */ class StockQuoteTest : LocalProperties() { private fun buildMatch(label: String): String { return "${label}:[ ]+[0-9.]+".prependIndent() diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt index 66f4d22..7ae2b83 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt @@ -45,9 +45,6 @@ import net.thauvin.erik.mobibot.modules.Weather2.Companion.mphToKmh import net.thauvin.erik.mobibot.msg.Message import kotlin.test.Test -/** - * The `Weather2Test` class. - */ class Weather2Test : LocalProperties() { @Test fun testFtoC() { diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt index 5faffc2..3bfe0d1 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt @@ -36,7 +36,7 @@ import assertk.assertThat import assertk.assertions.contains import assertk.assertions.hasMessage import assertk.assertions.isInstanceOf -import net.thauvin.erik.mobibot.DisabledOnCi +import net.thauvin.erik.mobibot.DisableOnCi import net.thauvin.erik.mobibot.ExceptionSanitizer.sanitize import net.thauvin.erik.mobibot.LocalProperties import net.thauvin.erik.mobibot.modules.WolframAlpha.Companion.queryWolfram @@ -54,7 +54,7 @@ class WolframAlphaTest : LocalProperties() { } @Test - @DisabledOnCi + @DisableOnCi @Throws(ModuleException::class) fun queryWolframTest() { val apiKey = getProperty(WolframAlpha.APPID_KEY_PROP) diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt index 35368b2..ae40e3a 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt @@ -42,9 +42,6 @@ import org.pircbotx.Colors import java.time.ZoneId import kotlin.test.Test -/** - * The `WordTimeTest` class. - */ class WordTimeTest { @Test fun testTime() { From 3a773f7d46accd1cdea0543c8b538f6fe5180d84 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sat, 25 Nov 2023 18:14:41 -0800 Subject: [PATCH 745/844] Added snapshots repository --- src/bld/java/net/thauvin/erik/MobibotBuild.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index d1c489a..d8f52e4 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -50,8 +50,7 @@ import java.util.ArrayList; import java.util.List; import java.util.jar.Attributes; -import static rife.bld.dependencies.Repository.MAVEN_CENTRAL; -import static rife.bld.dependencies.Repository.MAVEN_LOCAL; +import static rife.bld.dependencies.Repository.*; import static rife.bld.dependencies.Scope.compile; import static rife.bld.dependencies.Scope.test; @@ -67,7 +66,12 @@ public class MobibotBuild extends Project { javaRelease = 17; downloadSources = true; autoDownloadPurge = true; - repositories = List.of(MAVEN_LOCAL, MAVEN_CENTRAL, new Repository("https://jitpack.io")); + repositories = List.of( + MAVEN_LOCAL, + SONATYPE_SNAPSHOTS_LEGACY, + MAVEN_CENTRAL, + new Repository("https://jitpack.io") + ); var log4j = version(2, 22, 0); var kotlin = version(1, 9, 21); From 8412a8c26dbe8d78348eb28b2e9365f3916e101b Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 26 Nov 2023 00:43:44 -0800 Subject: [PATCH 746/844] Removed snapshot repository --- .idea/misc.xml | 2 ++ src/bld/java/net/thauvin/erik/MobibotBuild.java | 16 +++++++--------- .../net/thauvin/erik/mobibot/ReleaseInfo.kt | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index 8232032..26293d3 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -4,6 +4,8 @@ + +

  17. Apache Commons Net
  18. CryptoPrice
  19. exp4j
  20. +
  21. Google Vertex AI
  22. JokeAPI
  23. jsoup
  24. kotlinx-cli
  25. @@ -80,9 +81,10 @@
  26. Performing Google searches
    mobibot: google mobitopia on irc
  27. -
  28. Getting answers from Wolfram Alpha and ChatGPT +
  29. Getting answers from Wolfram Alpha, ChatGPT and Google Gemini
    mobibot: wolfram days until christmas
    mobibot: chatgpt explain quantum computing in simple terms
    +
    mobibot: gemini what are all the colors in a rainbow?
  30. Displaying weather information
    mobibot: weather san francisco
    From a10104dd9dc889841a92b5a4fb38d0fb34a97924 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 17 Dec 2023 22:11:56 -0800 Subject: [PATCH 748/844] Added website link to README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index fe1920f..b360d96 100644 --- a/README.md +++ b/README.md @@ -28,3 +28,5 @@ Some very basic instructions: # launch /usr/bin/nohup java -jar mobibot.jar & ``` + +For a listing of features, see the [website](https://mobitopia.org/mobibot/). From 356f62990d191a21b85b2dbce589dc7e4287f155 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Mon, 18 Dec 2023 14:14:08 -0800 Subject: [PATCH 749/844] Added support for ChatGPT 3.5 Turbo --- properties/mobibot.properties | 1 + .../net/thauvin/erik/mobibot/ReleaseInfo.kt | 4 +-- .../thauvin/erik/mobibot/modules/ChatGpt.kt | 29 +++++++++---------- .../thauvin/erik/mobibot/modules/Gemini.kt | 14 ++++----- .../erik/mobibot/modules/ChatGptTest.kt | 3 +- 5 files changed, 24 insertions(+), 27 deletions(-) diff --git a/properties/mobibot.properties b/properties/mobibot.properties index bc31e8a..a7526cc 100644 --- a/properties/mobibot.properties +++ b/properties/mobibot.properties @@ -87,6 +87,7 @@ disabled-modules=mastodon # gcloud config set project PROJECT_ID # gcloud auth login LOGIN # gcloud auth application-default login +# #gemini-project-id= #gemini-location=us-west1 #gemini-max-tokens=1024 diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt b/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt index f75b334..f805722 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt @@ -14,12 +14,12 @@ import java.time.ZoneId */ object ReleaseInfo { const val PROJECT = "mobibot" - const val VERSION = "0.8.0-rc+20231217213124" + const val VERSION = "0.8.0-rc+20231218140603" @JvmField @Suppress("MagicNumber") val BUILD_DATE: LocalDateTime = LocalDateTime.ofInstant( - Instant.ofEpochMilli(1702877484912L), ZoneId.systemDefault() + Instant.ofEpochMilli(1702937164085L), ZoneId.systemDefault() ) const val WEBSITE = "https://www.mobitopia.org/mobibot/" diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt index bd92332..e2ad717 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt @@ -34,10 +34,8 @@ package net.thauvin.erik.mobibot.modules import net.thauvin.erik.mobibot.Constants import net.thauvin.erik.mobibot.Utils import net.thauvin.erik.mobibot.Utils.sendMessage -import org.apache.commons.text.WordUtils import org.json.JSONException import org.json.JSONObject -import org.json.JSONWriter import org.pircbotx.hooks.types.GenericMessageEvent import org.slf4j.Logger import org.slf4j.LoggerFactory @@ -48,7 +46,7 @@ import java.net.http.HttpRequest import java.net.http.HttpResponse class ChatGpt : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(ChatGpt::class.java) + val logger: Logger = LoggerFactory.getLogger(ChatGpt::class.java) override val name = CHATGPT_NAME @@ -60,7 +58,7 @@ class ChatGpt : AbstractModule() { properties.getOrDefault(MAX_TOKENS_PROP, "1024").toInt() ) if (answer.isNotBlank()) { - event.sendMessage(WordUtils.wrap(answer, 400)) + event.sendMessage(answer) } else { event.respond("$name is stumped.") } @@ -95,7 +93,7 @@ class ChatGpt : AbstractModule() { const val MAX_TOKENS_PROP = "chatgpt-max-tokens" // ChatGPT API URL - private const val API_URL = "https://api.openai.com/v1/completions" + private const val API_URL = "https://api.openai.com/v1/chat/completions" // ChatGPT command private const val CHATGPT_CMD = "chatgpt" @@ -105,7 +103,7 @@ class ChatGpt : AbstractModule() { @Throws(ModuleException::class) fun chat(query: String, apiKey: String?, maxTokens: Int): String { if (!apiKey.isNullOrEmpty()) { - val prompt = JSONWriter.valueToString("Q:$query\nA:") + val content = query.replace("\"", "\\\"") val request = HttpRequest.newBuilder() .uri(URI.create(API_URL)) .header("Content-Type", "application/json") @@ -114,14 +112,15 @@ class ChatGpt : AbstractModule() { .POST( HttpRequest.BodyPublishers.ofString( """{ - "model": "text-davinci-003", - "prompt": $prompt, - "temperature": 0, - "max_tokens": $maxTokens, - "top_p": 1, - "frequency_penalty": 0, - "presence_penalty": 0 - }""".trimIndent() + "model": "gpt-3.5-turbo-1106", + "max_tokens": $maxTokens, + "messages": [ + { + "role": "user", + "content": "$content" + } + ] + }""".trimIndent() ) ) .build() @@ -131,7 +130,7 @@ class ChatGpt : AbstractModule() { try { val jsonResponse = JSONObject(response.body()) val choices = jsonResponse.getJSONArray("choices") - return choices.getJSONObject(0).getString("text").trim() + return choices.getJSONObject(0).getJSONObject("message").getString("content").trim() } catch (e: JSONException) { throw ModuleException( "$CHATGPT_CMD($query): JSON", diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini.kt index 2f7c842..6f9b5ff 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini.kt @@ -1,16 +1,12 @@ package net.thauvin.erik.mobibot.modules -import com.google.auth.Credentials import com.google.cloud.vertexai.VertexAI -import com.google.cloud.vertexai.api.GenerateContentResponse import com.google.cloud.vertexai.api.GenerationConfig import com.google.cloud.vertexai.generativeai.preview.ChatSession import com.google.cloud.vertexai.generativeai.preview.GenerativeModel import com.google.cloud.vertexai.generativeai.preview.ResponseHandler import net.thauvin.erik.mobibot.Utils import net.thauvin.erik.mobibot.Utils.sendMessage -import okio.IOException -import org.apache.commons.text.WordUtils import org.pircbotx.hooks.types.GenericMessageEvent import org.slf4j.Logger import org.slf4j.LoggerFactory @@ -86,7 +82,7 @@ class Gemini : AbstractModule() { val session = ChatSession(model) val response = session.sendMessage(query) - return ResponseHandler.getText(response); + return ResponseHandler.getText(response) } } catch (e: Exception) { throw ModuleException( @@ -96,7 +92,7 @@ class Gemini : AbstractModule() { ) } } else { - throw ModuleException("${GEMINI_CMD}($query)", "No ${GEMINI_NAME} Project ID or Location specified.") + throw ModuleException("${GEMINI_CMD}($query)", "No $GEMINI_NAME Project ID or Location specified.") } } } @@ -105,10 +101,10 @@ class Gemini : AbstractModule() { commands.add(GEMINI_CMD) with(help) { add("To get answers from $name:") - add(Utils.helpFormat("%c ${GEMINI_CMD} ")) + add(Utils.helpFormat("%c $GEMINI_CMD ")) add("For example:") - add(Utils.helpFormat("%c ${GEMINI_CMD} explain quantum computing in simple terms")) - add(Utils.helpFormat("%c ${GEMINI_CMD} how do I make an HTTP request in Javascript?")) + add(Utils.helpFormat("%c $GEMINI_CMD explain quantum computing in simple terms")) + add(Utils.helpFormat("%c $GEMINI_CMD how do I make an HTTP request in Javascript?")) } initProperties(PROJECT_ID_PROP, LOCATION_PROPR, MAX_TOKENS_PROP) } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt index 603c353..7180c13 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt @@ -54,11 +54,12 @@ class ChatGptTest : LocalProperties() { assertThat( ChatGpt.chat("how do I make an HTTP request in Javascript?", apiKey, 100) ).contains("XMLHttpRequest") + assertThat( ChatGpt.chat("how do I encode a URL in java?", apiKey, 60) ).contains("URLEncoder") - assertFailure { ChatGpt.chat("1 liter to gallon", apiKey, 0) } + assertFailure { ChatGpt.chat("1 liter to gallon", apiKey, -1) } .isInstanceOf(ModuleException::class.java) } } From c684332b9d804fb3b46de120a9f4b9678098f351 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 24 Dec 2023 12:11:11 -0800 Subject: [PATCH 750/844] Bumped to Kotlin 1.9.22 --- release_info.txt | 2 +- src/bld/java/net/thauvin/erik/MobibotBuild.java | 6 +++--- src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/release_info.txt b/release_info.txt index b00e5ba..d2c33ac 100644 --- a/release_info.txt +++ b/release_info.txt @@ -22,7 +22,7 @@ object {{v className/}} { Instant.ofEpochMilli({{v epoch/}}L), ZoneId.systemDefault() ) - const val WEBSITE = "https://www.mobitopia.org/mobibot/" + const val WEBSITE = "https://mobitopia.org/mobibot/" const val AUTHOR = "Erik C. Thauvin" const val AUTHOR_URL = "https://erik.thauvin.net/" } diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index d6a294f..ba67d1d 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -71,7 +71,7 @@ public class MobibotBuild extends Project { ); var log4j = version(2, 22, 0); - var kotlin = version(1, 9, 21); + var kotlin = version(1, 9, 22); scope(compile) // PircBotX .include(dependency("com.github.pircbotx", "pircbotx", "2.3.1")) @@ -82,7 +82,7 @@ public class MobibotBuild extends Project { .include(dependency("commons-net", "commons-net", "3.10.0")) // Google .include(dependency("com.google.code.gson", "gson", "2.10.1")) - .include(dependency("com.google.guava", "guava", "32.1.3-jre")) + .include(dependency("com.google.guava", "guava", "33.0.0-jre")) .include(dependency("com.google.cloud", "google-cloud-vertexai", version(0, 1, 0))) // Kotlin .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlin)) @@ -109,7 +109,7 @@ public class MobibotBuild extends Project { .include(dependency("net.thauvin.erik.urlencoder", "urlencoder-lib-jvm", "1.4.0")); scope(test) .include(dependency("com.willowtreeapps.assertk", "assertk-jvm", version(0, 28, 0))) - .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", version(1, 9, 21))) + .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", kotlin)) .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 10, 1))) .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 10, 1))); diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt b/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt index f805722..f499559 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt @@ -14,15 +14,15 @@ import java.time.ZoneId */ object ReleaseInfo { const val PROJECT = "mobibot" - const val VERSION = "0.8.0-rc+20231218140603" + const val VERSION = "0.8.0-rc+20231224114859" @JvmField @Suppress("MagicNumber") val BUILD_DATE: LocalDateTime = LocalDateTime.ofInstant( - Instant.ofEpochMilli(1702937164085L), ZoneId.systemDefault() + Instant.ofEpochMilli(1703447340121L), ZoneId.systemDefault() ) - const val WEBSITE = "https://www.mobitopia.org/mobibot/" + const val WEBSITE = "https://mobitopia.org/mobibot/" const val AUTHOR = "Erik C. Thauvin" const val AUTHOR_URL = "https://erik.thauvin.net/" } From 3c4e76e5b916bb9bcc727776c90737f0722d4706 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Tue, 16 Jan 2024 10:21:27 -0800 Subject: [PATCH 751/844] Updated copyright --- .idea/intellij-javadocs-4.0.1.xml | 204 ++++++++++++++++++ .../java/net/thauvin/erik/MobibotBuild.java | 10 +- .../kotlin/net/thauvin/erik/mobibot/Addons.kt | 2 +- .../net/thauvin/erik/mobibot/Constants.kt | 2 +- .../net/thauvin/erik/mobibot/FeedReader.kt | 2 +- .../net/thauvin/erik/mobibot/Mobibot.kt | 2 +- .../net/thauvin/erik/mobibot/Pinboard.kt | 2 +- .../net/thauvin/erik/mobibot/ReleaseInfo.kt | 4 +- .../kotlin/net/thauvin/erik/mobibot/Utils.kt | 2 +- .../erik/mobibot/commands/AbstractCommand.kt | 2 +- .../erik/mobibot/commands/ChannelFeed.kt | 2 +- .../thauvin/erik/mobibot/commands/Cycle.kt | 2 +- .../net/thauvin/erik/mobibot/commands/Die.kt | 2 +- .../thauvin/erik/mobibot/commands/Ignore.kt | 2 +- .../net/thauvin/erik/mobibot/commands/Info.kt | 2 +- .../net/thauvin/erik/mobibot/commands/Me.kt | 2 +- .../thauvin/erik/mobibot/commands/Modules.kt | 2 +- .../net/thauvin/erik/mobibot/commands/Msg.kt | 2 +- .../net/thauvin/erik/mobibot/commands/Nick.kt | 2 +- .../thauvin/erik/mobibot/commands/Recap.kt | 2 +- .../net/thauvin/erik/mobibot/commands/Say.kt | 2 +- .../thauvin/erik/mobibot/commands/Users.kt | 2 +- .../thauvin/erik/mobibot/commands/Versions.kt | 2 +- .../erik/mobibot/commands/links/Comment.kt | 2 +- .../mobibot/commands/links/LinksManager.kt | 2 +- .../erik/mobibot/commands/links/Posting.kt | 2 +- .../erik/mobibot/commands/links/Tags.kt | 2 +- .../erik/mobibot/commands/links/View.kt | 2 +- .../mobibot/commands/seen/NickComparator.kt | 2 +- .../erik/mobibot/commands/seen/Seen.kt | 2 +- .../erik/mobibot/commands/seen/SeenNick.kt | 2 +- .../erik/mobibot/commands/tell/Tell.kt | 2 +- .../erik/mobibot/commands/tell/TellManager.kt | 2 +- .../erik/mobibot/commands/tell/TellMessage.kt | 2 +- .../thauvin/erik/mobibot/entries/Entries.kt | 2 +- .../erik/mobibot/entries/EntriesUtils.kt | 2 +- .../erik/mobibot/entries/EntryComment.kt | 2 +- .../thauvin/erik/mobibot/entries/EntryLink.kt | 2 +- .../erik/mobibot/entries/FeedsManager.kt | 2 +- .../erik/mobibot/modules/AbstractModule.kt | 2 +- .../net/thauvin/erik/mobibot/modules/Calc.kt | 2 +- .../thauvin/erik/mobibot/modules/ChatGpt.kt | 2 +- .../erik/mobibot/modules/CryptoPrices.kt | 2 +- .../erik/mobibot/modules/CurrencyConverter.kt | 2 +- .../net/thauvin/erik/mobibot/modules/Dice.kt | 2 +- .../thauvin/erik/mobibot/modules/Gemini.kt | 33 ++- .../erik/mobibot/modules/GoogleSearch.kt | 2 +- .../net/thauvin/erik/mobibot/modules/Joke.kt | 2 +- .../thauvin/erik/mobibot/modules/Lookup.kt | 2 +- .../thauvin/erik/mobibot/modules/Mastodon.kt | 2 +- .../erik/mobibot/modules/ModuleException.kt | 2 +- .../net/thauvin/erik/mobibot/modules/Ping.kt | 2 +- .../erik/mobibot/modules/RockPaperScissors.kt | 2 +- .../erik/mobibot/modules/StockQuote.kt | 2 +- .../net/thauvin/erik/mobibot/modules/War.kt | 2 +- .../thauvin/erik/mobibot/modules/Weather2.kt | 2 +- .../erik/mobibot/modules/WolframAlpha.kt | 2 +- .../thauvin/erik/mobibot/modules/WorldTime.kt | 2 +- .../thauvin/erik/mobibot/msg/ErrorMessage.kt | 2 +- .../net/thauvin/erik/mobibot/msg/Message.kt | 2 +- .../thauvin/erik/mobibot/msg/NoticeMessage.kt | 2 +- .../erik/mobibot/msg/PrivateMessage.kt | 2 +- .../thauvin/erik/mobibot/msg/PublicMessage.kt | 2 +- .../erik/mobibot/social/SocialManager.kt | 2 +- .../erik/mobibot/social/SocialModule.kt | 2 +- .../erik/mobibot/social/SocialTimer.kt | 2 +- .../net/thauvin/erik/mobibot/AddonsTest.kt | 2 +- .../net/thauvin/erik/mobibot/DisableOnCi.kt | 2 +- .../erik/mobibot/DisableOnCiCondition.kt | 2 +- .../erik/mobibot/ExceptionSanitizer.kt | 2 +- .../thauvin/erik/mobibot/FeedReaderTest.kt | 2 +- .../thauvin/erik/mobibot/LocalProperties.kt | 2 +- .../net/thauvin/erik/mobibot/PinboardTest.kt | 2 +- .../net/thauvin/erik/mobibot/UtilsTest.kt | 2 +- .../thauvin/erik/mobibot/commands/InfoTest.kt | 2 +- .../erik/mobibot/commands/RecapTest.kt | 2 +- .../commands/links/LinksManagerTest.kt | 2 +- .../erik/mobibot/commands/links/ViewTest.kt | 2 +- .../erik/mobibot/commands/seen/SeenTest.kt | 2 +- .../mobibot/commands/tell/TellMessageTest.kt | 2 +- .../commands/tell/TellMessagesMgrTest.kt | 2 +- .../erik/mobibot/entries/EntriesUtilsTest.kt | 2 +- .../erik/mobibot/entries/EntryLinkTest.kt | 2 +- .../erik/mobibot/entries/FeedMgrTest.kt | 2 +- .../thauvin/erik/mobibot/modules/CalcTest.kt | 2 +- .../erik/mobibot/modules/ChatGptTest.kt | 2 +- .../erik/mobibot/modules/CryptoPricesTest.kt | 2 +- .../mobibot/modules/CurrencyConverterTest.kt | 2 +- .../thauvin/erik/mobibot/modules/DiceTest.kt | 2 +- .../erik/mobibot/modules/GeminiTest.kt | 4 +- .../erik/mobibot/modules/GoogleSearchTest.kt | 2 +- .../thauvin/erik/mobibot/modules/JokeTest.kt | 2 +- .../erik/mobibot/modules/LookupTest.kt | 6 +- .../erik/mobibot/modules/MastodonTest.kt | 2 +- .../mobibot/modules/ModuleExceptionTest.kt | 2 +- .../thauvin/erik/mobibot/modules/PingTest.kt | 2 +- .../mobibot/modules/RockPaperScissorsTest.kt | 2 +- .../erik/mobibot/modules/StockQuoteTest.kt | 2 +- .../erik/mobibot/modules/Weather2Test.kt | 2 +- .../erik/mobibot/modules/WolframAlphaTest.kt | 2 +- .../erik/mobibot/modules/WordTimeTest.kt | 2 +- .../thauvin/erik/mobibot/msg/MessageTest.kt | 2 +- 102 files changed, 344 insertions(+), 109 deletions(-) create mode 100644 .idea/intellij-javadocs-4.0.1.xml diff --git a/.idea/intellij-javadocs-4.0.1.xml b/.idea/intellij-javadocs-4.0.1.xml new file mode 100644 index 0000000..dd24abe --- /dev/null +++ b/.idea/intellij-javadocs-4.0.1.xml @@ -0,0 +1,204 @@ + + + + + UPDATE + false + true + + FIELD + METHOD + TYPE + + + PROTECTED + DEFAULT + PUBLIC + + + + + + ^.*(public|protected|private)*.+interface\s+\w+.* + /**\n + * The interface ${name}.\n +<#if element.typeParameters?has_content> * \n +</#if> +<#list element.typeParameters as typeParameter> + * @param <${typeParameter.name}> the type parameter\n +</#list> + */ + + + ^.*(public|protected|private)*.+enum\s+\w+.* + /**\n + * The enum ${name}.\n + */ + + + ^.*(public|protected|private)*.+class\s+\w+.* + /**\n + * The type ${name}.\n +<#if element.typeParameters?has_content> * \n +</#if> +<#list element.typeParameters as typeParameter> + * @param <${typeParameter.name}> the type parameter\n +</#list> + */ + + + .+ + /**\n + * The type ${name}.\n + */ + + + + + .+ + /**\n + * Instantiates a new ${name}.\n +<#if element.parameterList.parameters?has_content> + *\n +</#if> +<#list element.parameterList.parameters as parameter> + * @param ${parameter.name} the ${paramNames[parameter.name]}\n +</#list> +<#if element.throwsList.referenceElements?has_content> + *\n +</#if> +<#list element.throwsList.referenceElements as exception> + * @throws ${exception.referenceName} the ${exceptionNames[exception.referenceName]}\n +</#list> + */ + + + + + ^.*(public|protected|private)*\s*.*(\w(\s*<.+>)*)+\s+get\w+\s*\(.*\).+ + /**\n + * Gets ${partName}.\n +<#if element.typeParameters?has_content> * \n +</#if> +<#list element.typeParameters as typeParameter> + * @param <${typeParameter.name}> the type parameter\n +</#list> +<#if element.parameterList.parameters?has_content> + *\n +</#if> +<#list element.parameterList.parameters as parameter> + * @param ${parameter.name} the ${paramNames[parameter.name]}\n +</#list> +<#if isNotVoid> + *\n + * @return the ${partName}\n +</#if> +<#if element.throwsList.referenceElements?has_content> + *\n +</#if> +<#list element.throwsList.referenceElements as exception> + * @throws ${exception.referenceName} the ${exceptionNames[exception.referenceName]}\n +</#list> + */ + + + ^.*(public|protected|private)*\s*.*(void|\w(\s*<.+>)*)+\s+set\w+\s*\(.*\).+ + /**\n + * Sets ${partName}.\n +<#if element.typeParameters?has_content> * \n +</#if> +<#list element.typeParameters as typeParameter> + * @param <${typeParameter.name}> the type parameter\n +</#list> +<#if element.parameterList.parameters?has_content> + *\n +</#if> +<#list element.parameterList.parameters as parameter> + * @param ${parameter.name} the ${paramNames[parameter.name]}\n +</#list> +<#if isNotVoid> + *\n + * @return the ${partName}\n +</#if> +<#if element.throwsList.referenceElements?has_content> + *\n +</#if> +<#list element.throwsList.referenceElements as exception> + * @throws ${exception.referenceName} the ${exceptionNames[exception.referenceName]}\n +</#list> + */ + + + ^.*((public\s+static)|(static\s+public))\s+void\s+main\s*\(\s*String\s*(\[\s*\]|\.\.\.)\s+\w+\s*\).+ + /**\n + * The entry point of application.\n + + <#if element.parameterList.parameters?has_content> + *\n +</#if> + * @param ${element.parameterList.parameters[0].name} the input arguments\n +<#if element.throwsList.referenceElements?has_content> + *\n +</#if> +<#list element.throwsList.referenceElements as exception> + * @throws ${exception.referenceName} the ${exceptionNames[exception.referenceName]}\n +</#list> + */ + + + .+ + /**\n + * ${name}<#if isNotVoid> ${return}</#if>.\n +<#if element.typeParameters?has_content> * \n +</#if> +<#list element.typeParameters as typeParameter> + * @param <${typeParameter.name}> the type parameter\n +</#list> +<#if element.parameterList.parameters?has_content> + *\n +</#if> +<#list element.parameterList.parameters as parameter> + * @param ${parameter.name} the ${paramNames[parameter.name]}\n +</#list> +<#if isNotVoid> + *\n + * @return the ${return}\n +</#if> +<#if element.throwsList.referenceElements?has_content> + *\n +</#if> +<#list element.throwsList.referenceElements as exception> + * @throws ${exception.referenceName} the ${exceptionNames[exception.referenceName]}\n +</#list> + */ + + + + + ^.*(public|protected|private)*.+static.*(\w\s\w)+.+ + /**\n + * The constant ${element.getName()}.\n + */ + + + ^.*(public|protected|private)*.*(\w\s\w)+.+ + /**\n + <#if element.parent.isInterface()> + * The constant ${element.getName()}.\n +<#else> + * The ${name}.\n +</#if> */ + + + .+ + /**\n + <#if element.parent.isEnum()> + *${name} ${typeName}.\n +<#else> + * The ${name}.\n +</#if>*/ + + + + + \ No newline at end of file diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index ba67d1d..1eec4e8 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -1,7 +1,7 @@ /* * MobibotBuild.java * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -70,7 +70,7 @@ public class MobibotBuild extends Project { repositories = List.of(MAVEN_LOCAL, MAVEN_CENTRAL, new Repository("https://jitpack.io") ); - var log4j = version(2, 22, 0); + var log4j = version(2, 22, 1); var kotlin = version(1, 9, 22); scope(compile) // PircBotX @@ -83,7 +83,7 @@ public class MobibotBuild extends Project { // Google .include(dependency("com.google.code.gson", "gson", "2.10.1")) .include(dependency("com.google.guava", "guava", "33.0.0-jre")) - .include(dependency("com.google.cloud", "google-cloud-vertexai", version(0, 1, 0))) + .include(dependency("com.google.cloud", "google-cloud-vertexai", version(0, 2, 0))) // Kotlin .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlin)) .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-jdk7", kotlin)) @@ -91,7 +91,7 @@ public class MobibotBuild extends Project { .include(dependency("org.jetbrains.kotlinx", "kotlinx-coroutines-core", "1.7.3")) .include(dependency("org.jetbrains.kotlinx", "kotlinx-cli-jvm", "0.3.6")) // Logging - .include(dependency("org.slf4j", "slf4j-api", "2.0.9")) + .include(dependency("org.slf4j", "slf4j-api", "2.0.11")) .include(dependency("org.apache.logging.log4j", "log4j-api", log4j)) .include(dependency("org.apache.logging.log4j", "log4j-core", log4j)) .include(dependency("org.apache.logging.log4j", "log4j-slf4j2-impl", log4j)) @@ -101,7 +101,7 @@ public class MobibotBuild extends Project { .include(dependency("net.aksingh", "owm-japis", "2.5.3.0")) .include(dependency("net.objecthunter", "exp4j", "0.4.8")) .include(dependency("org.json", "json", "20231013")) - .include(dependency("org.jsoup", "jsoup", "1.17.1")) + .include(dependency("org.jsoup", "jsoup", "1.17.2")) // Thauvin .include(dependency("net.thauvin.erik", "cryptoprice", "1.0.2")) .include(dependency("net.thauvin.erik", "jokeapi", "0.9.1")) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt index 2c5f05d..f3ae0a3 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt @@ -1,7 +1,7 @@ /* * Addons.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt index d037e44..8716e14 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt @@ -1,7 +1,7 @@ /* * Constants.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt b/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt index d82f011..a91c6dc 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt @@ -1,7 +1,7 @@ /* * FeedReader.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt index 6b9c21a..88bed54 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt @@ -1,7 +1,7 @@ /* * Mobibot.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt index 7cb5aed..88e475e 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt @@ -1,7 +1,7 @@ /* * Pinboard.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt b/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt index f499559..13d9f52 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt @@ -14,12 +14,12 @@ import java.time.ZoneId */ object ReleaseInfo { const val PROJECT = "mobibot" - const val VERSION = "0.8.0-rc+20231224114859" + const val VERSION = "0.8.0-rc+20240116102134" @JvmField @Suppress("MagicNumber") val BUILD_DATE: LocalDateTime = LocalDateTime.ofInstant( - Instant.ofEpochMilli(1703447340121L), ZoneId.systemDefault() + Instant.ofEpochMilli(1705429295075L), ZoneId.systemDefault() ) const val WEBSITE = "https://mobitopia.org/mobibot/" diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt index e4760d2..6a8e4ff 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt @@ -1,7 +1,7 @@ /* * Utils.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/AbstractCommand.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/AbstractCommand.kt index 5f79472..5f79fab 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/AbstractCommand.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/AbstractCommand.kt @@ -1,7 +1,7 @@ /* * AbstractCommand.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/ChannelFeed.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/ChannelFeed.kt index 038e378..873d31f 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/ChannelFeed.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/ChannelFeed.kt @@ -1,7 +1,7 @@ /* * ChannelFeed.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Cycle.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Cycle.kt index 9608ca8..88b6c6d 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Cycle.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Cycle.kt @@ -1,7 +1,7 @@ /* * Cycle.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Die.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Die.kt index f271bfa..e4e111d 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Die.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Die.kt @@ -1,7 +1,7 @@ /* * Die.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt index 2109693..6dfff07 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt @@ -1,7 +1,7 @@ /* * Ignore.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Info.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Info.kt index ed0b6ef..4fae22f 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Info.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Info.kt @@ -1,7 +1,7 @@ /* * Info.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Me.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Me.kt index ec7823b..3495b28 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Me.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Me.kt @@ -1,7 +1,7 @@ /* * Me.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Modules.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Modules.kt index b2293b0..314ce99 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Modules.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Modules.kt @@ -1,7 +1,7 @@ /* * Modules.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Msg.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Msg.kt index 20a6635..bddd56c 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Msg.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Msg.kt @@ -1,7 +1,7 @@ /* * Msg.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Nick.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Nick.kt index 85a03ab..59b474a 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Nick.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Nick.kt @@ -1,7 +1,7 @@ /* * Nick.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Recap.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Recap.kt index 77154c7..886b26c 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Recap.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Recap.kt @@ -1,7 +1,7 @@ /* * Recap.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Say.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Say.kt index 7f76d35..90f3c04 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Say.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Say.kt @@ -1,7 +1,7 @@ /* * Say.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Users.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Users.kt index 33d6fef..54a85b2 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Users.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Users.kt @@ -1,7 +1,7 @@ /* * Users.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Versions.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Versions.kt index 4594da3..f422566 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Versions.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Versions.kt @@ -1,7 +1,7 @@ /* * Versions.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Comment.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Comment.kt index 1443d44..2fade4e 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Comment.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Comment.kt @@ -1,7 +1,7 @@ /* * Comment.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManager.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManager.kt index fba6b99..ea18613 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManager.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManager.kt @@ -1,7 +1,7 @@ /* * LinksManager.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Posting.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Posting.kt index ff4278d..2d24ba7 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Posting.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Posting.kt @@ -1,7 +1,7 @@ /* * Posting.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Tags.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Tags.kt index 1662857..1a582a9 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Tags.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Tags.kt @@ -1,7 +1,7 @@ /* * Tags.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/View.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/View.kt index 825e374..e6971ef 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/View.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/View.kt @@ -1,7 +1,7 @@ /* * View.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt index cfd2c27..e51a6bf 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt @@ -1,7 +1,7 @@ /* * NickComparator.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt index c9ee0f3..1ad12f6 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt @@ -1,7 +1,7 @@ /* * Seen.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt index 7924977..69923db 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt @@ -1,7 +1,7 @@ /* * SeenNick.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt index 061ca6a..790ce0e 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt @@ -1,7 +1,7 @@ /* * Tell.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellManager.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellManager.kt index b65a4da..f34af98 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellManager.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellManager.kt @@ -1,7 +1,7 @@ /* * TellManager.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt index d17fbb5..ac15595 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt @@ -1,7 +1,7 @@ /* * TellMessage.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/Entries.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/Entries.kt index e8676ec..676fbee 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/Entries.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/Entries.kt @@ -1,7 +1,7 @@ /* * Entries.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt index 9c09626..ea536bc 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt @@ -1,7 +1,7 @@ /* * EntriesUtils.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryComment.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryComment.kt index e18d692..d9d5587 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryComment.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryComment.kt @@ -1,7 +1,7 @@ /* * EntryComment.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt index 4a69446..c88f8a4 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt @@ -1,7 +1,7 @@ /* * EntryLink.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt index f786cb2..4dc8e9e 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt @@ -1,7 +1,7 @@ /* * FeedsManager.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/AbstractModule.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/AbstractModule.kt index 8c8e736..17dbde2 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/AbstractModule.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/AbstractModule.kt @@ -1,7 +1,7 @@ /* * AbstractModule.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Calc.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Calc.kt index b7aae28..b5fe5b1 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Calc.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Calc.kt @@ -1,7 +1,7 @@ /* * Calc.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt index e2ad717..b94b5d7 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt @@ -1,7 +1,7 @@ /* * ChatGpt.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt index 4614a4c..fe95fe0 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt @@ -1,7 +1,7 @@ /* * CryptoPrices.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt index da0efd8..4fb7555 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt @@ -1,7 +1,7 @@ /* * CurrencyConverter.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Dice.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Dice.kt index 8420fb1..b6d69ec 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Dice.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Dice.kt @@ -1,7 +1,7 @@ /* * Dice.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini.kt index 6f9b5ff..18db66d 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini.kt @@ -1,3 +1,34 @@ +/* + * Gemini.kt + * + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + package net.thauvin.erik.mobibot.modules import com.google.cloud.vertexai.VertexAI @@ -63,7 +94,7 @@ class Gemini : AbstractModule() { */ const val MAX_TOKENS_PROP = "gemini-max-tokens" - // ChatGPT command + // Gemini command private const val GEMINI_CMD = "gemini" @JvmStatic diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt index f426d1e..1611130 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt @@ -1,7 +1,7 @@ /* * GoogleSearch.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Joke.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Joke.kt index 2760fa7..1c6a5eb 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Joke.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Joke.kt @@ -1,7 +1,7 @@ /* * Joke.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Lookup.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Lookup.kt index 9ab2ead..baeebba 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Lookup.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Lookup.kt @@ -1,7 +1,7 @@ /* * Lookup.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Mastodon.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Mastodon.kt index 3be3a5f..166e39f 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Mastodon.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Mastodon.kt @@ -1,7 +1,7 @@ /* * Mastodon.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ModuleException.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ModuleException.kt index a7416c2..32240ca 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ModuleException.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ModuleException.kt @@ -1,7 +1,7 @@ /* * ModuleException.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Ping.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Ping.kt index 944dbc1..4b56df5 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Ping.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Ping.kt @@ -1,7 +1,7 @@ /* * Ping.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt index a299d8d..13afbb7 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt @@ -1,7 +1,7 @@ /* * RockPaperScissors.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt index dcae5e7..13b9329 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt @@ -1,7 +1,7 @@ /* * StockQuote.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/War.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/War.kt index 8799279..e0fd947 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/War.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/War.kt @@ -1,7 +1,7 @@ /* * War.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt index 80a06fa..21bf0ae 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt @@ -1,7 +1,7 @@ /* * Weather2.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt index a72efab..ba88711 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt @@ -1,7 +1,7 @@ /* * WolframAlpha.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WorldTime.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WorldTime.kt index 18072bc..8978275 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WorldTime.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WorldTime.kt @@ -1,7 +1,7 @@ /* * WorldTime.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/ErrorMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/ErrorMessage.kt index 0607936..abcd043 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/ErrorMessage.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/msg/ErrorMessage.kt @@ -1,7 +1,7 @@ /* * ErrorMessage.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/Message.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/Message.kt index d41ec8c..4b788ba 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/Message.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/msg/Message.kt @@ -1,7 +1,7 @@ /* * Message.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/NoticeMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/NoticeMessage.kt index 037d504..ea11c9c 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/NoticeMessage.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/msg/NoticeMessage.kt @@ -1,7 +1,7 @@ /* * NoticeMessage.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/PrivateMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/PrivateMessage.kt index b424fdf..27b1cbd 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/PrivateMessage.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/msg/PrivateMessage.kt @@ -1,7 +1,7 @@ /* * PrivateMessage.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/PublicMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/PublicMessage.kt index 9c5e088..ae909f6 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/PublicMessage.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/msg/PublicMessage.kt @@ -1,7 +1,7 @@ /* * PublicMessage.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialManager.kt b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialManager.kt index 91f2dd9..c785106 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialManager.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialManager.kt @@ -1,7 +1,7 @@ /* * SocialManager.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialModule.kt b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialModule.kt index b594670..a13b429 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialModule.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialModule.kt @@ -1,7 +1,7 @@ /* * SocialModule.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialTimer.kt b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialTimer.kt index 3fd315e..e722ed8 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialTimer.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialTimer.kt @@ -1,7 +1,7 @@ /* * SocialTimer.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt index 9dd6034..4555884 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt @@ -1,7 +1,7 @@ /* * AddonsTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCi.kt b/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCi.kt index 22b0146..8d73a5e 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCi.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCi.kt @@ -1,7 +1,7 @@ /* * DisableOnCi.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCiCondition.kt b/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCiCondition.kt index 1d9baf4..b0f4771 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCiCondition.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCiCondition.kt @@ -1,7 +1,7 @@ /* * DisableOnCiCondition.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/ExceptionSanitizer.kt b/src/test/kotlin/net/thauvin/erik/mobibot/ExceptionSanitizer.kt index a3994ec..d1ca71d 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/ExceptionSanitizer.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/ExceptionSanitizer.kt @@ -1,7 +1,7 @@ /* * ExceptionSanitizer.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt index bf4408f..1cb2645 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt @@ -1,7 +1,7 @@ /* * FeedReaderTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/LocalProperties.kt b/src/test/kotlin/net/thauvin/erik/mobibot/LocalProperties.kt index c039d74..c290262 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/LocalProperties.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/LocalProperties.kt @@ -1,7 +1,7 @@ /* * LocalProperties.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/PinboardTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/PinboardTest.kt index 3b81950..7e56912 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/PinboardTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/PinboardTest.kt @@ -1,7 +1,7 @@ /* * PinboardTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt index a65b3a5..49ee7fa 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt @@ -1,7 +1,7 @@ /* * UtilsTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/InfoTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/InfoTest.kt index 99ba951..add701e 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/InfoTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/InfoTest.kt @@ -1,7 +1,7 @@ /* * InfoTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/RecapTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/RecapTest.kt index b6fbbff..875342b 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/RecapTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/RecapTest.kt @@ -1,7 +1,7 @@ /* * RecapTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt index fa2bb70..59338f4 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt @@ -1,7 +1,7 @@ /* * LinksManagerTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/ViewTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/ViewTest.kt index e315891..9eb433a 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/ViewTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/ViewTest.kt @@ -1,7 +1,7 @@ /* * ViewTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt index 62a1db7..6d5ba78 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt @@ -1,7 +1,7 @@ /* * SeenTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt index 69bc2e9..33b3598 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt @@ -1,7 +1,7 @@ /* * TellMessageTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt index e3c9c1f..d7bde4c 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt @@ -1,7 +1,7 @@ /* * TellMessagesMgrTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt index 0ad26b5..983e225 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt @@ -1,7 +1,7 @@ /* * EntriesUtilsTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt index 3a3bdda..577f425 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt @@ -1,7 +1,7 @@ /* * EntryLinkTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt index b56e6ed..d2b959e 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt @@ -1,7 +1,7 @@ /* * FeedMgrTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt index 04afe8c..e7ef601 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt @@ -1,7 +1,7 @@ /* * CalcTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt index 7180c13..e38e81b 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt @@ -1,7 +1,7 @@ /* * ChatGptTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt index 10b3a43..0e2ef84 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt @@ -1,7 +1,7 @@ /* * CryptoPricesTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt index 8ab64c0..5ebb7dc 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt @@ -1,7 +1,7 @@ /* * CurrencyConverterTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/DiceTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/DiceTest.kt index 8bafede..007f22f 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/DiceTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/DiceTest.kt @@ -1,7 +1,7 @@ /* * DiceTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/GeminiTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/GeminiTest.kt index 28845a9..db69fe7 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/GeminiTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/GeminiTest.kt @@ -1,7 +1,7 @@ /* - * ChatGptTest.kt + * GeminiTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt index 4942266..752b49e 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt @@ -1,7 +1,7 @@ /* * GoogleSearchTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/JokeTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/JokeTest.kt index 441d435..118d736 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/JokeTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/JokeTest.kt @@ -1,7 +1,7 @@ /* * JokeTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt index 8699c0f..048d91a 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt @@ -1,7 +1,7 @@ /* * LookupTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -44,8 +44,8 @@ class LookupTest { var result = nslookup("apple.com") assertThat(result, "lookup(apple.com)").contains("17.253.144.10") - result = nslookup("204.122.16.136") - assertThat(result, "lookup(204.122.16.136)").contains("nix3.thauvin.us") + result = nslookup("37.27.52.13") + assertThat(result, "lookup(37.27.52.13)").contains("nix4.thauvin.us") } @Test diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt index f4b5e99..11d4a51 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt @@ -1,7 +1,7 @@ /* * MastodonTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt index 416b3ab..ff706fd 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt @@ -1,7 +1,7 @@ /* * ModuleExceptionTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/PingTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/PingTest.kt index bbf9eb1..5532e30 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/PingTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/PingTest.kt @@ -1,7 +1,7 @@ /* * PingTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt index f836b0e..0e4b4ec 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt @@ -1,7 +1,7 @@ /* * RockPaperScissorsTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt index 0816b17..3fe9189 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt @@ -1,7 +1,7 @@ /* * StockQuoteTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt index 7ae2b83..f4f85f8 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt @@ -1,7 +1,7 @@ /* * Weather2Test.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt index 3bfe0d1..4f827bb 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt @@ -1,7 +1,7 @@ /* * WolframAlphaTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt index ae40e3a..1211ea4 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt @@ -1,7 +1,7 @@ /* * WordTimeTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/msg/MessageTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/msg/MessageTest.kt index 32a0495..44054f1 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/msg/MessageTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/msg/MessageTest.kt @@ -1,7 +1,7 @@ /* * MessageTest.kt * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: From d371bf5a01eea11a733788e9e0828dd614cd771a Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Wed, 31 Jan 2024 15:55:32 -0800 Subject: [PATCH 752/844] Bumped bld to 1.8.0 --- .idea/libraries/bld.xml | 4 ++-- .vscode/settings.json | 2 +- README.md | 1 + lib/bld/bld-wrapper.jar | Bin 27321 -> 27293 bytes lib/bld/bld-wrapper.properties | 10 +++++----- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/.idea/libraries/bld.xml b/.idea/libraries/bld.xml index ca84ff0..bff4f62 100644 --- a/.idea/libraries/bld.xml +++ b/.idea/libraries/bld.xml @@ -2,12 +2,12 @@ - + - + diff --git a/.vscode/settings.json b/.vscode/settings.json index 133aa45..5633e79 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,7 +7,7 @@ ], "java.configuration.updateBuildConfiguration": "automatic", "java.project.referencedLibraries": [ - "${HOME}/.bld/dist/bld-1.7.5.jar", + "${HOME}/.bld/dist/bld-1.8.0.jar", "lib/compile/*.jar", "lib/runtime/*.jar", "lib/test/*.jar" diff --git a/README.md b/README.md index b360d96..c9191ce 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ [![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) [![Kotlin](https://img.shields.io/badge/kotlin-1.9.21-7f52ff.svg)](https://kotlinlang.org) +[![bld](https://img.shields.io/badge/1.8.0-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ethauvin_mobibot&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=ethauvin_mobibot) [![GitHub CI](https://github.com/ethauvin/mobibot/actions/workflows/bld.yml/badge.svg)](https://github.com/ethauvin/mobibot/actions/workflows/bld.yml) [![CircleCI](https://circleci.com/gh/ethauvin/mobibot/tree/master.svg?style=shield)](https://circleci.com/gh/ethauvin/mobibot/tree/master) diff --git a/lib/bld/bld-wrapper.jar b/lib/bld/bld-wrapper.jar index d17ad8982355ae5516129c6b07841609641eb492..1ae4f55822672a66d89f6c692ffc7f10b2d438c9 100644 GIT binary patch delta 25301 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 diff --git a/lib/bld/bld-wrapper.properties b/lib/bld/bld-wrapper.properties index e219f09..90471f8 100644 --- a/lib/bld/bld-wrapper.properties +++ b/lib/bld/bld-wrapper.properties @@ -1,10 +1,10 @@ bld.downloadExtensionJavadoc=false bld.downloadExtensionSources=true -bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.1 -bld.extensions=com.uwyn.rife2:bld-generated-version:0.9.3 -bld.extensions-kotlin=com.uwyn.rife2:bld-kotlin:0.9.0-SNAPSHOT -bld.extensions-detekt=com.uwyn.rife2:bld-detekt:0.9.0-SNAPSHOT +bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.2 +bld.extensions=com.uwyn.rife2:bld-generated-version:0.9.4 +bld.extensions-kotlin=com.uwyn.rife2:bld-kotlin:0.9.0 +bld.extensions-detekt=com.uwyn.rife2:bld-detekt:0.9.0 bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES bld.downloadLocation= bld.sourceDirectories= -bld.version=1.7.5 +bld.version=1.8.0 From 6c2338b8b6f1852e27bac9c1753197591eff2baf Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Mon, 5 Feb 2024 17:42:48 -0800 Subject: [PATCH 753/844] Bumped depedencies --- lib/bld/bld-wrapper.jar | Bin 27293 -> 27293 bytes lib/bld/bld-wrapper.properties | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/bld/bld-wrapper.jar b/lib/bld/bld-wrapper.jar index 1ae4f55822672a66d89f6c692ffc7f10b2d438c9..5e76a01d101edb93ddf297aa6a5ff753385cc8f4 100644 GIT binary patch delta 131 zcmbPxm2vJ>M&1B#W)=|!4h{|mg?^Wbymib#YGa?MF^Jy0%($Bg%rG(gr3+>lrkrO4 wGnms1!BUgWGweYElPfcv!SwzNPcY4$83Lx0GF`#+s?0cuc$Pnyj?Hoa047K%xBvhE delta 131 zcmbPxm2vJ>M&1B#W)=|!4h{|m!HsqkdFz;g)W$whV-UT0nQ=E0m|C<08is7ZU6uP diff --git a/lib/bld/bld-wrapper.properties b/lib/bld/bld-wrapper.properties index 90471f8..77cb51b 100644 --- a/lib/bld/bld-wrapper.properties +++ b/lib/bld/bld-wrapper.properties @@ -3,7 +3,7 @@ bld.downloadExtensionSources=true bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.2 bld.extensions=com.uwyn.rife2:bld-generated-version:0.9.4 bld.extensions-kotlin=com.uwyn.rife2:bld-kotlin:0.9.0 -bld.extensions-detekt=com.uwyn.rife2:bld-detekt:0.9.0 +bld.extensions-detekt=com.uwyn.rife2:bld-detekt:0.9.1 bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES bld.downloadLocation= bld.sourceDirectories= From 6da6783395e977b43c7f5572c3f53cbbae4512aa Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Mon, 5 Feb 2024 17:43:06 -0800 Subject: [PATCH 754/844] Minor cleanups --- .circleci/config.yml | 2 +- .gitlab-ci.yml | 3 +++ .../java/net/thauvin/erik/MobibotBuild.java | 24 +++++++++---------- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 77889be..09d8896 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -6,7 +6,7 @@ defaults: &defaults TERM: dumb CI_NAME: "CircleCI" -defaults_gradle: &defaults_bld +defaults_bld: &defaults_bld steps: - checkout - run: diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 052df48..2398bba 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,5 +1,8 @@ image: openjdk:17 +variables: + CI_NAME: "GitLab CI" + stages: - test diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index 1eec4e8..024b908 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -50,8 +50,7 @@ import java.util.ArrayList; import java.util.List; import java.util.jar.Attributes; -import static rife.bld.dependencies.Repository.MAVEN_CENTRAL; -import static rife.bld.dependencies.Repository.MAVEN_LOCAL; +import static rife.bld.dependencies.Repository.*; import static rife.bld.dependencies.Scope.compile; import static rife.bld.dependencies.Scope.test; @@ -67,8 +66,11 @@ public class MobibotBuild extends Project { javaRelease = 17; downloadSources = true; autoDownloadPurge = true; - repositories = List.of(MAVEN_LOCAL, MAVEN_CENTRAL, new Repository("https://jitpack.io") - ); + repositories = List.of( + MAVEN_LOCAL, + MAVEN_CENTRAL, + new Repository("https://jitpack.io"), + SONATYPE_SNAPSHOTS_LEGACY); var log4j = version(2, 22, 1); var kotlin = version(1, 9, 22); @@ -83,15 +85,13 @@ public class MobibotBuild extends Project { // Google .include(dependency("com.google.code.gson", "gson", "2.10.1")) .include(dependency("com.google.guava", "guava", "33.0.0-jre")) - .include(dependency("com.google.cloud", "google-cloud-vertexai", version(0, 2, 0))) + .include(dependency("com.google.cloud", "google-cloud-vertexai", version(0, 3, 0))) // Kotlin .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlin)) - .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-jdk7", kotlin)) - .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-jdk8", kotlin)) .include(dependency("org.jetbrains.kotlinx", "kotlinx-coroutines-core", "1.7.3")) .include(dependency("org.jetbrains.kotlinx", "kotlinx-cli-jvm", "0.3.6")) // Logging - .include(dependency("org.slf4j", "slf4j-api", "2.0.11")) + .include(dependency("org.slf4j", "slf4j-api", "2.0.12")) .include(dependency("org.apache.logging.log4j", "log4j-api", log4j)) .include(dependency("org.apache.logging.log4j", "log4j-core", log4j)) .include(dependency("org.apache.logging.log4j", "log4j-slf4j2-impl", log4j)) @@ -103,15 +103,15 @@ public class MobibotBuild extends Project { .include(dependency("org.json", "json", "20231013")) .include(dependency("org.jsoup", "jsoup", "1.17.2")) // Thauvin - .include(dependency("net.thauvin.erik", "cryptoprice", "1.0.2")) + .include(dependency("net.thauvin.erik", "cryptoprice", "1.0.3-SNAPSHOT")) .include(dependency("net.thauvin.erik", "jokeapi", "0.9.1")) - .include(dependency("net.thauvin.erik", "pinboard-poster", "1.1.1")) + .include(dependency("net.thauvin.erik", "pinboard-poster", "1.1.2-SNAPSHOT")) .include(dependency("net.thauvin.erik.urlencoder", "urlencoder-lib-jvm", "1.4.0")); scope(test) .include(dependency("com.willowtreeapps.assertk", "assertk-jvm", version(0, 28, 0))) .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", kotlin)) - .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 10, 1))) - .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 10, 1))); + .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 10, 2))) + .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 10, 2))); List jars = new ArrayList<>(); runtimeClasspathJars().forEach(f -> jars.add("./lib/" + f.getName())); From 69c18841bc5dccd682f4a7240cac1cc7b79d59ad Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Fri, 9 Feb 2024 01:14:52 -0800 Subject: [PATCH 755/844] Bumped depencendies (common-codec, org.json) --- .vscode/settings.json | 2 ++ src/bld/java/net/thauvin/erik/MobibotBuild.java | 5 ++--- src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 5633e79..1b057c3 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,7 +8,9 @@ "java.configuration.updateBuildConfiguration": "automatic", "java.project.referencedLibraries": [ "${HOME}/.bld/dist/bld-1.8.0.jar", + "lib/bld/*.jar", "lib/compile/*.jar", + "lib/provided/*.jar", "lib/runtime/*.jar", "lib/test/*.jar" ] diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index 024b908..3977d27 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -80,14 +80,13 @@ public class MobibotBuild extends Project { // Commons (mostly for PircBotX) .include(dependency("org.apache.commons", "commons-lang3", "3.14.0")) .include(dependency("org.apache.commons", "commons-text", "1.11.0")) - .include(dependency("commons-codec", "commons-codec", "1.16.0")) + .include(dependency("commons-codec", "commons-codec", "1.16.1")) .include(dependency("commons-net", "commons-net", "3.10.0")) // Google .include(dependency("com.google.code.gson", "gson", "2.10.1")) .include(dependency("com.google.guava", "guava", "33.0.0-jre")) .include(dependency("com.google.cloud", "google-cloud-vertexai", version(0, 3, 0))) // Kotlin - .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlin)) .include(dependency("org.jetbrains.kotlinx", "kotlinx-coroutines-core", "1.7.3")) .include(dependency("org.jetbrains.kotlinx", "kotlinx-cli-jvm", "0.3.6")) // Logging @@ -100,7 +99,7 @@ public class MobibotBuild extends Project { .include(dependency("com.squareup.okhttp3", "okhttp", "4.12.0")) .include(dependency("net.aksingh", "owm-japis", "2.5.3.0")) .include(dependency("net.objecthunter", "exp4j", "0.4.8")) - .include(dependency("org.json", "json", "20231013")) + .include(dependency("org.json", "json", "20240205")) .include(dependency("org.jsoup", "jsoup", "1.17.2")) // Thauvin .include(dependency("net.thauvin.erik", "cryptoprice", "1.0.3-SNAPSHOT")) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt b/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt index 13d9f52..72ba96c 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt @@ -14,12 +14,12 @@ import java.time.ZoneId */ object ReleaseInfo { const val PROJECT = "mobibot" - const val VERSION = "0.8.0-rc+20240116102134" + const val VERSION = "0.8.0-rc+20240209010856" @JvmField @Suppress("MagicNumber") val BUILD_DATE: LocalDateTime = LocalDateTime.ofInstant( - Instant.ofEpochMilli(1705429295075L), ZoneId.systemDefault() + Instant.ofEpochMilli(1707469736725L), ZoneId.systemDefault() ) const val WEBSITE = "https://mobitopia.org/mobibot/" From 26f1a2da1dd5049c5748066ec807067beb64c51a Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Fri, 9 Feb 2024 01:19:10 -0800 Subject: [PATCH 756/844] Fixed Kotlin badge version number --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c9191ce..f051559 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # mobibot [![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) -[![Kotlin](https://img.shields.io/badge/kotlin-1.9.21-7f52ff.svg)](https://kotlinlang.org) +[![Kotlin](https://img.shields.io/badge/kotlin-1.9.22-7f52ff.svg)](https://kotlinlang.org) [![bld](https://img.shields.io/badge/1.8.0-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ethauvin_mobibot&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=ethauvin_mobibot) [![GitHub CI](https://github.com/ethauvin/mobibot/actions/workflows/bld.yml/badge.svg)](https://github.com/ethauvin/mobibot/actions/workflows/bld.yml) From 8aa4dcbcce42fb44196994620cfafa6ae3f96cf7 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Fri, 9 Feb 2024 16:48:31 -0800 Subject: [PATCH 757/844] Bumped Google Cloud VertexAI dependency to 0.4.0 --- src/bld/java/net/thauvin/erik/MobibotBuild.java | 2 +- src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt | 4 ++-- src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini.kt | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index 3977d27..c1d5baa 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -85,7 +85,7 @@ public class MobibotBuild extends Project { // Google .include(dependency("com.google.code.gson", "gson", "2.10.1")) .include(dependency("com.google.guava", "guava", "33.0.0-jre")) - .include(dependency("com.google.cloud", "google-cloud-vertexai", version(0, 3, 0))) + .include(dependency("com.google.cloud", "google-cloud-vertexai", version(0, 4, 0))) // Kotlin .include(dependency("org.jetbrains.kotlinx", "kotlinx-coroutines-core", "1.7.3")) .include(dependency("org.jetbrains.kotlinx", "kotlinx-cli-jvm", "0.3.6")) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt b/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt index 72ba96c..a4d58f3 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt @@ -14,12 +14,12 @@ import java.time.ZoneId */ object ReleaseInfo { const val PROJECT = "mobibot" - const val VERSION = "0.8.0-rc+20240209010856" + const val VERSION = "0.8.0-rc+20240209164526" @JvmField @Suppress("MagicNumber") val BUILD_DATE: LocalDateTime = LocalDateTime.ofInstant( - Instant.ofEpochMilli(1707469736725L), ZoneId.systemDefault() + Instant.ofEpochMilli(1707525927076L), ZoneId.systemDefault() ) const val WEBSITE = "https://mobitopia.org/mobibot/" diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini.kt index 18db66d..b1a2c83 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini.kt @@ -33,9 +33,9 @@ package net.thauvin.erik.mobibot.modules import com.google.cloud.vertexai.VertexAI import com.google.cloud.vertexai.api.GenerationConfig -import com.google.cloud.vertexai.generativeai.preview.ChatSession -import com.google.cloud.vertexai.generativeai.preview.GenerativeModel -import com.google.cloud.vertexai.generativeai.preview.ResponseHandler +import com.google.cloud.vertexai.generativeai.ChatSession +import com.google.cloud.vertexai.generativeai.GenerativeModel +import com.google.cloud.vertexai.generativeai.ResponseHandler import net.thauvin.erik.mobibot.Utils import net.thauvin.erik.mobibot.Utils.sendMessage import org.pircbotx.hooks.types.GenericMessageEvent From 0d37c7b15250c5da643a5dc4fcb6462abcaaa12f Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 25 Feb 2024 21:24:16 -0800 Subject: [PATCH 758/844] Added the Snyk custom POM --- snyx.xml | 11 +++++++++++ src/bld/java/net/thauvin/erik/MobibotBuild.java | 14 +++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 snyx.xml diff --git a/snyx.xml b/snyx.xml new file mode 100644 index 0000000..8a129a6 --- /dev/null +++ b/snyx.xml @@ -0,0 +1,11 @@ + + + 4.0.0 + + + + + + + diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index c1d5baa..1f72ddf 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -39,11 +39,13 @@ import rife.bld.extension.DetektOperation; import rife.bld.extension.GeneratedVersionOperation; import rife.bld.extension.JacocoReportOperation; import rife.bld.operations.exceptions.ExitStatusException; +import rife.bld.publish.PomBuilder; import rife.tools.FileUtils; import rife.tools.exceptions.FileUtilsErrorException; import java.io.File; import java.io.IOException; +import java.nio.file.Path; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; @@ -72,7 +74,7 @@ public class MobibotBuild extends Project { new Repository("https://jitpack.io"), SONATYPE_SNAPSHOTS_LEGACY); - var log4j = version(2, 22, 1); + var log4j = version(2, 23, 0); var kotlin = version(1, 9, 22); scope(compile) // PircBotX @@ -85,9 +87,9 @@ public class MobibotBuild extends Project { // Google .include(dependency("com.google.code.gson", "gson", "2.10.1")) .include(dependency("com.google.guava", "guava", "33.0.0-jre")) - .include(dependency("com.google.cloud", "google-cloud-vertexai", version(0, 4, 0))) + .include(dependency("com.google.cloud", "google-cloud-vertexai", version(0, 5, 0))) // Kotlin - .include(dependency("org.jetbrains.kotlinx", "kotlinx-coroutines-core", "1.7.3")) + .include(dependency("org.jetbrains.kotlinx", "kotlinx-coroutines-core", "1.8.0")) .include(dependency("org.jetbrains.kotlinx", "kotlinx-cli-jvm", "0.3.6")) // Logging .include(dependency("org.slf4j", "slf4j-api", "2.0.12")) @@ -191,4 +193,10 @@ public class MobibotBuild extends Project { .extension(".kt") .execute(); } + + @BuildCommand(value = "snyk-pom", summary = "Generates the Snyk POM") + public void snykPom() throws FileUtilsErrorException { + PomBuilder.generateInto(publishOperation().info(), publishOperation().dependencies(), + Path.of(workDirectory.getPath(), "snyx.xml").toFile()); + } } From 2a9bb44fecff85e4ef2fd82313b68b6a7620ca43 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 25 Feb 2024 21:32:58 -0800 Subject: [PATCH 759/844] Added Root POM for Snyk --- snyx.xml => pom.xml | 0 src/bld/java/net/thauvin/erik/MobibotBuild.java | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) rename snyx.xml => pom.xml (100%) diff --git a/snyx.xml b/pom.xml similarity index 100% rename from snyx.xml rename to pom.xml diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index 1f72ddf..6f4e7cc 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -194,9 +194,9 @@ public class MobibotBuild extends Project { .execute(); } - @BuildCommand(value = "snyk-pom", summary = "Generates the Snyk POM") - public void snykPom() throws FileUtilsErrorException { + @BuildCommand(value = "root-pom", summary = "Generates the POM file in the root directory") + public void rootPom() throws FileUtilsErrorException { PomBuilder.generateInto(publishOperation().info(), publishOperation().dependencies(), - Path.of(workDirectory.getPath(), "snyx.xml").toFile()); + Path.of(workDirectory.getPath(), "pom.xml").toFile()); } } From 7931e4adbe1d96afe2af97ceb2fae7364780524a Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Mon, 26 Feb 2024 17:01:30 -0800 Subject: [PATCH 760/844] Bumped to bld 1.9.0 --- .github/workflows/bld.yml | 4 ++++ .idea/libraries/bld.xml | 4 ++-- .vscode/launch.json | 11 ----------- .vscode/settings.json | 17 ----------------- README.md | 2 +- lib/bld/bld-wrapper.jar | Bin 27293 -> 27319 bytes lib/bld/bld-wrapper.properties | 10 +++++----- .../net/thauvin/erik/mobibot/ReleaseInfo.kt | 4 ++-- 8 files changed, 14 insertions(+), 38 deletions(-) delete mode 100644 .vscode/launch.json delete mode 100644 .vscode/settings.json diff --git a/.github/workflows/bld.yml b/.github/workflows/bld.yml index 19081a4..9bd9d9d 100644 --- a/.github/workflows/bld.yml +++ b/.github/workflows/bld.yml @@ -47,6 +47,10 @@ jobs: EXCHANGERATE_API_KEY: ${{ secrets.EXCHANGERATE_API_KEY }} run: ./bld jacoco + - name: Remove pom.xml + if: success() && matrix.java-version == env.COVERAGE_SDK + run: rm -rf pom.xml + - name: SonarCloud Scan uses: sonarsource/sonarcloud-github-action@master if: success() && matrix.java-version == env.COVERAGE_SDK diff --git a/.idea/libraries/bld.xml b/.idea/libraries/bld.xml index bff4f62..0b615c1 100644 --- a/.idea/libraries/bld.xml +++ b/.idea/libraries/bld.xml @@ -2,12 +2,12 @@ - + - + diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index c6500f2..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "type": "java", - "name": "Run Tests", - "request": "launch", - "mainClass": "net.thauvin.erik.MobibotTest" - } - ] -} diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 1b057c3..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "java.project.sourcePaths": [ - "src/main/java", - "src/main/resources", - "src/test/java", - "src/bld/java" - ], - "java.configuration.updateBuildConfiguration": "automatic", - "java.project.referencedLibraries": [ - "${HOME}/.bld/dist/bld-1.8.0.jar", - "lib/bld/*.jar", - "lib/compile/*.jar", - "lib/provided/*.jar", - "lib/runtime/*.jar", - "lib/test/*.jar" - ] -} diff --git a/README.md b/README.md index f051559..0ce0853 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) [![Kotlin](https://img.shields.io/badge/kotlin-1.9.22-7f52ff.svg)](https://kotlinlang.org) -[![bld](https://img.shields.io/badge/1.8.0-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) +[![bld](https://img.shields.io/badge/1.9.0-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ethauvin_mobibot&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=ethauvin_mobibot) [![GitHub CI](https://github.com/ethauvin/mobibot/actions/workflows/bld.yml/badge.svg)](https://github.com/ethauvin/mobibot/actions/workflows/bld.yml) [![CircleCI](https://circleci.com/gh/ethauvin/mobibot/tree/master.svg?style=shield)](https://circleci.com/gh/ethauvin/mobibot/tree/master) diff --git a/lib/bld/bld-wrapper.jar b/lib/bld/bld-wrapper.jar index 5e76a01d101edb93ddf297aa6a5ff753385cc8f4..c2adfe8730e64fdc0c51dc7994d0d143787eb1e2 100644 GIT binary patch delta 25244 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

    ^*a+>tbBpHE+pL~3DbtKbopH&MqggYR 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 diff --git a/lib/bld/bld-wrapper.properties b/lib/bld/bld-wrapper.properties index 77cb51b..95b4a2e 100644 --- a/lib/bld/bld-wrapper.properties +++ b/lib/bld/bld-wrapper.properties @@ -1,10 +1,10 @@ bld.downloadExtensionJavadoc=false bld.downloadExtensionSources=true -bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.2 -bld.extensions=com.uwyn.rife2:bld-generated-version:0.9.4 -bld.extensions-kotlin=com.uwyn.rife2:bld-kotlin:0.9.0 -bld.extensions-detekt=com.uwyn.rife2:bld-detekt:0.9.1 +bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.3 +bld.extensions=com.uwyn.rife2:bld-generated-version:0.9.5 +bld.extensions-kotlin=com.uwyn.rife2:bld-kotlin:0.9.1 +bld.extensions-detekt=com.uwyn.rife2:bld-detekt:0.9.2 bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES bld.downloadLocation= bld.sourceDirectories= -bld.version=1.8.0 +bld.version=1.9.0 diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt b/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt index a4d58f3..e44a35b 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt @@ -14,12 +14,12 @@ import java.time.ZoneId */ object ReleaseInfo { const val PROJECT = "mobibot" - const val VERSION = "0.8.0-rc+20240209164526" + const val VERSION = "0.8.0-rc+20240225204340" @JvmField @Suppress("MagicNumber") val BUILD_DATE: LocalDateTime = LocalDateTime.ofInstant( - Instant.ofEpochMilli(1707525927076L), ZoneId.systemDefault() + Instant.ofEpochMilli(1708922620439L), ZoneId.systemDefault() ) const val WEBSITE = "https://mobitopia.org/mobibot/" From cf0bafff940697dfbcb7755df95bae6ae8a10ecc Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 3 Mar 2024 22:10:00 -0800 Subject: [PATCH 761/844] Reworked the ChatGPT JSON request programmatically --- .idea/misc.xml | 1 + .../java/net/thauvin/erik/MobibotBuild.java | 4 +-- .../thauvin/erik/mobibot/modules/ChatGpt.kt | 28 ++++++++----------- 3 files changed, 15 insertions(+), 18 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index 26293d3..f63c128 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -6,6 +6,7 @@ + - - - - \ No newline at end of file + diff --git a/README.md b/README.md index 4ac4370..eb38cfb 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # mobibot [![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) -[![Kotlin](https://img.shields.io/badge/kotlin-1.9.24-7f52ff.svg)](https://kotlinlang.org) +[![Kotlin](https://img.shields.io/badge/kotlin-2.0.0-7f52ff.svg)](https://kotlinlang.org) [![bld](https://img.shields.io/badge/1.9.1-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ethauvin_mobibot&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=ethauvin_mobibot) [![GitHub CI](https://github.com/ethauvin/mobibot/actions/workflows/bld.yml/badge.svg)](https://github.com/ethauvin/mobibot/actions/workflows/bld.yml) diff --git a/pom.xml b/pom.xml index df4bbe8..3ef1964 100644 --- a/pom.xml +++ b/pom.xml @@ -42,7 +42,7 @@ com.google.code.gson gson - 2.10.1 + 2.11.0 compile @@ -54,31 +54,31 @@ com.google.cloud google-cloud-vertexai - 1.3.0 + 1.4.0 compile org.jetbrains.kotlin kotlin-stdlib - 1.9.24 + 2.0.0 compile org.jetbrains.kotlin kotlin-stdlib-common - 1.9.24 + 2.0.0 compile org.jetbrains.kotlin kotlin-stdlib-jdk7 - 1.9.24 + 2.0.0 compile org.jetbrains.kotlin kotlin-stdlib-jdk8 - 1.9.24 + 2.0.0 compile diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index d2e4cb1..8a7265e 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -78,7 +78,7 @@ public class MobibotBuild extends Project { SONATYPE_SNAPSHOTS_LEGACY); var log4j = version(2, 23, 1); - var kotlin = version(1, 9, 24); + var kotlin = version(2, 0, 0); scope(compile) // PircBotX .include(dependency("com.github.pircbotx", "pircbotx", "2.3.1")) @@ -88,9 +88,9 @@ public class MobibotBuild extends Project { .include(dependency("commons-codec", "commons-codec", "1.17.0")) .include(dependency("commons-net", "commons-net", "3.10.0")) // Google - .include(dependency("com.google.code.gson", "gson", "2.10.1")) + .include(dependency("com.google.code.gson", "gson", "2.11.0")) .include(dependency("com.google.guava", "guava", "33.2.0-jre")) - .include(dependency("com.google.cloud", "google-cloud-vertexai", "1.3.0")) + .include(dependency("com.google.cloud", "google-cloud-vertexai", "1.4.0")) // Kotlin .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlin)) .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-common", kotlin)) @@ -153,7 +153,7 @@ public class MobibotBuild extends Project { @Override public void updates() throws Exception { super.updates(); - rootPom(); + pomRoot(); } @BuildCommand(summary = "Copies all needed files to the deploy directory") @@ -203,13 +203,13 @@ public class MobibotBuild extends Project { .classTemplate(new File(workDirectory(), "release-info.txt")) .className("ReleaseInfo") .packageName(pkg) - .directory(new File(srcMainDirectory(), "kotlin")) + .directory(srcMainKotlin) .extension(".kt") .execute(); } - @BuildCommand(value = "root-pom", summary = "Generates the POM file in the root directory") - public void rootPom() throws FileUtilsErrorException { + @BuildCommand(value = "pom-root", summary = "Generates the POM file in the root directory") + public void pomRoot() throws FileUtilsErrorException { PomBuilder.generateInto(publishOperation().info(), dependencies(), Path.of(workDirectory.getPath(), "pom.xml").toFile()); } From db0e4d30f1f3b4f32cad66163b121546249351d6 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Fri, 12 Jul 2024 17:42:39 -0700 Subject: [PATCH 790/844] Updated various dependencies Cleaned up CI workflows --- .circleci/config.yml | 8 ++++++++ .github/workflows/bld.yml | 5 +++-- .gitlab-ci.yml | 18 ++++++++++++++---- bitbucket-pipelines.yml | 12 +++++++++++- lib/bld/bld-wrapper.properties | 10 +++++----- pom.xml | 8 ++++---- .../java/net/thauvin/erik/MobibotBuild.java | 16 ++++++++-------- .../net/thauvin/erik/mobibot/ReleaseInfo.kt | 4 ++-- 8 files changed, 55 insertions(+), 26 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 09d8896..c5e20a6 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -9,6 +9,14 @@ defaults: &defaults defaults_bld: &defaults_bld steps: - checkout + - run: + name: Install Kotlin via SDKMAN! + command: | + curl -s "https://get.sdkman.io" | bash + echo sdkman_auto_answer=true > $HOME/.sdkman/etc/config + echo sdkman_auto_selfupdate=true >> $HOME/.sdkman/etc/config + source "$HOME/.sdkman/bin/sdkman-init.sh" + sdk install kotlin 2.0.0 - run: name: Download the bld dependencies command: ./bld download diff --git a/.github/workflows/bld.yml b/.github/workflows/bld.yml index 28175b0..21c09a8 100644 --- a/.github/workflows/bld.yml +++ b/.github/workflows/bld.yml @@ -8,10 +8,12 @@ jobs: env: COVERAGE_SDK: "17" + COVERAGE_KOTLIN: "2.0.0" strategy: matrix: java-version: [17, 21, 22] + kotlin-version: [1.9.24, 2.0.0] steps: - name: Checkout source repository @@ -48,12 +50,11 @@ jobs: run: ./bld jacoco - name: Remove pom.xml - if: success() && matrix.java-version == env.COVERAGE_SDK run: rm -rf pom.xml - name: SonarCloud Scan uses: sonarsource/sonarcloud-github-action@master - if: success() && matrix.java-version == env.COVERAGE_SDK + if: success() && matrix.java-version == env.COVERAGE_SDK && matrix.kotlin-version == env.COVERAGE_KOTLIN env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2398bba..14646f3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,4 +1,4 @@ -image: openjdk:17 +image: ubuntu:latest variables: CI_NAME: "GitLab CI" @@ -6,9 +6,19 @@ variables: stages: - test +before_script: + - apt-get update -qq && apt-get install -y curl zip + - curl -s "https://get.sdkman.io" | bash + - echo sdkman_auto_answer=true > $HOME/.sdkman/etc/config + - echo sdkman_auto_selfupdate=true >> $HOME/.sdkman/etc/config + - source "$HOME/.sdkman/bin/sdkman-init.sh" + - sdk install java 17.0.11-tem + - sdk install kotlin 2.0.0 + - source "$HOME/.sdkman/bin/sdkman-init.sh" + test: stage: test script: - - ./bld download - - ./bld compile - - ./bld test + - ./bld download + - ./bld compile + - ./bld test diff --git a/bitbucket-pipelines.yml b/bitbucket-pipelines.yml index 7c85194..5951f4b 100644 --- a/bitbucket-pipelines.yml +++ b/bitbucket-pipelines.yml @@ -1,10 +1,20 @@ -image: openjdk:17 +image: ubuntu:latest pipelines: default: - step: name: Test with bld script: + # Install Java & Kotlin via SDKMAN! + - apt-get update -qq && apt-get install -y curl zip + - curl -s "https://get.sdkman.io" | bash + - echo sdkman_auto_answer=true > $HOME/.sdkman/etc/config + - echo sdkman_auto_selfupdate=true >> $HOME/.sdkman/etc/config + - source "$HOME/.sdkman/bin/sdkman-init.sh" + - sdk install java 17.0.11-tem + - sdk install kotlin 2.0.0 + - source "$HOME/.sdkman/bin/sdkman-init.sh" + # Download, compile and test with bld - ./bld download - ./bld compile - ./bld test diff --git a/lib/bld/bld-wrapper.properties b/lib/bld/bld-wrapper.properties index 1695c0b..0aa69b0 100644 --- a/lib/bld/bld-wrapper.properties +++ b/lib/bld/bld-wrapper.properties @@ -1,10 +1,10 @@ bld.downloadExtensionJavadoc=false bld.downloadExtensionSources=true -bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.5 -bld.extensions=com.uwyn.rife2:bld-generated-version:0.9.6 -bld.extensions-kotlin=com.uwyn.rife2:bld-kotlin:0.9.8 -bld.extensions-detekt=com.uwyn.rife2:bld-detekt:0.9.4 -bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES bld.downloadLocation= +bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.4 +bld.extension-gv=com.uwyn.rife2:bld-generated-version:0.9.8-SNAPSHOT +bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.6 +bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.0.0-SNAPSHOT +bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES bld.sourceDirectories= bld.version=1.9.1 diff --git a/pom.xml b/pom.xml index 3ef1964..8fa40d6 100644 --- a/pom.xml +++ b/pom.xml @@ -36,7 +36,7 @@ commons-net commons-net - 3.10.0 + 3.11.1 compile @@ -48,13 +48,13 @@ com.google.guava guava - 33.2.0-jre + 33.2.1-jre compile com.google.cloud google-cloud-vertexai - 1.4.0 + 1.6.0 compile @@ -150,7 +150,7 @@ org.jsoup jsoup - 1.17.2 + 1.18.1 compile diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index 8a7265e..e9343c5 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -86,11 +86,11 @@ public class MobibotBuild extends Project { .include(dependency("org.apache.commons", "commons-lang3", "3.14.0")) .include(dependency("org.apache.commons", "commons-text", "1.12.0")) .include(dependency("commons-codec", "commons-codec", "1.17.0")) - .include(dependency("commons-net", "commons-net", "3.10.0")) + .include(dependency("commons-net", "commons-net", "3.11.1")) // Google .include(dependency("com.google.code.gson", "gson", "2.11.0")) - .include(dependency("com.google.guava", "guava", "33.2.0-jre")) - .include(dependency("com.google.cloud", "google-cloud-vertexai", "1.4.0")) + .include(dependency("com.google.guava", "guava", "33.2.1-jre")) + .include(dependency("com.google.cloud", "google-cloud-vertexai", "1.6.0")) // Kotlin .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlin)) .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-common", kotlin)) @@ -109,7 +109,7 @@ public class MobibotBuild extends Project { .include(dependency("net.aksingh", "owm-japis", "2.5.3.0")) .include(dependency("net.objecthunter", "exp4j", "0.4.8")) .include(dependency("org.json", "json", "20240303")) - .include(dependency("org.jsoup", "jsoup", "1.17.2")) + .include(dependency("org.jsoup", "jsoup", "1.18.1")) // Thauvin .include(dependency("net.thauvin.erik", "cryptoprice", "1.0.3-SNAPSHOT")) .include(dependency("net.thauvin.erik", "jokeapi", "0.9.2-SNAPSHOT")) @@ -118,8 +118,8 @@ public class MobibotBuild extends Project { scope(test) .include(dependency("com.willowtreeapps.assertk", "assertk-jvm", version(0, 28, 1))) .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", kotlin)) - .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 10, 2))) - .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 10, 2))); + .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 10, 3))) + .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 10, 3))); List jars = new ArrayList<>(); runtimeClasspathJars().forEach(f -> jars.add("./lib/" + f.getName())); @@ -189,7 +189,7 @@ public class MobibotBuild extends Project { } @BuildCommand(summary = "Generates JaCoCo Reports") - public void jacoco() throws IOException { + public void jacoco() throws Exception { new JacocoReportOperation() .fromProject(this) .sourceFiles(srcMainKotlin) @@ -197,7 +197,7 @@ public class MobibotBuild extends Project { } @BuildCommand(value = "release-info", summary = "Generates the ReleaseInfo class") - public void releaseInfo() { + public void releaseInfo() throws Exception { new GeneratedVersionOperation() .fromProject(this) .classTemplate(new File(workDirectory(), "release-info.txt")) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt b/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt index c892cf0..3abf162 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt @@ -14,12 +14,12 @@ import java.time.ZoneId */ object ReleaseInfo { const val PROJECT = "mobibot" - const val VERSION = "0.8.0-rc+20240509074831" + const val VERSION = "0.8.0-rc+20240712110931" @JvmField @Suppress("MagicNumber") val BUILD_DATE: LocalDateTime = LocalDateTime.ofInstant( - Instant.ofEpochMilli(1715266111851L), ZoneId.systemDefault() + Instant.ofEpochMilli(1720807771484L), ZoneId.systemDefault() ) const val WEBSITE = "https://mobitopia.org/mobibot/" From c3a8018cc39881f7f5d508583c41712575207550 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Fri, 12 Jul 2024 21:58:34 -0700 Subject: [PATCH 791/844] Cleaned up CI workflows --- .circleci/config.yml | 58 ++++++++++-------- .github/workflows/bld.yml | 48 +++++++-------- .gitlab-ci.yml | 8 +-- .idea/libraries/bld.xml | 4 +- bitbucket-pipelines.yml | 6 +- lib/bld/bld-wrapper.jar | Bin 27319 -> 29578 bytes lib/bld/bld-wrapper.properties | 2 +- .../erik/mobibot/modules/ChatGptTest.kt | 2 +- 8 files changed, 68 insertions(+), 60 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index c5e20a6..17b50f1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,4 +1,8 @@ -version: 2 +version: 2.1 + +orbs: + sdkman: joshdholtz/sdkman@0.2.0 + defaults: &defaults working_directory: ~/repo environment: @@ -6,26 +10,31 @@ defaults: &defaults TERM: dumb CI_NAME: "CircleCI" -defaults_bld: &defaults_bld - steps: - - checkout - - run: - name: Install Kotlin via SDKMAN! - command: | - curl -s "https://get.sdkman.io" | bash - echo sdkman_auto_answer=true > $HOME/.sdkman/etc/config - echo sdkman_auto_selfupdate=true >> $HOME/.sdkman/etc/config - source "$HOME/.sdkman/bin/sdkman-init.sh" - sdk install kotlin 2.0.0 - - run: - name: Download the bld dependencies - command: ./bld download - - run: - name: Compile source with bld - command: ./bld compile - - run: - name: Run tests with bld - command: ./bld test +commands: + build_and_test: + parameters: + reports-dir: + type: string + default: "build/reports/test_results" + steps: + - checkout + - sdkman/setup-sdkman + - sdkman/sdkman-install: + candidate: kotlin + version: 2.0.0 + - run: + name: Download dependencies + command: ./bld download + - run: + name: Compile source + command: ./bld compile + - run: + name: Run tests + command: ./bld jacoco -reports-dir=<< parameters.reports-dir >> + - store_test_results: + path: << parameters.reports-dir >> + - store_artifacts: + path: build/reports/jacoco/test/html jobs: bld_jdk17: @@ -34,7 +43,8 @@ jobs: docker: - image: cimg/openjdk:17.0 - <<: *defaults_bld + steps: + - build_and_test bld_jdk20: <<: *defaults @@ -42,10 +52,10 @@ jobs: docker: - image: cimg/openjdk:20.0 - <<: *defaults_bld + steps: + - build_and_test workflows: - version: 2 bld: jobs: - bld_jdk17 diff --git a/.github/workflows/bld.yml b/.github/workflows/bld.yml index 21c09a8..a3c4951 100644 --- a/.github/workflows/bld.yml +++ b/.github/workflows/bld.yml @@ -1,19 +1,29 @@ name: bld-ci -on: [push, pull_request, workflow_dispatch] +on: [ push, pull_request, workflow_dispatch ] + +env: + ALPHAVANTAGE_API_KEY: ${{ secrets.ALPHAVANTAGE_API_KEY }} + CHATGPT_API_KEY: ${{ secrets.CHATGPT_API_KEY }} + CI_NAME: "GitHub CI" + COVERAGE_JDK: "21" + COVERAGE_KOTLIN: "2.0.0" + EXCHANGERATE_API_KEY: ${{ secrets.EXCHANGERATE_API_KEY }} + KOTLIN_HOME: /usr/share/kotlinc + MASTODON_ACCESS_TOKEN: ${{ secrets.MASTODON_ACCESS_TOKEN }} + MASTODON_HANDLE: ${{ secrets.MASTODON_HANDLE }} + MASTODON_INSTANCE: ${{ secrets.MASTODON_INSTANCE }} + OWM_API_KEY: ${{ secrets.OWM_API_KEY }} + PINBOARD_API_TOKEN: ${{ secrets.PINBOARD_API_TOKEN }} jobs: build-bld-project: runs-on: ubuntu-latest - env: - COVERAGE_SDK: "17" - COVERAGE_KOTLIN: "2.0.0" - strategy: matrix: - java-version: [17, 21, 22] - kotlin-version: [1.9.24, 2.0.0] + java-version: [ 17, 21, 22 ] + kotlin-version: [ 1.9.24, 2.0.0 ] steps: - name: Checkout source repository @@ -21,40 +31,28 @@ jobs: with: fetch-depth: 0 - - name: Set up JDK ${{ matrix.java-version }} + - name: Set up JDK ${{ matrix.java-version }} with Kotlin ${{ matrix.kotlin-version }} uses: actions/setup-java@v4 with: distribution: "zulu" java-version: ${{ matrix.java-version }} - - name: Grant bld execute permission - run: chmod +x bld - - - name: Download the bld dependencies + - name: Download dependencies run: ./bld download - - name: Compile source with bld + - name: Compile source run: ./bld compile - - name: Run tests with bld - env: - CI_NAME: "GitHub CI" - ALPHAVANTAGE_API_KEY: ${{ secrets.ALPHAVANTAGE_API_KEY }} - CHATGPT_API_KEY: ${{ secrets.CHATGPT_API_KEY }} - OWM_API_KEY: ${{ secrets.OWM_API_KEY }} - PINBOARD_API_TOKEN: ${{ secrets.PINBOARD_API_TOKEN }} - MASTODON_ACCESS_TOKEN: ${{ secrets.MASTODON_ACCESS_TOKEN }} - MASTODON_HANDLE: ${{ secrets.MASTODON_HANDLE }} - MASTODON_INSTANCE: ${{ secrets.MASTODON_INSTANCE }} - EXCHANGERATE_API_KEY: ${{ secrets.EXCHANGERATE_API_KEY }} + - name: Run tests run: ./bld jacoco - name: Remove pom.xml + if: success() && matrix.java-version == env.COVERAGE_JDK && matrix.kotlin-version == env.COVERAGE_KOTLIN run: rm -rf pom.xml - name: SonarCloud Scan uses: sonarsource/sonarcloud-github-action@master - if: success() && matrix.java-version == env.COVERAGE_SDK && matrix.kotlin-version == env.COVERAGE_KOTLIN + if: success() && matrix.java-version == env.COVERAGE_JDK && matrix.kotlin-version == env.COVERAGE_KOTLIN env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 14646f3..10b9b0f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,4 +1,4 @@ -image: ubuntu:latest +image: fedora:latest variables: CI_NAME: "GitLab CI" @@ -7,13 +7,13 @@ stages: - test before_script: - - apt-get update -qq && apt-get install -y curl zip + - dnf -qy update && dnf -y install zip - curl -s "https://get.sdkman.io" | bash - echo sdkman_auto_answer=true > $HOME/.sdkman/etc/config - echo sdkman_auto_selfupdate=true >> $HOME/.sdkman/etc/config - source "$HOME/.sdkman/bin/sdkman-init.sh" - - sdk install java 17.0.11-tem - - sdk install kotlin 2.0.0 + - sdk install java + - sdk install kotlin - source "$HOME/.sdkman/bin/sdkman-init.sh" test: diff --git a/.idea/libraries/bld.xml b/.idea/libraries/bld.xml index a2969be..2fb5ff0 100644 --- a/.idea/libraries/bld.xml +++ b/.idea/libraries/bld.xml @@ -2,12 +2,12 @@ - + - + diff --git a/bitbucket-pipelines.yml b/bitbucket-pipelines.yml index 5951f4b..ace99d2 100644 --- a/bitbucket-pipelines.yml +++ b/bitbucket-pipelines.yml @@ -5,14 +5,14 @@ pipelines: - step: name: Test with bld script: - # Install Java & Kotlin via SDKMAN! + # Install latest Java & Kotlin via SDKMAN! - apt-get update -qq && apt-get install -y curl zip - curl -s "https://get.sdkman.io" | bash - echo sdkman_auto_answer=true > $HOME/.sdkman/etc/config - echo sdkman_auto_selfupdate=true >> $HOME/.sdkman/etc/config - source "$HOME/.sdkman/bin/sdkman-init.sh" - - sdk install java 17.0.11-tem - - sdk install kotlin 2.0.0 + - sdk install java + - sdk install kotlin - source "$HOME/.sdkman/bin/sdkman-init.sh" # Download, compile and test with bld - ./bld download diff --git a/lib/bld/bld-wrapper.jar b/lib/bld/bld-wrapper.jar index 8a6c6415420d24c2f97b665923c81552b4add950..f46bb77a290005df0476b73c34554b894620bf01 100644 GIT binary patch delta 27557 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 A#Q*>R delta 25368 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 diff --git a/lib/bld/bld-wrapper.properties b/lib/bld/bld-wrapper.properties index 0aa69b0..e9d6ec3 100644 --- a/lib/bld/bld-wrapper.properties +++ b/lib/bld/bld-wrapper.properties @@ -7,4 +7,4 @@ bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.6 bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.0.0-SNAPSHOT bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES bld.sourceDirectories= -bld.version=1.9.1 +bld.version=2.0.0-SNAPSHOT diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt index c031295..1809a9f 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt @@ -49,7 +49,7 @@ class ChatGptTest : LocalProperties() { @Test fun testChatOnCoverage() { - if (System.getenv("CI") == null || System.getenv("COVERAGE_SDK") != null) { + if (System.getenv("CI") == null || System.getenv("COVERAGE_JDK") != null) { assertThat( ChatGpt.chat("how do I encode a URL in java?", getProperty(ChatGpt.API_KEY_PROP), 60) ).contains("URLEncoder") From 8d9acd8184f2c36abfde1ab37efb00c2b95f8636 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Mon, 15 Jul 2024 21:00:28 -0700 Subject: [PATCH 792/844] Moved to Gemini 1.5 Flash --- .../thauvin/erik/mobibot/modules/Gemini.kt | 28 +++++++++---------- .../erik/mobibot/modules/GeminiTest.kt | 2 +- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini.kt index c0faefa..2e4ed91 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini.kt @@ -35,7 +35,6 @@ import com.google.cloud.vertexai.VertexAI import com.google.cloud.vertexai.api.GenerationConfig import com.google.cloud.vertexai.api.HarmCategory import com.google.cloud.vertexai.api.SafetySetting -import com.google.cloud.vertexai.generativeai.ChatSession import com.google.cloud.vertexai.generativeai.GenerativeModel import com.google.cloud.vertexai.generativeai.ResponseHandler import net.thauvin.erik.mobibot.Utils @@ -57,7 +56,7 @@ class Gemini : AbstractModule() { val answer = chat( args.trim(), properties[PROJECT_ID_PROP], - properties[LOCATION_PROPR], + properties[LOCATION_PROP], properties.getOrDefault(MAX_TOKENS_PROP, "1024").toInt() ) if (!answer.isNullOrEmpty()) { @@ -83,17 +82,17 @@ class Gemini : AbstractModule() { const val GEMINI_NAME = "Gemini" /** - * The Google cloud project ID. + * The Google cloud project ID property. */ const val PROJECT_ID_PROP = "gemini-project-id" /** - * The Vertex AI location. + * The Vertex AI location property. */ - const val LOCATION_PROPR = "gemini-location" + const val LOCATION_PROP = "gemini-location" /** - * The max tokens property. + * The max number of tokens property. */ const val MAX_TOKENS_PROP = "gemini-max-tokens" @@ -112,31 +111,30 @@ class Gemini : AbstractModule() { try { VertexAI(projectId, location).use { vertexAI -> val generationConfig = GenerationConfig.newBuilder().setMaxOutputTokens(maxToken).build() - val safetySettings = Arrays.asList( + val safetySettings = listOf( SafetySetting.newBuilder() .setCategory(HarmCategory.HARM_CATEGORY_HATE_SPEECH) - .setThreshold(SafetySetting.HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE) + .setThreshold(SafetySetting.HarmBlockThreshold.BLOCK_LOW_AND_ABOVE) .build(), SafetySetting.newBuilder() .setCategory(HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT) - .setThreshold(SafetySetting.HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE) + .setThreshold(SafetySetting.HarmBlockThreshold.BLOCK_LOW_AND_ABOVE) .build(), SafetySetting.newBuilder() .setCategory(HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT) - .setThreshold(SafetySetting.HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE) + .setThreshold(SafetySetting.HarmBlockThreshold.BLOCK_LOW_AND_ABOVE) .build(), SafetySetting.newBuilder() .setCategory(HarmCategory.HARM_CATEGORY_HARASSMENT) - .setThreshold(SafetySetting.HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE) + .setThreshold(SafetySetting.HarmBlockThreshold.BLOCK_LOW_AND_ABOVE) .build() ) - val model = GenerativeModel.Builder().setModelName("gemini-pro-vision") + val model = GenerativeModel.Builder().setModelName("gemini-1.5-flash-001") .setGenerationConfig(generationConfig) .setVertexAi(vertexAI).build() .withSafetySettings(safetySettings) - val session = ChatSession(model) - val response = session.sendMessage(query) + val response = model.generateContent(query) return ResponseHandler.getText(response) } } catch (e: Exception) { @@ -161,7 +159,7 @@ class Gemini : AbstractModule() { add(Utils.helpFormat("%c $GEMINI_CMD explain quantum computing in simple terms")) add(Utils.helpFormat("%c $GEMINI_CMD how do I make an HTTP request in Javascript?")) } - initProperties(PROJECT_ID_PROP, LOCATION_PROPR, MAX_TOKENS_PROP) + initProperties(PROJECT_ID_PROP, LOCATION_PROP, MAX_TOKENS_PROP) } } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/GeminiTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/GeminiTest.kt index db69fe7..1f0202f 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/GeminiTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/GeminiTest.kt @@ -49,7 +49,7 @@ class GeminiTest : LocalProperties() { @DisableOnCi fun chatPrompt() { val projectId = getProperty(Gemini.PROJECT_ID_PROP) - val location = getProperty(Gemini.LOCATION_PROPR) + val location = getProperty(Gemini.LOCATION_PROP) val maxTokens = getProperty(Gemini.MAX_TOKENS_PROP).toInt() assertThat( From ebf05fa398a328d8fec8867172f5ef43e7f7d273 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Mon, 15 Jul 2024 21:01:00 -0700 Subject: [PATCH 793/844] Fixed root POM generation --- pom.xml | 8 ++++---- src/bld/java/net/thauvin/erik/MobibotBuild.java | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 8fa40d6..71e21a8 100644 --- a/pom.xml +++ b/pom.xml @@ -2,10 +2,10 @@ 4.0.0 - - - - + net.thauvin.erik.mobibot + mobibot + 0.8.0-rc+20240715201342 + mobibot diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index e9343c5..5b15c86 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -210,7 +210,7 @@ public class MobibotBuild extends Project { @BuildCommand(value = "pom-root", summary = "Generates the POM file in the root directory") public void pomRoot() throws FileUtilsErrorException { - PomBuilder.generateInto(publishOperation().info(), dependencies(), - Path.of(workDirectory.getPath(), "pom.xml").toFile()); + PomBuilder.generateInto(publishOperation().fromProject(this).info(), dependencies(), + new File(workDirectory, "pom.xml")); } } From 2905dec49f58fd9916091ade8033093a09c203af Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Fri, 9 Aug 2024 18:06:24 -0700 Subject: [PATCH 794/844] Bumped bld to version 2.0.1 --- .idea/bld.xml | 6 ++++++ .idea/libraries/bld.xml | 4 ++-- lib/bld/bld-wrapper.jar | Bin 29578 -> 29577 bytes lib/bld/bld-wrapper.properties | 10 +++++----- 4 files changed, 13 insertions(+), 7 deletions(-) create mode 100644 .idea/bld.xml diff --git a/.idea/bld.xml b/.idea/bld.xml new file mode 100644 index 0000000..6600cee --- /dev/null +++ b/.idea/bld.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/libraries/bld.xml b/.idea/libraries/bld.xml index 2fb5ff0..4dd96bf 100644 --- a/.idea/libraries/bld.xml +++ b/.idea/libraries/bld.xml @@ -2,12 +2,12 @@ - + - + diff --git a/lib/bld/bld-wrapper.jar b/lib/bld/bld-wrapper.jar index f46bb77a290005df0476b73c34554b894620bf01..1d2b318f1cbb9e83f5b4e6d4d922146c95191b40 100644 GIT binary patch delta 27484 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 Date: Fri, 9 Aug 2024 18:10:59 -0700 Subject: [PATCH 795/844] Updated dependencies Bumped Kotlin to version 2.0.1 Bumped Commons Lang3 to version 3.16.0 Bumped slf4j-api to version 2.0.15 Bumped Commons Codec to version 1.17.1 Bumped Google Cloud VertexAI to version 1.7.0 --- README.md | 4 ++-- pom.xml | 18 +++++++++--------- .../java/net/thauvin/erik/MobibotBuild.java | 10 +++++----- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index eb38cfb..a4db76e 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # mobibot [![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) -[![Kotlin](https://img.shields.io/badge/kotlin-2.0.0-7f52ff.svg)](https://kotlinlang.org) -[![bld](https://img.shields.io/badge/1.9.1-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) +[![Kotlin](https://img.shields.io/badge/kotlin-2.0.10-7f52ff.svg)](https://kotlinlang.org) +[![bld](https://img.shields.io/badge/2.0.1-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ethauvin_mobibot&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=ethauvin_mobibot) [![GitHub CI](https://github.com/ethauvin/mobibot/actions/workflows/bld.yml/badge.svg)](https://github.com/ethauvin/mobibot/actions/workflows/bld.yml) [![CircleCI](https://circleci.com/gh/ethauvin/mobibot/tree/master.svg?style=shield)](https://circleci.com/gh/ethauvin/mobibot/tree/master) diff --git a/pom.xml b/pom.xml index 71e21a8..7996b05 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 net.thauvin.erik.mobibot mobibot - 0.8.0-rc+20240715201342 + 0.8.0-rc+20240809180718 mobibot @@ -18,7 +18,7 @@ org.apache.commons commons-lang3 - 3.14.0 + 3.16.0 compile @@ -30,7 +30,7 @@ commons-codec commons-codec - 1.17.0 + 1.17.1 compile @@ -54,31 +54,31 @@ com.google.cloud google-cloud-vertexai - 1.6.0 + 1.7.0 compile org.jetbrains.kotlin kotlin-stdlib - 2.0.0 + 2.0.10 compile org.jetbrains.kotlin kotlin-stdlib-common - 2.0.0 + 2.0.10 compile org.jetbrains.kotlin kotlin-stdlib-jdk7 - 2.0.0 + 2.0.10 compile org.jetbrains.kotlin kotlin-stdlib-jdk8 - 2.0.0 + 2.0.10 compile @@ -96,7 +96,7 @@ org.slf4j slf4j-api - 2.0.13 + 2.0.15 compile diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index 5b15c86..1e6649b 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -78,19 +78,19 @@ public class MobibotBuild extends Project { SONATYPE_SNAPSHOTS_LEGACY); var log4j = version(2, 23, 1); - var kotlin = version(2, 0, 0); + var kotlin = version(2, 0, 10); scope(compile) // PircBotX .include(dependency("com.github.pircbotx", "pircbotx", "2.3.1")) // Commons (mostly for PircBotX) - .include(dependency("org.apache.commons", "commons-lang3", "3.14.0")) + .include(dependency("org.apache.commons", "commons-lang3", "3.16.0")) .include(dependency("org.apache.commons", "commons-text", "1.12.0")) - .include(dependency("commons-codec", "commons-codec", "1.17.0")) + .include(dependency("commons-codec", "commons-codec", "1.17.1")) .include(dependency("commons-net", "commons-net", "3.11.1")) // Google .include(dependency("com.google.code.gson", "gson", "2.11.0")) .include(dependency("com.google.guava", "guava", "33.2.1-jre")) - .include(dependency("com.google.cloud", "google-cloud-vertexai", "1.6.0")) + .include(dependency("com.google.cloud", "google-cloud-vertexai", "1.7.0")) // Kotlin .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlin)) .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-common", kotlin)) @@ -99,7 +99,7 @@ public class MobibotBuild extends Project { .include(dependency("org.jetbrains.kotlinx", "kotlinx-coroutines-core", "1.8.1")) .include(dependency("org.jetbrains.kotlinx", "kotlinx-cli-jvm", "0.3.6")) // Logging - .include(dependency("org.slf4j", "slf4j-api", "2.0.13")) + .include(dependency("org.slf4j", "slf4j-api", "2.0.15")) .include(dependency("org.apache.logging.log4j", "log4j-api", log4j)) .include(dependency("org.apache.logging.log4j", "log4j-core", log4j)) .include(dependency("org.apache.logging.log4j", "log4j-slf4j2-impl", log4j)) From ebc3da70e4b27d4b748446c02be1fbfa319da1ee Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 8 Sep 2024 17:39:18 -0700 Subject: [PATCH 796/844] Bumped bld to version 2.1.0 --- .idea/libraries/bld.xml | 4 ++-- .idea/libraries/compile.xml | 4 ++-- .idea/libraries/runtime.xml | 4 ++-- .idea/libraries/test.xml | 4 ++-- README.md | 4 ++-- lib/bld/bld-wrapper.jar | Bin 29577 -> 30440 bytes lib/bld/bld-wrapper.properties | 10 +++++----- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/.idea/libraries/bld.xml b/.idea/libraries/bld.xml index 4dd96bf..5c4010c 100644 --- a/.idea/libraries/bld.xml +++ b/.idea/libraries/bld.xml @@ -2,12 +2,12 @@ - + - + diff --git a/.idea/libraries/compile.xml b/.idea/libraries/compile.xml index 9bd86aa..99cc0c0 100644 --- a/.idea/libraries/compile.xml +++ b/.idea/libraries/compile.xml @@ -7,7 +7,7 @@ - - + + \ No newline at end of file diff --git a/.idea/libraries/runtime.xml b/.idea/libraries/runtime.xml index 2ae5c4b..d4069f2 100644 --- a/.idea/libraries/runtime.xml +++ b/.idea/libraries/runtime.xml @@ -8,7 +8,7 @@ - - + + \ No newline at end of file diff --git a/.idea/libraries/test.xml b/.idea/libraries/test.xml index b80486a..57ed5ef 100644 --- a/.idea/libraries/test.xml +++ b/.idea/libraries/test.xml @@ -8,7 +8,7 @@ - - + + \ No newline at end of file diff --git a/README.md b/README.md index a4db76e..e438c94 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # mobibot [![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) -[![Kotlin](https://img.shields.io/badge/kotlin-2.0.10-7f52ff.svg)](https://kotlinlang.org) -[![bld](https://img.shields.io/badge/2.0.1-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) +[![Kotlin](https://img.shields.io/badge/kotlin-2.0.20-7f52ff.svg)](https://kotlinlang.org) +[![bld](https://img.shields.io/badge/2.1.0-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ethauvin_mobibot&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=ethauvin_mobibot) [![GitHub CI](https://github.com/ethauvin/mobibot/actions/workflows/bld.yml/badge.svg)](https://github.com/ethauvin/mobibot/actions/workflows/bld.yml) [![CircleCI](https://circleci.com/gh/ethauvin/mobibot/tree/master.svg?style=shield)](https://circleci.com/gh/ethauvin/mobibot/tree/master) diff --git a/lib/bld/bld-wrapper.jar b/lib/bld/bld-wrapper.jar index 1d2b318f1cbb9e83f5b4e6d4d922146c95191b40..5425f1c05b18a00f2f1d69df4fc5885b310c372a 100644 GIT binary patch delta 15855 zcmYj&WmFz9w>4UzxH~OSin}`$FFd%rySop?o#Oi7?(SOL-5rX%JA8fL`>l0vW@SxQ zvd_-RpPA(3?63pK!!t+}d1+`EEC_gbcnIkXVvSf7ADI8XV;BJ+1aIYe?1z?z&S9B2 zxIiSxKV*>p#xdFcXhI?wUsGV?A!^MtzF}g3On1ft#nu)V8Z32$PAZ!l$VSkz!xt7R z<}J%q%PJbYDk>@((p8?`4>~zn?cxx&9^N`N4?5bwUgs@lT@U@qU26|)==9F>%~GEU zz8s(5CO6$VC)fd>pPrvzbFSwXSObt8Td2psaeBa*fR9!WX)mr|ITAP60ymoM{P4(c{Q3Geu~>W zIEW@kv3w60i|Pn7jU>@Zw#*pFS<5$amuZYDGa}-goz=NsQ|M-EYwa zZsOXF?k1=$?JX9GXX4KZO#J?|w=nsS_fGw0UJN7+^C-vcpm%~S*zfdzJ5%4s(SfgP z#7OF)8Rj!mGVyECTZKY$Q;Q0iR(2@&AuBe{xarD3V(X&g*c`g`Vuz)S<_~Gumepro z-naG_$Mqc~HoyL4#Ov?XrAR^ETF0%u>e9sXZ6!VV;+p8YOQOk4Fx|NO(MuoxE-nFk zK;iXf&g^+n~2YtBQ(PrVOsondtG5 z8mp546RRjGD+}<~-mVrxJbc&&oZ?v-9&q)V!x?E8?d&Mc-zgH~x-s+W-;9ndm~_%X3~x%1JEmZ)D2wM0l>vSt&vclLxh6;)I0y+_UxEcE6Iy}X4c~@ua)!%XY!pMQZRNh1y97mIBjss6d$egj z*~CkwBY09H-y%!=(LAac&#rK;OrKyq@@|FDug3|63E(#Xg(NPK-;P0a@E9tA2xUrh zFj>2Fjc59u5&oJu=(wC*j}$IoC(_figOIm~2H!(o318DaOwa);h(N}?(RJq_DZM

    (QD6Zvw*7^l%{Y!lFB7v?Qa_La;UGqqOnMPF1$sKsF z>hq@+pV;~JScdjrdeG>HMOH^VoIbtzCoW9}`W7pj`w?Y1d zZM?6s@n2<&1<{Vqqc8zV%b84r(AoOhoPtIH3Ws}Nlbxm6!atURCwKrChR6|h ze5Pr_=iuBq#o4vE&sk1tFf$s?D?2tNyEODhr9~h?b=# zWhK^?77HD{1TlE=z$Kba$MlyS4cvXZhRuo5%c;q1XJTw7n~RiNCr{kQPblstT3k!B zU#{wK0{Wwu`%{j0&%2n8l5Yj*48ECb?A5^buB@QSJhMN5%r-X$E1S}N5drEJ-c!Zm zHsrcvDH@{!q-XxO9uUBGBzJ2d<1ql|poX_Noy57L-j-bm_$xn_m+|ImDDk31j!Jxg z3wr;o*Vena8}n$zYh|sbuRZegdAsWac}{9c0G@?T55lm2V{h>9P8N`IOZ|q42pM+l zv;K>V41%wu+alP*Jr|qh%I-NP{oQKD>{d`XKI9~2bL(WUqrA!*;y`F}iR`QSNOkvJ z%4bv`NI^4IV3`@;8I6oSkUC$UNvRiEEW*EDAS4K~Dp* zvZ~D5R-BH8uTT;4F~l&sE%OXk-qJ83dol57x4SM_E0W{~ z8&_S_8#*1N<>1AM3!ku?aU?&M}-}e|WeHdfl$>>Lo{OHAPmfB4NhO zox%>g4Kh$_F;Ug1vda^c$3e28TC}ShMYj*QgOMmf86P>()ejFcMCXEBaC4B8SW~3b ze#26blF4fAm#UE;thBtoVK5HG?B~j?8^M|faz9-WX(fu@hD@kRq^l&Q8RC;0K!tIA z;`42xmc?;daYGW#*7-yE(u6dU(3kH(Pl+w=A)5D90ZNNOmRT%bsQmcz!=1ehH|xBo zqNpyPYXP-t%`1NK@m{zRs3v%q(#_4CnI|iedLiu2)*+2r*6daMTLEmgM72ZY2Y%rt z5XSMFq>#K`j5A7BF+4+5U!Az{5>YgSr1_fkOVUNPbgNN?PRxc*?kfERTfau6{QVR| zckL*yt>5x~XGbACylB2S1a^RtSh~BdgR3G&&cn8$ns^YIL3BwlFl<#}GIWr-;~hN4m?Y`D+vy>yC&4lCly_&ncoRednjRw{vcUQDs0boj>K z35v+-wjqx;BB!GEpq9EyqT!6SqO%Iep*wcj3nAzVyS=ui@O=V$9!hX^mrKo9clxu8Yey#=x;0;#xb=k>yWIqW)tq! z*TH-um`_;f$J)tqT6Il|V#-aeK5BU(>(E6_g2u~4iK9dqS|;Vng3;PL4YA;59vTlx zT-L%U!Z&0!iV>5xv%16Ej{SxX>|3qVnCB{SXU(pwbvCxiaau&wU=ka$GAvlI0wG5G zNLMLK{h!XmM7Mb0Idx}@44bHP4N(_{JkXf*dRqH~8Y1U)l}<53v$p%@&(|(c=&nU@)E;T#d5w9sE5! z26V+K>)VDi_{qmG90-*YzOjGc_5~}I-Gu_Ax>WQHnA_It?|@PGNBCs6XHN^Mo|kb8 z>mrziqBLsfpzzV(M*fr4U|^4c`Old_SZ`0}Z(qVm6w?%$quO1c8wi*hLac;;Gbj~G zaYC$0c`vC{OOCLWvVu;Mj-*JWGwNl+P+%%%*!JL2GzaPQRI=bTcB#v(_NbIhEod!G zF1aSZ*MW`_jR2u}4fHhet{Q)S|WMp~8*)=2` zy0g<>jcF%#5J8hLfJnepRfCC0yqf4ztnv1V-Q6`}OEZC&_|J7UzkoN)>;&_kHb*x3 zS)hdf^j|)uiG$MvnBS}Wb;rU_kWJcXqtQGZ(h+bOLK?zGeAl9nMtknbiG|v9Wsggc z*-*qpBtRik^!?Un5`|v!BzPMB++MapNiM2doKAEJ&M;Ufzuj0$BeCJTg8O@|v%9I{ zlbc0eMI>eds82`2Rgn~`h}+Qp@H_U=CMzTVtG z_3%B~t%K!Nx7$JM{QMp^?|ksqFB&Q2Xh?hg8D9W6RkCotS}in>zZ%&s`;RlaK;Pna z1n|h^G4%M5#?tMbgiqMQG6%i-=_Y!h4#cC!<6n`Zt39?Sm4nZRv0&_dU0%SiKSjdp zK+T!v7_TaQ$4;MEF`xKYVpU#RZdGBaT@$P_g`*i;jswZphP( z&N_l9<3TD7Kd4-8z{POz90Bq`SY-WJ27Il`xe06TR7gCy&Gqzryn|oUUR$+vEk?@z z&NI7Fj15no4<%iDiu!aSzaO6?`!=Set`zJ*f4)aGLuSM*ffNd|O!}y9I(>! zWArus#6SI&C%mUPr?{2kbuKS{+6JEEp~+3<-rA2K!ugIT8gFI~T-Yw1rKd4Wn|V#5 zv@t3XU}Q*_XnfFz8o)o*a;%d?CH_@k=#y#MOX_Q0(uJd#u|-*QRA5B zi3`V(Tllf*Eg`U<#0z?AUQ0an1{PO(kAsoQ0*d&>1i~&A&Si;&29~{5I6Ua+ne|6H z%E`1f@r{SxuG?&%5~#D1;0)iR&-{A0FA(bB3ib4*px!~QQd7AGd~2;aXk07@qA+zK z{3JuBqh_Ed{-=z+n7(aUdP!LSCn}CPdH~JogAIBP7Mf5Sm#F?dnN%+hU~Jn%1wD~J z{iMrcC!(6dc~|<1Br_vM3W=kva7< z7Pe0>`Cj;8H!sc(L9cn#AKwIFN;DVBiy^HFe=3Z`$UNabsnL$j78T~ayMjHqIF4w3 zfjgb%0$;&=YAr@+Y>%5?za*uFF|v=%dK-=aLvj_bULArn*nx|H{fxoHWJuPmzkE;Y zu3n+KzywSFWhSPQ|K&6pu4&x~Y8S4>eq zFEGxwK*oehjm{(;%B8sLynA3v1A?CswvKq&*cNuN%l#0m!Oz;mg}xK*5G>zC11dYL2;fM-mcklYI`^u6{oc9)cD~-!b)X4#>J*1DM3D zF6~<5%=6mO+7hTokco}Mi^#CW2rQGzH{3DIJjNv?A>O$zze;c%1KBm<^d@eZGmu?! zOJsKlIr9Lz^fPm5wFr<(!I{T}2Jt#6a`}L=bjp3k_QH>~kR{s|My&lu#S5>BlB65w zUGzSKTJ>7G3^prp$*~GF3_*_^q4r8rHmmB~X^kzsAkzA3g=J8QtO95$kTqZ((#!gN zN}XSHM*>*CglaAUge{j)4yB7CZpCW4!*w*tD#cfhG{cir51NwZT&l;`}SYA6TiavNj(=s2=@kDo`;{Q~MD`}=9==W$G{ zx&;6=ddFi4FrFQuvlg}Pkt)1yVSZrEXa1V4G4jCF_KW--d&yV=(AScV$rvvHB5=ky}=7e@3;&xuv|mfY-Ly;>eBsjV*~S z)-RDV>^hbTzkB20dDgA$s2-$Pmhq^`_rwAyfg7L9?vWOp9cJk(zZ2zt<+>bfS2raVT@J4(#AG~+JOGs2>x-q9i zPHAbhk{T8`l;uo}cbyKC4OS5bW|HBY`_HC-~+hA`geN0iDcrm2XnaYd)9Xj=`wbb8{ zPglt#>j=paK}FtSZ&1@Om7XINnH=+wcQP|#gZZi51|6N9eax#&Q^A7?2Tz$mNv2V( zH1xyq%kYo4Zso}nnFf<7jiuejwLING9 z#cFZJDs7eJ)<8S_@8`;;iylotT(f^X8DVC7m_%pW@)Qv?$z7pOAW$fhYF3<8(zJd| ztn`+FkPtr-5J*+@^3)ypi}?oVG%M9Rq-~6%EhjQ2o2=a6oUclWSi4+#_9EN1CMfV7 zkGv)nXy#^{dFX70R6Z%7v-AYkGcV>6!^*>Tj8FMuL zM8|wp1UDD8GWLu}a^*)Ad~j(Z7Tt1zlw#IuoSf zY-wv<{MTCh6)kt!Ncpqo<%c8Nkc4_v8R0PjZP}fLWJISTw}GUNw`{SjYN$%0%BUsZ z00!2wc>N75nwDCvD2MXGB0RzF>pQ6e7+;J2@8UVzqhVckyD(>_lD>!X%n%l_<4zQa zot7ZoN(&%JXESlyy<;zGoMThxEVGbgF)EaLoOI3< z(PQ(()pgxk_8*fHggLG`^B!BmYr#G$nYxcyIRf{(v^*bcBkelv|os2`-YnAK=z&KS}V|JAP6@u9IekGgDH!r!5EF%>(+U zP6C})ge&%a)!8MH0&mL_IOUzFJqlJaKBthiJi5GR&|W^YQ31tV7}WlVsyWZD6}P=D zcqX(}3y*H$N8ZdiiFV(sD-ATH>Olg3bNDa(ecIPoRvq{N%JTT5iiwWt7rcFn{?>tc zGgG%_cGKG@R|j>*Cb%EWFc7`23&1i;$$HZA5nm|SF-1ggYli#KE8ubb57s8xCBvVb zfIWC*{*L|)l5J)?qN?o)ha9DQ9>Gm+EH)p?5guC`o2GABb~%(2&xJ($>X=$KV2j54 zl_EFHV8MiXlQc7F*_!2Jv~8{Mp5DymoR5?qvs}b*_5DI(0;{rkLQ4s~Qh+Tpq-k&H z{EuePk2fE5z`xKxTJUzh#~^40Vq)9)1mnY#STgdsZYHO~CMkhp)=s`sc{8bYvZ|dr zx&sEgFwK`%GerRoXs#Z*F41N(U73Zt$O7DHS2~ ze$iQe+EcaKJwOo&gzcx6qu+`Cm2IRn^>~>l%SSYgON8=6*K#46S>T1PE5au(HZbE} z((qu3nZ_PtWTH#W(m(W^>*X78Lt6Y*?2c*7>l$6-4|zk9t+h{C6+mAei_%XwUQar> zEg}io*gz*)wtH)|lTCB)is@^5Kc)IU(_LC`mgxY`>?-SfYmbNWT`kRp5o6A-w<`iR z>g4LK(dF?vev<0O41s6=60js|ftIm^QlCk6eP>>Jf<5EE&&nQ_91Fy*iUxi+p`(bH zLKFS+6eJ&R)ptPK2E1VS=|<7-o4+*|@^P1ZbH*7qflp&=rZ{RWqaA;bq`a@FxNPQo ztuRhavWcOE765V6fQDRDs=JEFnONfn)mX0$8O%3im}hqhQk~)E!*8!M&P8=I5U)j3 z2NPjKloNXLu9|CeYK(9rgnOSn$g0ZA=_Ypx0=O}mj5B(tc!h%oh4#BLGYp^$k%^?|wf6jrP7>-vvqYG&Tm0GY%G zH&xc*A%HOwfoY-NnIdg1DwJxIpk1nAQ?Xccr*l#^Z`Dx8528o~(-%~Fdl5rLtb>&@or$<@;XxwC`* z`*`@_uJ5Wt7gPbs{u=y;}Ka_EzIDo^p z%ys3rX5DAY*NGhTM{x8op*a%!jHsrt$DC;YTx26oX?Eh*K^mSQ)!heWO$nheAlAcps*8N# zrnGn2cAfcxrhir(4hyAAZhyI@q5&AfW}b6*sKBv)tcp!wkOfw*%x5cg4^@Cr*q0ZY zi1aocm5(Nhqn)*Mtm>>Lb*^Oz8})k^xG9ILt=B!AXR-LSavze%iBZ_=EJsqrB7ws; zk5wA(Fym=}p_OSdbf$pf;(>|qeU~P4N^RwX7CeIjvSdYx%jV2A>YzT*Q zW?mfs$I%pgVfq+jv{^W-3h-o|=MEm~JX5Swh=*Y)L?7VqSUM0NC+LHKQ(k4QSI_G80sibJRanb47!?Xc+(xfR-J?O%jH zUk~y+#5v1;_RSFM49)0Bm^pw1gW{IT6i^?_l@NvH|1Mhq-a%TS063;Fr%L6*N6nj> z(?0oWC~M1k_1V!0gG)cs6WJ-Gv=d{EPoQt#j%a?*E4Tqev9X4P8E$u{6GU6FfY`7 zj$~IRDnliW7BOZl$mWkujq%5@j=qsYcgC8&VMA%Wq4Es7J~By@7R=wfCBJ=P_UweB zc%otQ(YZJvJIwZ`sd;cR@fQ5$rHu(jUlcW4@?wd$jMCk}1VDG%aWX|%%5J|Ut~asj zhi~ZT3YhD({(3M7$B9RLYZ1RktbUv(AU#~r2wlP7~8LmzMFw7zKHxA z!PM?>{?ATJK$crc(nfE}1M@L%wRl%wxL~&Hb7<>fl{146k|Y3EE(dvr8G0-Dwee#n zeF_FvAakDpvIBws3e?Q-{ih$(DEzUiJbfqg>Mmj3`bLUO>qHInV7vobw^F#svcALN z9DSC;bzy@6e*8S`tQ#?=wXCb&O_A&Af@cq=QT!1ye5)0y`VQDe#8q%!O zGp?HUI>k1s9`@>6isLu*7E!Qh3=I!+mzhJYN-@N4(u`?4T`9SD@>Cw9iVFYns#O~> zaN~O&fnZ`Mv>u_+61-8Q_{$)+a&H|pFEr%^Ht+?lG&=TYtiisS}Iw7$SChm?f zpXcPx5G`8Un2SZ+sds?I4aU~i>N^Z8^5>IV`=SHvSQ3iO*J)Q^*%QvO31LKwaT)mm z|4ekB@=y2Szx{@fAHt&)YCH(%9p+nHu_wn+{>(bf%n`Xo^HQFX&`h}OHJeR7{PlEq ze5O27O9j9Ap62a`ZYR-(14*SV%a%{E2%T!I(`Sn6EkP# zOTTw41x+7UjgSmFq8Rf?ooE44B|+8-__sKclyFZOM|iQT4;A24nxwbL25Y7G_oUE$(`Kz~jf*D{6}XKsig_ zib6(pWnQ>YD(c)KmUaF^*&c0W)V{HX>bukP(-eKuqV~jEcu~ZIuUW?QY`w_TmVJv3 z&bzC+Go+t(3Wj9A{?{TBj3Kds{>CxxUkS*cW;n3mgLR+~nVc`ndjh-^k&<53+N^Ko zV0+a2Blm`cjZG6x5+(ZCU-~%pf#bf&o*95+FZ4ILFCJm?dyS?B!kcT!D^u8h+{bxR z1-k7Ia99%L!aBvvR}hLM1t-=X$o4(IDbEL0oUho}Zq+*-sQapXLl_^I zul0sFYZCVngG;aBgUh%B&t-W#!|YCc*RljUV`7QW2!u-xmu^$+r`!?H0527;qghAl z&8!oD%Tf6ZKb&LK0ri(8UB0@2@8fP~*$y|X&9;F$2WeTU>5%&+N1z8GLbZ4>Q^vr{2& zO1K?fZhh^%@mERDrRIfZ6kY+atzui0-O`U|jMOZpOf73($w74t00A1h2Xl38N295E zmY&2pVh~>3zLpE#%;1qBsp6*@ZDOm$nk_MmK&5a;=<%AfTthH(97{<34zS=()iSpm zpK^!zdG*f~>s$?L{qNLyTKxdq(C{yFzmj#!H)FOcjFTUyNv`69cMgW5M$CS?E$p(F zsozL@iXh;*s}4hgfFA0l1IK3Jx}(SDGNxbDjE%p@8{=`AC$SuO$NTE!ts_QLaCzPN z>F1e7Y63Q=cQ9I2*;YLRm2~VJ#AW78@c)ep*IT&AMn`_>hqLz7SmT=;9d&AL}Tn$^S}9#XS##X@7ex4|oa=qY<^ zU?t{u7Uy%(L`j@@>|kW#r4*6xr-ZX>!?d;Qcv_Pe>zF#=7DRX*QC&gEjQg;G*5vvP z;l^=Mr&+F;0QLw8^9uKbl|D@8M)$Z0?6&QZv%JxM-&R#`T=6Svy#69mE4W)(x_~vJ zAf2{Y5DqBMnQLUT?;LBErtMtZk&yGKY1R2;e1*4_kwN7FzX-oc$Y5{`tl~s#>5e-1 zdlc^cReR9WNgyvz)+n9*1%8 zZTg5Utkcwba1{n-zDbz58nQT?vD$J7s*DJcP0A;FO4WIMFGwA+4g3wzvec^CQ^$!J zfo?Pc@>m87>d1AuJ3XSd6EU6RL}fA9mbyE3nCv~6p$9iJmh9D*>|+}LrI^?kE!i(N zw>utJPwBY{3G$%$JgNB$_^2P+75X!v$i?G_EKcEtYuaJZGn|tTgVL? z74ZcZud^W|xvsa}urNe)C}nuPDLf+Prx!i8i8eJDoLquq3ev`;9w${SEeNq>TV z?FjgmXMJ`w<^P(TYF&@JbQM#yM2nbL`#3H9TfjMcKP+#*hFEJDP#6xbhc2!W0G}nA z+{s&9r`Y_xA2B+?pFhRTW@ogZ3JQQ^o%ZL_Cv5qNR-U_g#k;H9tH5J)r^eDZ*arX^ zbkg2GF#84d$pwN^-f0;!Qz)WGtqE}hMk0CZVY4K6BY8E9857mHKoRGP~uJh+x#HEx~t4!JJ*nZU%$Owoq zT?*>Ia3_r5PIbYR$j1%bb0K;YtvUjPTE1=4M(N@~IE@KnN|9~owHoi@-m@*NitrKm@q$c-^&n0^GnA}W{_;wNh|tmW`0gMV9MSfpl+Fy9VrTkJr*hn z?#Y%3p*(|esRG3~^Ny1}#dK(#+7cn_F+kt?cqVJ37d#jqQMi}6v>CIijbs2m7*3*l zCH-*vJaT2L!gd3*gDdX7kfj{;wv1&x zWYZ85(2xYzrc5N(9YFyaKX8XxTE!;(zo^JIjT#-wdeHHIi^&6DyRXn6OhIxd>;9&k zDsx2dV3f=68vgm*RF3m=0lrC_Or}K{YebV-ngJL4+SsAC922<~oz@&}yjCiMCcXct zR?K-MF;}7z7u_SRS-CO1tUzv!fwvD_3tFRZ>(9HEsnOF^u)+cqQ$f0CRtWM^%Rf}b zQ(I+c&WhVm?J@*-e=ZhGLmoc7^jK#YowATj6~UnPm@NO|5g<&VvtuR+bW@iU8xYAT z71G|~Bq_{mDD+uL>h;)R@oN0+5Ox)s)ceyR^NQ-3x)kRCZ*w4B_+s{D!0pl6?_Io# zAf|uv(?n6Z($+NKk!;z7!Yp-=%mz-RXWLeOfyq`%KGQzrhs)t!AHK7dRo^;bWf91$ z4bYFd%||( zl7TLtM*Z|xAiAOMU)B}6(H&{Bw|JH*{*lq&8-=Hx5=}FpJ$!oYo&av%;y!)&dJ^)U zuHqBK%N?=uVmA9!y5=w&F6vO$S^R}1g^FjlrRU`Gt+X_-%zZNheZ!CQHSmbYFS&=+ z@(0uG4=Z#2Oi>-@#@7;G-6)D1Ob1FZDCVSyg2#r9&SlsFHYs1zrrn{?CY%w_( zB)997T{x)iF-1g1MF!hEn@c8qke^Z|?*`&|A}5M0jhfK=KLwdXExDo|SLRr_%KthG zBMf-s>6#eO??O5>(lD)b@xGk<%O~-J$O@@h%#|+=a7DF|4$o0(C!UVddQWI6M2^Cj zo!AycGQwxA85A(`)T(A_%c_MnOFu6{8V$yaacWTO{F3-(4%^Hl6Jwts5sV@i186T_ z(#<}?oljn*ExO;@sje_Q!SSuVhK>j>_9l3jGqKQoY{*058J8=Z@L-6syj*4HLarc0(KZ~lD^^NBkNW663C5N`HI5~2wTnD9k`Hetc8-R_?ffFv2F zKXtF0m^I{58}CgvSuSN~-sa{54?9ztbs9!kEd$eC79m;%^Q6HtA&*5;oZtNT@*MH8QjeIpIk7A3Xu{dR_aKlF_8ZT-8E8T4>!zw$}v96VW)<1y?4 zu6XY2jlEig+p6qr7c2^e!-GM~U zc~ORHuZ%psc1uS`F$HB%Sm{xjwDhA}R~o{g3idIRI(A)h=|}^O(x3prBEoZYh<700 zwZcf;W+BlN9#WqykLJ0*t~->eGbb2;;cpQ|nflz4tUBz&l=ZTkYL`t|B;l1oa)!fS zz2!0xF(9qJ^f{#_IqHj{mt4TF$JndSEjwBkcU|loA1Yf5g<#R)zm8~D&XMZJMoe>( zXlDj=&oHlA23h8&moI*reKEzQ+EHfgO4;sJnluQaTb~ABSWed6f3`P>?-7gx(8qrv z=eai7v(q#-5lQb$**_hfS}Hf3tJuWtd)=2YoKF2a8+eqpAJg%tkM-d6^ec9F9VR^C zw?zK@asku*w{_dcBvgA+7u$9Ab!=^{!!ka*n8%K{B80V&q5eiZO7)i#;mx@AtgP+W zU(N~JV(I-Dzt|z-8a18o=0ZB1fSixcYBe$3Cfj~W%lW}_-db5DMuL&RNIzLybHFv% z*$ZD(l-f5Fz@~6FXkaONb6~I4W}p{Cdx3SptmT|5Z?83Vmam0`__(x8?ZA_5(j(k2pC_etb-?}18308ZdlAYuH5O{^0hXga63+#Y4q zdq?AYB-f=-`fG>gA$tdR*~Y{miT z55qC+Rht3wrRBJyF%MEp;gyzYkM7I$%>QO5^WE zCbOJM;u&>4QtTo2R^?SEHNM=Ot_v6^6k<`Opmd+-{A4bwyuPKvDK<|ZYS4b%NSv^r zs3dn^YL`*$v zzaYt!X1R>SubSjlicE_;iZOe5a+to$uiRS-^RI9k!mM&707G1b1*9L+GtrdW<<3Y~%I>9K`9>F=Wu;F2I66l}ND^gr_r@^B zYJ-MEf(G<}dNdF8hgbIDM@{yof!Xpe@mqq!rU#E-AUthdDQ$w()R0{6eLAb5)(e%) zk70d6H;8D9lXG*sI={_Jd3uz_-!k_TwcUU?tB_T{6m^-(siSV5NL=mS?w;*B|ID&W z_)E|>M{6k5Q7DyQb*d!jG83A379GHtbQB_D4|2MWQ$TTGN*yb)s8BNpXahv z+_k6}DX5bd&;sSq)5O@yD;>H1HpI>J`&9kpAnnVthY#$sTGJHu4{W-0yFu>}0=u;O zC|PSFa(G!na0u>75mCSvXn?+D{@$YfOex*WH1_1HTrNdNQb8|ICBycvrNumkkMQ@V z@XAR5jpf@t1D07u#F_Geww2XJw*cuFvAo^cTERxt{Lz^qvtrj;k%0Y-oxGv~_7uE| zWS$DbUYR0|f(e^+;w+KMj%4D53lW=z;6FWHR=3r$z55#ntZvuaXLn-6_GoBbr(cT* z-Bu)*X{hb{BnY~39}~^vClbr;ou%JsY;CB3JtJfHsIHLHH+0#6XQdLCd>OFSW9Wm} z2~&*S6Q3N3&tdw>iUs!Il3Dk6iI%a0I!7IED0cj99oV^BL(QL~y9b_{!X=o)1+xAq z<@pYl|I)=(lnYC9GD?eo&_|p7pcEOuEFq~|Ds851p~=M5DG(74%Pcxn(xMH}8aML= zC=X|+&F)gOe2Oiy%r{cGUJ3Ch+4~4~O#9J~3U0ErYw3qER^uY+Rtnx(n62iX1|2Hh zra%x4MCs18EDUgS&hJj!9AlK$o1M9bu#REi4CRfycU?7Qy=%4u zQm4q_hpE4DM7vAel{-YqFBy<`2$_#S$DH5sBgjF~f0@h<8oxAlW{#Rok$swNUPi1m zD7xo`sDY-Er3exX5PnSOSOp14n%rrY#x{&CxGP$~aa-@~Drx-EOB(x_N+?Hq=b-YX z9wGbr>7+4thaU?+VN7L~sBdUWGvHQ>(e9i6+XZbmOT7LY1wM{Pf~Lers^*Ry%Wl&xFE`{{wcV)K`OB;EFUEFQCTUYtBl>l*+ko zF(p^8(IcwldC#SaS*J_;klhqGOeSm}ka@cfU!U=e7h#DQYh7P^@?(QyVj{< zrnMw`34BJZ%bl9j6ysj`>|XMDLXthOCV2nXFAXBO;Ga5Dqb1mO{K^t~0i5pqHlmR= zVdn+ow^Yuzwmc!3g%!6@VCkx9k6V=2KE1MnY6iVS;-?ud^N1l))34#cl(`xLLh@AC z&yUvIDy@&glTDd7-X9;)GhGW*Rqx}|UAwn-l~x?oi=vC)7O`IF8Q(e9RkB~OTJ|mU zf^Q`Luz%zugr1|e(rmFlwBR)36cm(=TUMO()jKarRrXg}j=TxVOT)oKrrndC@Ja$E@IQTn))SEb(@M2v`k&GGaeI<) zbFBYigM*)T)KGzgfPjGgSLLN4p|BwSSL_^*>hJ^QKWgXybs=8QLEyi1@i`6zP%V7% z4h{tIzq!%l4;_%c{s$^HjGD>`1p#3V0|7z(kMn&LZ#Lb3!w?Yv52g(P Ai~s-t delta 15009 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

    s$*rls@!sHBO;ZCZI;P{yKGwD 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 L_^*Fz5Rm@|Z!jRr diff --git a/lib/bld/bld-wrapper.properties b/lib/bld/bld-wrapper.properties index 26eaf6a..47fd61f 100644 --- a/lib/bld/bld-wrapper.properties +++ b/lib/bld/bld-wrapper.properties @@ -1,10 +1,10 @@ bld.downloadExtensionJavadoc=false bld.downloadExtensionSources=true bld.downloadLocation= -bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.5 -bld.extension-gv=com.uwyn.rife2:bld-generated-version:0.9.8 -bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.7 -bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.0.0 +bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.6 +bld.extension-gv=com.uwyn.rife2:bld-generated-version:0.9.9 +bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.8 +bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.0.1 bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES bld.sourceDirectories= -bld.version=2.0.1 +bld.version=2.1.0 From c60531f6170ed701ac742986cb8c5e13a6b823ea Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 8 Sep 2024 19:30:53 -0700 Subject: [PATCH 797/844] Moved to LangChain4J for ChatGPT and Gemini modules --- .gitignore | 1 + config/detekt/baseline.xml | 6 +- lib/bld/bld-wrapper.properties | 2 +- pom.xml | 50 +++++++++----- properties/mobibot.properties | 13 +--- .../java/net/thauvin/erik/MobibotBuild.java | 19 ++++-- .../net/thauvin/erik/mobibot/Mobibot.kt | 4 +- .../net/thauvin/erik/mobibot/ReleaseInfo.kt | 4 +- .../modules/{ChatGpt.kt => ChatGpt2.kt} | 67 ++++-------------- .../erik/mobibot/modules/CurrencyConverter.kt | 2 +- .../mobibot/modules/{Gemini.kt => Gemini2.kt} | 68 +++++-------------- .../{ChatGptTest.kt => ChatGpt2Test.kt} | 12 ++-- .../modules/{GeminiTest.kt => Gemini2Test.kt} | 15 ++-- website/index.html | 2 +- 14 files changed, 102 insertions(+), 163 deletions(-) rename src/main/kotlin/net/thauvin/erik/mobibot/modules/{ChatGpt.kt => ChatGpt2.kt} (62%) rename src/main/kotlin/net/thauvin/erik/mobibot/modules/{Gemini.kt => Gemini2.kt} (58%) rename src/test/kotlin/net/thauvin/erik/mobibot/modules/{ChatGptTest.kt => ChatGpt2Test.kt} (84%) rename src/test/kotlin/net/thauvin/erik/mobibot/modules/{GeminiTest.kt => Gemini2Test.kt} (79%) diff --git a/.gitignore b/.gitignore index 6c5fc87..d2daf1c 100644 --- a/.gitignore +++ b/.gitignore @@ -60,3 +60,4 @@ local.properties logs mobibot.properties out +/target/ diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml index b20abc9..719ca4e 100644 --- a/config/detekt/baseline.xml +++ b/config/detekt/baseline.xml @@ -71,9 +71,6 @@ ReturnCount:Addons.kt$Addons$fun help(channel: String, topic: String, event: GenericMessageEvent): Boolean ReturnCount:ExceptionSanitizer.kt$ExceptionSanitizer$fun ModuleException.sanitize(vararg sanitize: String): ModuleException ReturnCount:Seen.kt$Seen$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) - SwallowedException:GoogleSearchTest.kt$GoogleSearchTest$e: ModuleException - SwallowedException:StockQuoteTest.kt$StockQuoteTest$e: ModuleException - SwallowedException:WolframAlphaTest.kt$WolframAlphaTest$e: ModuleException ThrowsCount:ChatGpt.kt$ChatGpt.Companion$@JvmStatic @Throws(ModuleException::class) fun chat(query: String, apiKey: String?, maxTokens: Int): String ThrowsCount:GoogleSearch.kt$GoogleSearch.Companion$@JvmStatic @Throws(ModuleException::class) fun searchGoogle( query: String, apiKey: String?, cseKey: String?, quotaUser: String = ReleaseInfo.PROJECT ): List<Message> ThrowsCount:Joke.kt$Joke.Companion$@JvmStatic @Throws(ModuleException::class) fun randomJoke(): List<Message> @@ -82,7 +79,9 @@ ThrowsCount:StockQuote.kt$StockQuote.Companion$@Throws(ModuleException::class) private fun getJsonResponse(response: String, debugMessage: String): JSONObject ThrowsCount:Weather2.kt$Weather2.Companion$@JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message> ThrowsCount:WolframAlpha.kt$WolframAlpha.Companion$@JvmStatic @Throws(ModuleException::class) fun queryWolfram(query: String, units: String = IMPERIAL, appId: String?): String + TooGenericExceptionCaught:ChatGpt2.kt$ChatGpt2.Companion$e: Exception TooGenericExceptionCaught:Gemini.kt$Gemini.Companion$e: Exception + TooGenericExceptionCaught:Gemini2.kt$Gemini2.Companion$e: Exception TooGenericExceptionCaught:StockQuote.kt$StockQuote.Companion$e: NullPointerException TooGenericExceptionCaught:Weather2.kt$Weather2.Companion$e: NullPointerException TooManyFunctions:EntryLink.kt$EntryLink : Serializable @@ -94,6 +93,7 @@ WildcardImport:FeedMgrTest.kt$import assertk.assertions.* WildcardImport:FeedReaderTest.kt$import assertk.assertions.* WildcardImport:FeedsManager.kt$import com.rometools.rome.feed.synd.* + WildcardImport:Gemini2Test.kt$import assertk.assertions.* WildcardImport:GeminiTest.kt$import assertk.assertions.* WildcardImport:GoogleSearchTest.kt$import assertk.assertions.* WildcardImport:JokeTest.kt$import assertk.assertions.* diff --git a/lib/bld/bld-wrapper.properties b/lib/bld/bld-wrapper.properties index 47fd61f..ed0fdb7 100644 --- a/lib/bld/bld-wrapper.properties +++ b/lib/bld/bld-wrapper.properties @@ -1,7 +1,7 @@ bld.downloadExtensionJavadoc=false bld.downloadExtensionSources=true bld.downloadLocation= -bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.6 +bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.7 bld.extension-gv=com.uwyn.rife2:bld-generated-version:0.9.9 bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.8 bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.0.1 diff --git a/pom.xml b/pom.xml index 7996b05..5d1b89a 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 net.thauvin.erik.mobibot mobibot - 0.8.0-rc+20240809180718 + 0.8.0-rc+20240908192921 mobibot @@ -18,7 +18,7 @@ org.apache.commons commons-lang3 - 3.16.0 + 3.17.0 compile @@ -51,34 +51,28 @@ 33.2.1-jre compile - - com.google.cloud - google-cloud-vertexai - 1.7.0 - compile - org.jetbrains.kotlin kotlin-stdlib - 2.0.10 + 2.0.20 compile org.jetbrains.kotlin kotlin-stdlib-common - 2.0.10 + 2.0.20 compile org.jetbrains.kotlin kotlin-stdlib-jdk7 - 2.0.10 + 2.0.20 compile org.jetbrains.kotlin kotlin-stdlib-jdk8 - 2.0.10 + 2.0.20 compile @@ -96,25 +90,49 @@ org.slf4j slf4j-api - 2.0.15 + 2.0.16 compile org.apache.logging.log4j log4j-api - 2.23.1 + 2.24.0 compile org.apache.logging.log4j log4j-core - 2.23.1 + 2.24.0 compile org.apache.logging.log4j log4j-slf4j2-impl - 2.23.1 + 2.24.0 + compile + + + dev.langchain4j + langchain4j-open-ai + 0.34.0 + compile + + + dev.langchain4j + langchain4j-google-ai-gemini + 0.34.0 + compile + + + dev.langchain4j + langchain4j-core + 0.34.0 + compile + + + dev.langchain4j + langchain4j + 0.34.0 compile diff --git a/properties/mobibot.properties b/properties/mobibot.properties index a7526cc..fd7b104 100644 --- a/properties/mobibot.properties +++ b/properties/mobibot.properties @@ -45,7 +45,6 @@ disabled-modules=mastodon # Automatically post links to Mastodon #mastodon-auto-post=true - # # Get Exchange Rate API key from: https://www.exchangerate-api.com/ # @@ -75,19 +74,13 @@ disabled-modules=mastodon #wolfram-units=imperial # -# ChatGPT/OpenAI API key from: https://beta.openai.com/account/api-keys +# Get ChatGPT/OpenAI API key from: https://platform.openai.com/api-keys # #chatgpt-api-key= #chatgpt-max-tokens=1024 # -# Set a Vertex AI Gemini API project in Google Cloud: -# https://cloud.google.com/vertex-ai/docs/generative-ai/start/quickstarts/quickstart-multimodal -# Don't forget to: -# gcloud config set project PROJECT_ID -# gcloud auth login LOGIN -# gcloud auth application-default login +# Get Google Gemini API key from https://ai.google.dev/gemini-api/docs/api-key # -#gemini-project-id= -#gemini-location=us-west1 +#gemini-api-key= #gemini-max-tokens=1024 diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index 1e6649b..980f2a6 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -77,20 +77,20 @@ public class MobibotBuild extends Project { new Repository("https://jitpack.io"), SONATYPE_SNAPSHOTS_LEGACY); - var log4j = version(2, 23, 1); - var kotlin = version(2, 0, 10); + var log4j = version(2, 24, 0); + var kotlin = version(2, 0, 20); + var langchain = version(0, 34, 0); scope(compile) // PircBotX .include(dependency("com.github.pircbotx", "pircbotx", "2.3.1")) // Commons (mostly for PircBotX) - .include(dependency("org.apache.commons", "commons-lang3", "3.16.0")) + .include(dependency("org.apache.commons", "commons-lang3", "3.17.0")) .include(dependency("org.apache.commons", "commons-text", "1.12.0")) .include(dependency("commons-codec", "commons-codec", "1.17.1")) .include(dependency("commons-net", "commons-net", "3.11.1")) // Google .include(dependency("com.google.code.gson", "gson", "2.11.0")) .include(dependency("com.google.guava", "guava", "33.2.1-jre")) - .include(dependency("com.google.cloud", "google-cloud-vertexai", "1.7.0")) // Kotlin .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlin)) .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-common", kotlin)) @@ -99,10 +99,15 @@ public class MobibotBuild extends Project { .include(dependency("org.jetbrains.kotlinx", "kotlinx-coroutines-core", "1.8.1")) .include(dependency("org.jetbrains.kotlinx", "kotlinx-cli-jvm", "0.3.6")) // Logging - .include(dependency("org.slf4j", "slf4j-api", "2.0.15")) + .include(dependency("org.slf4j", "slf4j-api", "2.0.16")) .include(dependency("org.apache.logging.log4j", "log4j-api", log4j)) .include(dependency("org.apache.logging.log4j", "log4j-core", log4j)) .include(dependency("org.apache.logging.log4j", "log4j-slf4j2-impl", log4j)) + // LangChain4J + .include(dependency("dev.langchain4j", "langchain4j-open-ai", langchain)) + .include(dependency("dev.langchain4j", "langchain4j-google-ai-gemini", langchain)) + .include(dependency("dev.langchain4j", "langchain4j-core", langchain)) + .include(dependency("dev.langchain4j", "langchain4j", langchain)) // Misc. .include(dependency("com.rometools", "rome", "2.1.0")) .include(dependency("com.squareup.okhttp3", "okhttp", "4.12.0")) @@ -118,8 +123,8 @@ public class MobibotBuild extends Project { scope(test) .include(dependency("com.willowtreeapps.assertk", "assertk-jvm", version(0, 28, 1))) .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", kotlin)) - .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 10, 3))) - .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 10, 3))); + .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 11, 0))) + .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 11, 0))); List jars = new ArrayList<>(); runtimeClasspathJars().forEach(f -> jars.add("./lib/" + f.getName())); diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt index 88bed54..1e49a88 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt @@ -396,11 +396,11 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro // Load the modules addons.add(Calc()) - addons.add(ChatGpt()) + addons.add(ChatGpt2()) addons.add(CryptoPrices()) addons.add(CurrencyConverter()) addons.add(Dice()) - addons.add(Gemini()) + addons.add(Gemini2()) addons.add(GoogleSearch()) addons.add(Info(tell, seen)) addons.add(Joke()) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt b/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt index 3abf162..5b5e5d2 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt @@ -14,12 +14,12 @@ import java.time.ZoneId */ object ReleaseInfo { const val PROJECT = "mobibot" - const val VERSION = "0.8.0-rc+20240712110931" + const val VERSION = "0.8.0-rc+20240908190240" @JvmField @Suppress("MagicNumber") val BUILD_DATE: LocalDateTime = LocalDateTime.ofInstant( - Instant.ofEpochMilli(1720807771484L), ZoneId.systemDefault() + Instant.ofEpochMilli(1725847361020L), ZoneId.systemDefault() ) const val WEBSITE = "https://mobitopia.org/mobibot/" diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt2.kt similarity index 62% rename from src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt rename to src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt2.kt index c7ba4ba..854bb9f 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt2.kt @@ -31,23 +31,16 @@ package net.thauvin.erik.mobibot.modules -import net.thauvin.erik.mobibot.Constants +import dev.langchain4j.model.openai.OpenAiChatModel +import dev.langchain4j.model.openai.OpenAiChatModelName import net.thauvin.erik.mobibot.Utils import net.thauvin.erik.mobibot.Utils.sendMessage -import org.json.JSONArray -import org.json.JSONException -import org.json.JSONObject import org.pircbotx.hooks.types.GenericMessageEvent import org.slf4j.Logger import org.slf4j.LoggerFactory -import java.io.IOException -import java.net.URI -import java.net.http.HttpClient -import java.net.http.HttpRequest -import java.net.http.HttpResponse -class ChatGpt : AbstractModule() { - val logger: Logger = LoggerFactory.getLogger(ChatGpt::class.java) +class ChatGpt2 : AbstractModule() { + val logger: Logger = LoggerFactory.getLogger(ChatGpt2::class.java) override val name = CHATGPT_NAME @@ -93,9 +86,6 @@ class ChatGpt : AbstractModule() { */ const val MAX_TOKENS_PROP = "chatgpt-max-tokens" - // ChatGPT API URL - private const val API_URL = "https://api.openai.com/v1/chat/completions" - // ChatGPT command private const val CHATGPT_CMD = "chatgpt" @@ -103,48 +93,15 @@ class ChatGpt : AbstractModule() { @Throws(ModuleException::class) fun chat(query: String, apiKey: String?, maxTokens: Int): String { if (!apiKey.isNullOrEmpty()) { - val jsonObject = JSONObject() - jsonObject.put("model", "gpt-3.5-turbo-1106") - jsonObject.put("max_tokens", maxTokens) - val message = JSONObject() - message.put("role", "user") - message.put("content", query) - val messages = JSONArray() - messages.put(message) - jsonObject.put("messages", messages) - - val request = HttpRequest.newBuilder() - .uri(URI.create(API_URL)) - .header("Content-Type", "application/json") - .header("Authorization", "Bearer $apiKey") - .header("User-Agent", Constants.USER_AGENT) - .POST(HttpRequest.BodyPublishers.ofString(jsonObject.toString())) - .build() try { - val response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString()) - if (response.statusCode() == 200) { - try { - val jsonResponse = JSONObject(response.body()) - val choices = jsonResponse.getJSONArray("choices") - return choices.getJSONObject(0).getJSONObject("message").getString("content").trim() - } catch (e: JSONException) { - throw ModuleException( - "$CHATGPT_CMD($query): JSON", - "A JSON error has occurred while conversing with $CHATGPT_NAME.", - e - ) - } - } else { - if (response.statusCode() == 429) { - throw ModuleException( - "$CHATGPT_CMD($query): Rate limit reached", - "Rate limit reached. Please try again later." - ) - } else { - throw IOException("HTTP Status Code: " + response.statusCode()) - } - } - } catch (e: IOException) { + val model = OpenAiChatModel.builder() + .apiKey(apiKey) + .modelName(OpenAiChatModelName.GPT_4_O) + .maxTokens(maxTokens) + .build() + + return model.generate(query) + } catch (e: Exception) { throw ModuleException( "$CHATGPT_CMD($query): IO", "An IO error has occurred while conversing with $CHATGPT_NAME.", diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt index 4fb7555..3c8ea92 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt @@ -217,6 +217,6 @@ class CurrencyConverter : AbstractModule() { init { commands.add(CURRENCY_CMD) initProperties(API_KEY_PROP) - loadSymbols(properties[ChatGpt.API_KEY_PROP]) + loadSymbols(properties[ChatGpt2.API_KEY_PROP]) } } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini2.kt similarity index 58% rename from src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini.kt rename to src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini2.kt index 2e4ed91..812aed3 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini2.kt @@ -31,12 +31,7 @@ package net.thauvin.erik.mobibot.modules -import com.google.cloud.vertexai.VertexAI -import com.google.cloud.vertexai.api.GenerationConfig -import com.google.cloud.vertexai.api.HarmCategory -import com.google.cloud.vertexai.api.SafetySetting -import com.google.cloud.vertexai.generativeai.GenerativeModel -import com.google.cloud.vertexai.generativeai.ResponseHandler +import dev.langchain4j.model.googleai.GoogleAiGeminiChatModel import net.thauvin.erik.mobibot.Utils import net.thauvin.erik.mobibot.Utils.sendMessage import org.pircbotx.hooks.types.GenericMessageEvent @@ -45,8 +40,8 @@ import org.slf4j.LoggerFactory import java.util.* -class Gemini : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(Gemini::class.java) +class Gemini2 : AbstractModule() { + private val logger: Logger = LoggerFactory.getLogger(Gemini2::class.java) override val name = GEMINI_NAME @@ -55,8 +50,7 @@ class Gemini : AbstractModule() { try { val answer = chat( args.trim(), - properties[PROJECT_ID_PROP], - properties[LOCATION_PROP], + properties[GEMINI_API_KEY], properties.getOrDefault(MAX_TOKENS_PROP, "1024").toInt() ) if (!answer.isNullOrEmpty()) { @@ -82,17 +76,12 @@ class Gemini : AbstractModule() { const val GEMINI_NAME = "Gemini" /** - * The Google cloud project ID property. + * The API key */ - const val PROJECT_ID_PROP = "gemini-project-id" + const val GEMINI_API_KEY = "gemini-api-key" /** - * The Vertex AI location property. - */ - const val LOCATION_PROP = "gemini-location" - - /** - * The max number of tokens property. + * The max number of output tokens property. */ const val MAX_TOKENS_PROP = "gemini-max-tokens" @@ -103,40 +92,18 @@ class Gemini : AbstractModule() { @Throws(ModuleException::class) fun chat( query: String, - projectId: String?, - location: String?, - maxToken: Int + apiKey: String?, + maxTokens: Int ): String? { - if (!projectId.isNullOrEmpty() && !location.isNullOrEmpty()) { + if (!apiKey.isNullOrEmpty()) { try { - VertexAI(projectId, location).use { vertexAI -> - val generationConfig = GenerationConfig.newBuilder().setMaxOutputTokens(maxToken).build() - val safetySettings = listOf( - SafetySetting.newBuilder() - .setCategory(HarmCategory.HARM_CATEGORY_HATE_SPEECH) - .setThreshold(SafetySetting.HarmBlockThreshold.BLOCK_LOW_AND_ABOVE) - .build(), - SafetySetting.newBuilder() - .setCategory(HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT) - .setThreshold(SafetySetting.HarmBlockThreshold.BLOCK_LOW_AND_ABOVE) - .build(), - SafetySetting.newBuilder() - .setCategory(HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT) - .setThreshold(SafetySetting.HarmBlockThreshold.BLOCK_LOW_AND_ABOVE) - .build(), - SafetySetting.newBuilder() - .setCategory(HarmCategory.HARM_CATEGORY_HARASSMENT) - .setThreshold(SafetySetting.HarmBlockThreshold.BLOCK_LOW_AND_ABOVE) - .build() - ) - val model = GenerativeModel.Builder().setModelName("gemini-1.5-flash-001") - .setGenerationConfig(generationConfig) - .setVertexAi(vertexAI).build() - .withSafetySettings(safetySettings) + val gemini = GoogleAiGeminiChatModel.builder() + .apiKey(apiKey) + .modelName("gemini-1.5-flash") + .maxOutputTokens(maxTokens) + .build() - val response = model.generateContent(query) - return ResponseHandler.getText(response) - } + return gemini.generate(query) } catch (e: Exception) { throw ModuleException( "$GEMINI_CMD($query): IO", @@ -159,7 +126,6 @@ class Gemini : AbstractModule() { add(Utils.helpFormat("%c $GEMINI_CMD explain quantum computing in simple terms")) add(Utils.helpFormat("%c $GEMINI_CMD how do I make an HTTP request in Javascript?")) } - initProperties(PROJECT_ID_PROP, LOCATION_PROP, MAX_TOKENS_PROP) + initProperties(GEMINI_API_KEY, MAX_TOKENS_PROP) } - } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt2Test.kt similarity index 84% rename from src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt rename to src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt2Test.kt index 1809a9f..4332a52 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt2Test.kt @@ -39,10 +39,10 @@ import net.thauvin.erik.mobibot.DisableOnCi import net.thauvin.erik.mobibot.LocalProperties import kotlin.test.Test -class ChatGptTest : LocalProperties() { +class ChatGpt2Test : LocalProperties() { @Test fun testApiKey() { - assertFailure { ChatGpt.chat("1 gallon to liter", "", 0) } + assertFailure { ChatGpt2.chat("1 gallon to liter", "", 0) } .isInstanceOf(ModuleException::class.java) .hasNoCause() } @@ -51,7 +51,7 @@ class ChatGptTest : LocalProperties() { fun testChatOnCoverage() { if (System.getenv("CI") == null || System.getenv("COVERAGE_JDK") != null) { assertThat( - ChatGpt.chat("how do I encode a URL in java?", getProperty(ChatGpt.API_KEY_PROP), 60) + ChatGpt2.chat("how do I encode a URL in java?", getProperty(ChatGpt2.API_KEY_PROP), 60) ).contains("URLEncoder") } } @@ -59,12 +59,12 @@ class ChatGptTest : LocalProperties() { @Test @DisableOnCi fun testChat() { - val apiKey = getProperty(ChatGpt.API_KEY_PROP) + val apiKey = getProperty(ChatGpt2.API_KEY_PROP) assertThat( - ChatGpt.chat("how do I make an HTTP request in Javascript?", apiKey, 100) + ChatGpt2.chat("how do I make an HTTP request in Javascript?", apiKey, 200) ).contains("XMLHttpRequest") - assertFailure { ChatGpt.chat("1 liter to gallon", apiKey, -1) } + assertFailure { ChatGpt2.chat("1 liter to gallon", apiKey, -1) } .isInstanceOf(ModuleException::class.java) } } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/GeminiTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/Gemini2Test.kt similarity index 79% rename from src/test/kotlin/net/thauvin/erik/mobibot/modules/GeminiTest.kt rename to src/test/kotlin/net/thauvin/erik/mobibot/modules/Gemini2Test.kt index 1f0202f..226ff6a 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/GeminiTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/Gemini2Test.kt @@ -37,10 +37,10 @@ import net.thauvin.erik.mobibot.DisableOnCi import net.thauvin.erik.mobibot.LocalProperties import kotlin.test.Test -class GeminiTest : LocalProperties() { +class Gemini2Test : LocalProperties() { @Test fun testApiKey() { - assertFailure { Gemini.chat("1 gallon to liter", "", "", 1024) } + assertFailure { Gemini2.chat("1 gallon to liter", "", 0) } .isInstanceOf(ModuleException::class.java) .hasNoCause() } @@ -48,19 +48,18 @@ class GeminiTest : LocalProperties() { @Test @DisableOnCi fun chatPrompt() { - val projectId = getProperty(Gemini.PROJECT_ID_PROP) - val location = getProperty(Gemini.LOCATION_PROP) - val maxTokens = getProperty(Gemini.MAX_TOKENS_PROP).toInt() + val apiKey = getProperty(Gemini2.GEMINI_API_KEY) + val maxTokens = getProperty(Gemini2.MAX_TOKENS_PROP).toInt() assertThat( - Gemini.chat("how do I make an HTTP request in Javascript?", projectId, location, maxTokens) + Gemini2.chat("how do I make an HTTP request in Javascript?", apiKey, maxTokens) ).isNotNull().contains("XMLHttpRequest") assertThat( - Gemini.chat("how do I encode a URL in java?", projectId, location, 60) + Gemini2.chat("how do I encode a URL in java?", apiKey, 60) ).isNotNull().contains("URLEncoder") - assertFailure { Gemini.chat("1 liter to gallon", projectId, "blah", 40) } + assertFailure { Gemini2.chat("1 liter to gallon", "foo", 40) } .isInstanceOf(ModuleException::class.java) } } diff --git a/website/index.html b/website/index.html index fffe650..370c3cf 100644 --- a/website/index.html +++ b/website/index.html @@ -38,10 +38,10 @@

  31. Apache Commons Net
  32. CryptoPrice
  33. exp4j
  34. -
  35. Google Vertex AI
  36. JokeAPI
  37. jsoup
  38. kotlinx-cli
  39. +
  40. LangChain4J
  41. OkHttp
  42. OWM JAPIs
  43. Pinboard Poster
  44. From 863de0c21997ce569a4671f337fdea9114bad49a Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Tue, 10 Sep 2024 00:08:51 -0700 Subject: [PATCH 798/844] Bumped Kotlin extension to version 1.0.2 --- lib/bld/bld-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/bld/bld-wrapper.properties b/lib/bld/bld-wrapper.properties index ed0fdb7..547a2bb 100644 --- a/lib/bld/bld-wrapper.properties +++ b/lib/bld/bld-wrapper.properties @@ -4,7 +4,7 @@ bld.downloadLocation= bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.7 bld.extension-gv=com.uwyn.rife2:bld-generated-version:0.9.9 bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.8 -bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.0.1 +bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.0.2 bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES bld.sourceDirectories= bld.version=2.1.0 From ff98e39b0c72bff892158f751cb1d0cd6e3806d4 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Tue, 10 Sep 2024 00:09:47 -0700 Subject: [PATCH 799/844] Test against Kotlin 2.0.20 in CI workflows --- .circleci/config.yml | 2 +- .github/workflows/bld.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 17b50f1..8dabc3f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -21,7 +21,7 @@ commands: - sdkman/setup-sdkman - sdkman/sdkman-install: candidate: kotlin - version: 2.0.0 + version: 2.0.20 - run: name: Download dependencies command: ./bld download diff --git a/.github/workflows/bld.yml b/.github/workflows/bld.yml index a3c4951..f76f164 100644 --- a/.github/workflows/bld.yml +++ b/.github/workflows/bld.yml @@ -1,6 +1,6 @@ name: bld-ci -on: [ push, pull_request, workflow_dispatch ] +on: [push, pull_request, workflow_dispatch] env: ALPHAVANTAGE_API_KEY: ${{ secrets.ALPHAVANTAGE_API_KEY }} @@ -22,8 +22,8 @@ jobs: strategy: matrix: - java-version: [ 17, 21, 22 ] - kotlin-version: [ 1.9.24, 2.0.0 ] + java-version: [17, 21, 22] + kotlin-version: [1.9.24, 2.0.20] steps: - name: Checkout source repository From 97e1e5e73be534f0f638829c11080e3bbfa590b8 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Wed, 18 Sep 2024 20:28:58 -0700 Subject: [PATCH 800/844] Bumped Kotlin Coroutines to version 1.9.0 --- pom.xml | 4 ++-- src/bld/java/net/thauvin/erik/MobibotBuild.java | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 5d1b89a..a50df02 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 net.thauvin.erik.mobibot mobibot - 0.8.0-rc+20240908192921 + 0.8.0-rc+20240918181213 mobibot @@ -78,7 +78,7 @@ org.jetbrains.kotlinx kotlinx-coroutines-core - 1.8.1 + 1.9.0 compile diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index 980f2a6..6c4a09c 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -45,7 +45,6 @@ import rife.tools.exceptions.FileUtilsErrorException; import java.io.File; import java.io.IOException; -import java.nio.file.Path; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; @@ -96,7 +95,7 @@ public class MobibotBuild extends Project { .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-common", kotlin)) .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-jdk7", kotlin)) .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-jdk8", kotlin)) - .include(dependency("org.jetbrains.kotlinx", "kotlinx-coroutines-core", "1.8.1")) + .include(dependency("org.jetbrains.kotlinx", "kotlinx-coroutines-core", "1.9.0")) .include(dependency("org.jetbrains.kotlinx", "kotlinx-cli-jvm", "0.3.6")) // Logging .include(dependency("org.slf4j", "slf4j-api", "2.0.16")) From 4b908d596ef08f712a9846158a0ed8ec7ef2ad7d Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Wed, 18 Sep 2024 20:37:11 -0700 Subject: [PATCH 801/844] Converted deploy script to fish --- deploy.fish | 11 +++++++++++ deploy.sh | 11 ----------- 2 files changed, 11 insertions(+), 11 deletions(-) create mode 100755 deploy.fish delete mode 100755 deploy.sh diff --git a/deploy.fish b/deploy.fish new file mode 100755 index 0000000..d69ee4e --- /dev/null +++ b/deploy.fish @@ -0,0 +1,11 @@ +#!/usr/bin/env fish + +./bld clean jar deploy +if test $status -eq 0 + echo "cd /home/mobibot/mobitopia/mobibot +lcd deploy +put *.jar +cd lib +rm *.jar +put lib/*.jar" | sftp nix4 +end diff --git a/deploy.sh b/deploy.sh deleted file mode 100755 index d1c1f23..0000000 --- a/deploy.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -./bld clean jar deploy -[ $? -eq 0 ] && sftp nix4.thauvin.us < Date: Wed, 27 Nov 2024 22:24:45 -0800 Subject: [PATCH 802/844] Updated dependencies Bumped Kotlin to version 2.1.0 Bumped Log4J to version 2.24.2 Bumped LangChain4J to version 0.36.2 Bumped Jsoup to version 1.18.2 Bumped UrlEncoder to version 1.6.0 Bumped JUnit to version 5.11.3 --- .github/workflows/bld.yml | 4 ++-- .idea/kotlinc.xml | 16 ++++++++++++++++ README.md | 2 +- src/bld/java/net/thauvin/erik/MobibotBuild.java | 14 +++++++------- 4 files changed, 26 insertions(+), 10 deletions(-) create mode 100644 .idea/kotlinc.xml diff --git a/.github/workflows/bld.yml b/.github/workflows/bld.yml index f76f164..cb0ad5d 100644 --- a/.github/workflows/bld.yml +++ b/.github/workflows/bld.yml @@ -22,8 +22,8 @@ jobs: strategy: matrix: - java-version: [17, 21, 22] - kotlin-version: [1.9.24, 2.0.20] + java-version: [17, 21, 23] + kotlin-version: [1.9.24, 2.0.20, 2.1.0] steps: - name: Checkout source repository diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..0273acf --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index e438c94..b31ec67 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # mobibot [![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) -[![Kotlin](https://img.shields.io/badge/kotlin-2.0.20-7f52ff.svg)](https://kotlinlang.org) +[![Kotlin](https://img.shields.io/badge/kotlin-2.1.0-7f52ff.svg)](https://kotlinlang.org) [![bld](https://img.shields.io/badge/2.1.0-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ethauvin_mobibot&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=ethauvin_mobibot) [![GitHub CI](https://github.com/ethauvin/mobibot/actions/workflows/bld.yml/badge.svg)](https://github.com/ethauvin/mobibot/actions/workflows/bld.yml) diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index 6c4a09c..3858951 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -76,9 +76,9 @@ public class MobibotBuild extends Project { new Repository("https://jitpack.io"), SONATYPE_SNAPSHOTS_LEGACY); - var log4j = version(2, 24, 0); - var kotlin = version(2, 0, 20); - var langchain = version(0, 34, 0); + var log4j = version(2, 24, 2); + var kotlin = version(2, 1, 0); + var langchain = version(0, 36, 2); scope(compile) // PircBotX .include(dependency("com.github.pircbotx", "pircbotx", "2.3.1")) @@ -113,17 +113,17 @@ public class MobibotBuild extends Project { .include(dependency("net.aksingh", "owm-japis", "2.5.3.0")) .include(dependency("net.objecthunter", "exp4j", "0.4.8")) .include(dependency("org.json", "json", "20240303")) - .include(dependency("org.jsoup", "jsoup", "1.18.1")) + .include(dependency("org.jsoup", "jsoup", "1.18.2")) // Thauvin .include(dependency("net.thauvin.erik", "cryptoprice", "1.0.3-SNAPSHOT")) .include(dependency("net.thauvin.erik", "jokeapi", "0.9.2-SNAPSHOT")) .include(dependency("net.thauvin.erik", "pinboard-poster", "1.1.2-SNAPSHOT")) - .include(dependency("net.thauvin.erik.urlencoder", "urlencoder-lib-jvm", "1.5.0")); + .include(dependency("net.thauvin.erik.urlencoder", "urlencoder-lib-jvm", "1.6.0")); scope(test) .include(dependency("com.willowtreeapps.assertk", "assertk-jvm", version(0, 28, 1))) .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", kotlin)) - .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 11, 0))) - .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 11, 0))); + .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 11, 3))) + .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 11, 3))); List jars = new ArrayList<>(); runtimeClasspathJars().forEach(f -> jars.add("./lib/" + f.getName())); From f27501634c7d6621284186c6bbebb53427ce03fb Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Wed, 27 Nov 2024 22:26:46 -0800 Subject: [PATCH 803/844] Ensured HttpUrlConnection is properly disconnected --- .../kotlin/net/thauvin/erik/mobibot/Utils.kt | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt index 6a8e4ff..92b4883 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt @@ -421,14 +421,22 @@ object Utils { @Throws(IOException::class) fun URL.reader(): UrlReaderResponse { val connection = this.openConnection() as HttpURLConnection - connection.setRequestProperty( - "User-Agent", - "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/109.0" - ) - return if (connection.responseCode.isHttpSuccess()) { - UrlReaderResponse(connection.responseCode, connection.inputStream.bufferedReader().use { it.readText() }) - } else { - UrlReaderResponse(connection.responseCode, connection.errorStream.bufferedReader().use { it.readText() }) + try { + connection.setRequestProperty( + "User-Agent", + "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/109.0" + ) + return if (connection.responseCode.isHttpSuccess()) { + UrlReaderResponse( + connection.responseCode, + connection.inputStream.bufferedReader().use { it.readText() }) + } else { + UrlReaderResponse( + connection.responseCode, + connection.errorStream.bufferedReader().use { it.readText() }) + } + } finally { + connection.disconnect() } } From 83b4b18be743593ddf640140bad7d0f5c1e45551 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Wed, 27 Nov 2024 22:29:31 -0800 Subject: [PATCH 804/844] Added pom-root command --- src/bld/java/net/thauvin/erik/MobibotBuild.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index 3858951..897a966 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -200,6 +200,12 @@ public class MobibotBuild extends Project { .execute(); } + @BuildCommand(value = "pom-root", summary = "Generates the POM file in the root directory") + public void pomRoot() throws FileUtilsErrorException { + PomBuilder.generateInto(publishOperation().fromProject(this).info(), dependencies(), + new File(workDirectory, "pom.xml")); + } + @BuildCommand(value = "release-info", summary = "Generates the ReleaseInfo class") public void releaseInfo() throws Exception { new GeneratedVersionOperation() @@ -211,10 +217,4 @@ public class MobibotBuild extends Project { .extension(".kt") .execute(); } - - @BuildCommand(value = "pom-root", summary = "Generates the POM file in the root directory") - public void pomRoot() throws FileUtilsErrorException { - PomBuilder.generateInto(publishOperation().fromProject(this).info(), dependencies(), - new File(workDirectory, "pom.xml")); - } } From 64bd5c92afdbd834f5833738d39f5e4ba371c49d Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Wed, 27 Nov 2024 22:32:12 -0800 Subject: [PATCH 805/844] Don't clean/delete deploy dir if not there --- src/bld/java/net/thauvin/erik/MobibotBuild.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index 897a966..c95d779 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -141,7 +141,10 @@ public class MobibotBuild extends Project { @Override public void clean() throws Exception { - FileUtils.deleteDirectory(new File("deploy")); + var deploy = new File("deploy"); + if (deploy.exists()) { + FileUtils.deleteDirectory(deploy); + } super.clean(); } From 700369d7c9b363c5ee5e992f2820269471b2bbf5 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sat, 21 Dec 2024 06:59:40 -0800 Subject: [PATCH 806/844] Updated dependencies Bumped JUnit to version 5.11.4 Bumped Log4j to version 2.24.3 Bumped Commons Text to version 1.13.0 Bumped Jsoup to version 1.18.3 Bumped Kotlin Coroutines to version 1.10.1 Bumped Kotlin extension to version 1.0.3 --- lib/bld/bld-wrapper.properties | 2 +- .../java/net/thauvin/erik/MobibotBuild.java | 20 ++++++++++--------- .../thauvin/erik/mobibot/modules/Gemini2.kt | 1 - 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/lib/bld/bld-wrapper.properties b/lib/bld/bld-wrapper.properties index 547a2bb..ae6925d 100644 --- a/lib/bld/bld-wrapper.properties +++ b/lib/bld/bld-wrapper.properties @@ -4,7 +4,7 @@ bld.downloadLocation= bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.7 bld.extension-gv=com.uwyn.rife2:bld-generated-version:0.9.9 bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.8 -bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.0.2 +bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.0.3 bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES bld.sourceDirectories= bld.version=2.1.0 diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index c95d779..6800ec1 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -76,7 +76,7 @@ public class MobibotBuild extends Project { new Repository("https://jitpack.io"), SONATYPE_SNAPSHOTS_LEGACY); - var log4j = version(2, 24, 2); + var log4j = version(2, 24, 3); var kotlin = version(2, 1, 0); var langchain = version(0, 36, 2); scope(compile) @@ -84,7 +84,7 @@ public class MobibotBuild extends Project { .include(dependency("com.github.pircbotx", "pircbotx", "2.3.1")) // Commons (mostly for PircBotX) .include(dependency("org.apache.commons", "commons-lang3", "3.17.0")) - .include(dependency("org.apache.commons", "commons-text", "1.12.0")) + .include(dependency("org.apache.commons", "commons-text", "1.13.0")) .include(dependency("commons-codec", "commons-codec", "1.17.1")) .include(dependency("commons-net", "commons-net", "3.11.1")) // Google @@ -95,7 +95,7 @@ public class MobibotBuild extends Project { .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-common", kotlin)) .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-jdk7", kotlin)) .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-jdk8", kotlin)) - .include(dependency("org.jetbrains.kotlinx", "kotlinx-coroutines-core", "1.9.0")) + .include(dependency("org.jetbrains.kotlinx", "kotlinx-coroutines-core", "1.10.1")) .include(dependency("org.jetbrains.kotlinx", "kotlinx-cli-jvm", "0.3.6")) // Logging .include(dependency("org.slf4j", "slf4j-api", "2.0.16")) @@ -113,7 +113,7 @@ public class MobibotBuild extends Project { .include(dependency("net.aksingh", "owm-japis", "2.5.3.0")) .include(dependency("net.objecthunter", "exp4j", "0.4.8")) .include(dependency("org.json", "json", "20240303")) - .include(dependency("org.jsoup", "jsoup", "1.18.2")) + .include(dependency("org.jsoup", "jsoup", "1.18.3")) // Thauvin .include(dependency("net.thauvin.erik", "cryptoprice", "1.0.3-SNAPSHOT")) .include(dependency("net.thauvin.erik", "jokeapi", "0.9.2-SNAPSHOT")) @@ -122,8 +122,8 @@ public class MobibotBuild extends Project { scope(test) .include(dependency("com.willowtreeapps.assertk", "assertk-jvm", version(0, 28, 1))) .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", kotlin)) - .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 11, 3))) - .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 11, 3))); + .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 11, 4))) + .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 11, 4))); List jars = new ArrayList<>(); runtimeClasspathJars().forEach(f -> jars.add("./lib/" + f.getName())); @@ -152,9 +152,11 @@ public class MobibotBuild extends Project { @Override public void compile() throws Exception { releaseInfo(); - new CompileKotlinOperation() - .fromProject(this) - .execute(); + var op = new CompileKotlinOperation() + .kotlinHome("/opt/kotlinc/") + .fromProject(this); + op.compileOptions().verbose(true); + op.execute(); } @Override diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini2.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini2.kt index 812aed3..365fe60 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini2.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini2.kt @@ -39,7 +39,6 @@ import org.slf4j.Logger import org.slf4j.LoggerFactory import java.util.* - class Gemini2 : AbstractModule() { private val logger: Logger = LoggerFactory.getLogger(Gemini2::class.java) From 4f0f4214c531fcd72fd6f18159069bc467628ac1 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sat, 21 Dec 2024 07:14:10 -0800 Subject: [PATCH 807/844] Updated POM --- pom.xml | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/pom.xml b/pom.xml index a50df02..8c805f1 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 net.thauvin.erik.mobibot mobibot - 0.8.0-rc+20240918181213 + 0.8.0-rc+20241221064558 mobibot @@ -24,7 +24,7 @@ org.apache.commons commons-text - 1.12.0 + 1.13.0 compile @@ -54,31 +54,31 @@ org.jetbrains.kotlin kotlin-stdlib - 2.0.20 + 2.1.0 compile org.jetbrains.kotlin kotlin-stdlib-common - 2.0.20 + 2.1.0 compile org.jetbrains.kotlin kotlin-stdlib-jdk7 - 2.0.20 + 2.1.0 compile org.jetbrains.kotlin kotlin-stdlib-jdk8 - 2.0.20 + 2.1.0 compile org.jetbrains.kotlinx kotlinx-coroutines-core - 1.9.0 + 1.10.1 compile @@ -96,43 +96,43 @@ org.apache.logging.log4j log4j-api - 2.24.0 + 2.24.3 compile org.apache.logging.log4j log4j-core - 2.24.0 + 2.24.3 compile org.apache.logging.log4j log4j-slf4j2-impl - 2.24.0 + 2.24.3 compile dev.langchain4j langchain4j-open-ai - 0.34.0 + 0.36.2 compile dev.langchain4j langchain4j-google-ai-gemini - 0.34.0 + 0.36.2 compile dev.langchain4j langchain4j-core - 0.34.0 + 0.36.2 compile dev.langchain4j langchain4j - 0.34.0 + 0.36.2 compile @@ -168,7 +168,7 @@ org.jsoup jsoup - 1.18.1 + 1.18.3 compile @@ -192,7 +192,7 @@ net.thauvin.erik.urlencoder urlencoder-lib-jvm - 1.5.0 + 1.6.0 compile From 67de345c2590401c0803fb1fbddffbdadb21359e Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sat, 21 Dec 2024 07:21:48 -0800 Subject: [PATCH 808/844] Fixed kotlin coverage version --- .github/workflows/bld.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/bld.yml b/.github/workflows/bld.yml index cb0ad5d..cf1ac97 100644 --- a/.github/workflows/bld.yml +++ b/.github/workflows/bld.yml @@ -7,7 +7,7 @@ env: CHATGPT_API_KEY: ${{ secrets.CHATGPT_API_KEY }} CI_NAME: "GitHub CI" COVERAGE_JDK: "21" - COVERAGE_KOTLIN: "2.0.0" + COVERAGE_KOTLIN: "2.1.0" EXCHANGERATE_API_KEY: ${{ secrets.EXCHANGERATE_API_KEY }} KOTLIN_HOME: /usr/share/kotlinc MASTODON_ACCESS_TOKEN: ${{ secrets.MASTODON_ACCESS_TOKEN }} From 16ac7937fa001f90cb0f0e41089e467deccaa699 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Thu, 2 Jan 2025 17:58:37 -0800 Subject: [PATCH 809/844] build: Bump org.json to version 20241224 --- pom.xml | 6 +++--- src/bld/java/net/thauvin/erik/MobibotBuild.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 8c805f1..5b7ef1c 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 net.thauvin.erik.mobibot mobibot - 0.8.0-rc+20241221064558 + 0.8.0-rc+20250102175731 mobibot @@ -162,7 +162,7 @@ org.json json - 20240303 + 20241224 compile @@ -180,7 +180,7 @@ net.thauvin.erik jokeapi - 0.9.2-SNAPSHOT + 1.0.0-SNAPSHOT compile diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index 6800ec1..192b596 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -112,7 +112,7 @@ public class MobibotBuild extends Project { .include(dependency("com.squareup.okhttp3", "okhttp", "4.12.0")) .include(dependency("net.aksingh", "owm-japis", "2.5.3.0")) .include(dependency("net.objecthunter", "exp4j", "0.4.8")) - .include(dependency("org.json", "json", "20240303")) + .include(dependency("org.json", "json", "20241224")) .include(dependency("org.jsoup", "jsoup", "1.18.3")) // Thauvin .include(dependency("net.thauvin.erik", "cryptoprice", "1.0.3-SNAPSHOT")) From f05ab9751361758d695f12d2a6afd24dd4003fb6 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Thu, 2 Jan 2025 17:59:13 -0800 Subject: [PATCH 810/844] build: Bump JokeApi to version 1.0.0-SNAPSHOT --- src/bld/java/net/thauvin/erik/MobibotBuild.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index 192b596..a7164f8 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -116,7 +116,7 @@ public class MobibotBuild extends Project { .include(dependency("org.jsoup", "jsoup", "1.18.3")) // Thauvin .include(dependency("net.thauvin.erik", "cryptoprice", "1.0.3-SNAPSHOT")) - .include(dependency("net.thauvin.erik", "jokeapi", "0.9.2-SNAPSHOT")) + .include(dependency("net.thauvin.erik", "jokeapi", "1.0.0-SNAPSHOT")) .include(dependency("net.thauvin.erik", "pinboard-poster", "1.1.2-SNAPSHOT")) .include(dependency("net.thauvin.erik.urlencoder", "urlencoder-lib-jvm", "1.6.0")); scope(test) From f58951846635baa4532115ed8d4edd586aaa300e Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Thu, 2 Jan 2025 18:00:17 -0800 Subject: [PATCH 811/844] chore: Update copyright notices for 2025 --- LICENSE.txt | 2 +- .../java/net/thauvin/erik/MobibotBuild.java | 2 +- .../kotlin/net/thauvin/erik/mobibot/Addons.kt | 2 +- .../net/thauvin/erik/mobibot/Constants.kt | 2 +- .../net/thauvin/erik/mobibot/FeedReader.kt | 2 +- .../net/thauvin/erik/mobibot/Mobibot.kt | 2 +- .../net/thauvin/erik/mobibot/Pinboard.kt | 2 +- .../net/thauvin/erik/mobibot/ReleaseInfo.kt | 35 +++++++++++++++++-- .../kotlin/net/thauvin/erik/mobibot/Utils.kt | 2 +- .../erik/mobibot/commands/AbstractCommand.kt | 2 +- .../erik/mobibot/commands/ChannelFeed.kt | 2 +- .../thauvin/erik/mobibot/commands/Cycle.kt | 2 +- .../net/thauvin/erik/mobibot/commands/Die.kt | 2 +- .../thauvin/erik/mobibot/commands/Ignore.kt | 2 +- .../net/thauvin/erik/mobibot/commands/Info.kt | 2 +- .../net/thauvin/erik/mobibot/commands/Me.kt | 2 +- .../thauvin/erik/mobibot/commands/Modules.kt | 2 +- .../net/thauvin/erik/mobibot/commands/Msg.kt | 2 +- .../net/thauvin/erik/mobibot/commands/Nick.kt | 2 +- .../thauvin/erik/mobibot/commands/Recap.kt | 2 +- .../net/thauvin/erik/mobibot/commands/Say.kt | 2 +- .../thauvin/erik/mobibot/commands/Users.kt | 2 +- .../thauvin/erik/mobibot/commands/Versions.kt | 2 +- .../erik/mobibot/commands/links/Comment.kt | 2 +- .../mobibot/commands/links/LinksManager.kt | 2 +- .../erik/mobibot/commands/links/Posting.kt | 2 +- .../erik/mobibot/commands/links/Tags.kt | 2 +- .../erik/mobibot/commands/links/View.kt | 2 +- .../mobibot/commands/seen/NickComparator.kt | 2 +- .../erik/mobibot/commands/seen/Seen.kt | 2 +- .../erik/mobibot/commands/seen/SeenNick.kt | 2 +- .../erik/mobibot/commands/tell/Tell.kt | 2 +- .../erik/mobibot/commands/tell/TellManager.kt | 2 +- .../erik/mobibot/commands/tell/TellMessage.kt | 2 +- .../thauvin/erik/mobibot/entries/Entries.kt | 2 +- .../erik/mobibot/entries/EntriesUtils.kt | 2 +- .../erik/mobibot/entries/EntryComment.kt | 2 +- .../thauvin/erik/mobibot/entries/EntryLink.kt | 2 +- .../erik/mobibot/entries/FeedsManager.kt | 2 +- .../erik/mobibot/modules/AbstractModule.kt | 2 +- .../net/thauvin/erik/mobibot/modules/Calc.kt | 2 +- .../thauvin/erik/mobibot/modules/ChatGpt2.kt | 4 +-- .../erik/mobibot/modules/CryptoPrices.kt | 2 +- .../erik/mobibot/modules/CurrencyConverter.kt | 2 +- .../net/thauvin/erik/mobibot/modules/Dice.kt | 2 +- .../thauvin/erik/mobibot/modules/Gemini2.kt | 4 +-- .../erik/mobibot/modules/GoogleSearch.kt | 2 +- .../net/thauvin/erik/mobibot/modules/Joke.kt | 2 +- .../thauvin/erik/mobibot/modules/Lookup.kt | 2 +- .../thauvin/erik/mobibot/modules/Mastodon.kt | 2 +- .../erik/mobibot/modules/ModuleException.kt | 2 +- .../net/thauvin/erik/mobibot/modules/Ping.kt | 2 +- .../erik/mobibot/modules/RockPaperScissors.kt | 2 +- .../erik/mobibot/modules/StockQuote.kt | 2 +- .../net/thauvin/erik/mobibot/modules/War.kt | 2 +- .../thauvin/erik/mobibot/modules/Weather2.kt | 2 +- .../erik/mobibot/modules/WolframAlpha.kt | 2 +- .../thauvin/erik/mobibot/modules/WorldTime.kt | 2 +- .../thauvin/erik/mobibot/msg/ErrorMessage.kt | 2 +- .../net/thauvin/erik/mobibot/msg/Message.kt | 2 +- .../thauvin/erik/mobibot/msg/NoticeMessage.kt | 2 +- .../erik/mobibot/msg/PrivateMessage.kt | 2 +- .../thauvin/erik/mobibot/msg/PublicMessage.kt | 2 +- .../erik/mobibot/social/SocialManager.kt | 2 +- .../erik/mobibot/social/SocialModule.kt | 2 +- .../erik/mobibot/social/SocialTimer.kt | 2 +- .../net/thauvin/erik/mobibot/AddonsTest.kt | 2 +- .../net/thauvin/erik/mobibot/DisableOnCi.kt | 2 +- .../erik/mobibot/DisableOnCiCondition.kt | 2 +- .../erik/mobibot/ExceptionSanitizer.kt | 2 +- .../thauvin/erik/mobibot/FeedReaderTest.kt | 2 +- .../thauvin/erik/mobibot/LocalProperties.kt | 2 +- .../net/thauvin/erik/mobibot/PinboardTest.kt | 2 +- .../net/thauvin/erik/mobibot/UtilsTest.kt | 2 +- .../thauvin/erik/mobibot/commands/InfoTest.kt | 2 +- .../erik/mobibot/commands/RecapTest.kt | 2 +- .../commands/links/LinksManagerTest.kt | 2 +- .../erik/mobibot/commands/links/ViewTest.kt | 2 +- .../erik/mobibot/commands/seen/SeenTest.kt | 2 +- .../mobibot/commands/tell/TellMessageTest.kt | 2 +- .../commands/tell/TellMessagesMgrTest.kt | 2 +- .../erik/mobibot/entries/EntriesUtilsTest.kt | 2 +- .../erik/mobibot/entries/EntryLinkTest.kt | 2 +- .../erik/mobibot/entries/FeedMgrTest.kt | 2 +- .../thauvin/erik/mobibot/modules/CalcTest.kt | 2 +- .../erik/mobibot/modules/ChatGpt2Test.kt | 4 +-- .../erik/mobibot/modules/CryptoPricesTest.kt | 2 +- .../mobibot/modules/CurrencyConverterTest.kt | 2 +- .../thauvin/erik/mobibot/modules/DiceTest.kt | 2 +- .../erik/mobibot/modules/Gemini2Test.kt | 4 +-- .../erik/mobibot/modules/GoogleSearchTest.kt | 2 +- .../thauvin/erik/mobibot/modules/JokeTest.kt | 2 +- .../erik/mobibot/modules/LookupTest.kt | 2 +- .../erik/mobibot/modules/MastodonTest.kt | 2 +- .../mobibot/modules/ModuleExceptionTest.kt | 2 +- .../thauvin/erik/mobibot/modules/PingTest.kt | 2 +- .../mobibot/modules/RockPaperScissorsTest.kt | 2 +- .../erik/mobibot/modules/StockQuoteTest.kt | 2 +- .../erik/mobibot/modules/Weather2Test.kt | 2 +- .../erik/mobibot/modules/WolframAlphaTest.kt | 2 +- .../erik/mobibot/modules/WordTimeTest.kt | 2 +- .../thauvin/erik/mobibot/msg/MessageTest.kt | 2 +- 102 files changed, 138 insertions(+), 107 deletions(-) diff --git a/LICENSE.txt b/LICENSE.txt index 16e13ca..54e8774 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) +Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index a7164f8..6aa683c 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -1,7 +1,7 @@ /* * MobibotBuild.java * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt index f3ae0a3..ed34897 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt @@ -1,7 +1,7 @@ /* * Addons.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt index 8716e14..d00939e 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt @@ -1,7 +1,7 @@ /* * Constants.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt b/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt index a91c6dc..3ab8d1f 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt @@ -1,7 +1,7 @@ /* * FeedReader.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt index 1e49a88..691a339 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt @@ -1,7 +1,7 @@ /* * Mobibot.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt index 88e475e..f9076c9 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt @@ -1,7 +1,7 @@ /* * Pinboard.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt b/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt index 5b5e5d2..7571a9f 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt @@ -1,3 +1,34 @@ +/* + * ReleaseInfo.kt + * + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + /* * This file is automatically generated * Do not modify! -- ALL CHANGES WILL BE ERASED! @@ -14,12 +45,12 @@ import java.time.ZoneId */ object ReleaseInfo { const val PROJECT = "mobibot" - const val VERSION = "0.8.0-rc+20240908190240" + const val VERSION = "0.8.0-rc+20250102175731" @JvmField @Suppress("MagicNumber") val BUILD_DATE: LocalDateTime = LocalDateTime.ofInstant( - Instant.ofEpochMilli(1725847361020L), ZoneId.systemDefault() + Instant.ofEpochMilli(1735869451156L), ZoneId.systemDefault() ) const val WEBSITE = "https://mobitopia.org/mobibot/" diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt index 92b4883..fc5ee7d 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt @@ -1,7 +1,7 @@ /* * Utils.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/AbstractCommand.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/AbstractCommand.kt index 5f79fab..4642f42 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/AbstractCommand.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/AbstractCommand.kt @@ -1,7 +1,7 @@ /* * AbstractCommand.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/ChannelFeed.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/ChannelFeed.kt index 873d31f..0075293 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/ChannelFeed.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/ChannelFeed.kt @@ -1,7 +1,7 @@ /* * ChannelFeed.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Cycle.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Cycle.kt index 88b6c6d..cefcde3 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Cycle.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Cycle.kt @@ -1,7 +1,7 @@ /* * Cycle.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Die.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Die.kt index e4e111d..d7577af 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Die.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Die.kt @@ -1,7 +1,7 @@ /* * Die.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt index 6dfff07..13b20b0 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt @@ -1,7 +1,7 @@ /* * Ignore.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Info.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Info.kt index 4fae22f..8e244cc 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Info.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Info.kt @@ -1,7 +1,7 @@ /* * Info.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Me.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Me.kt index 3495b28..afa9046 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Me.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Me.kt @@ -1,7 +1,7 @@ /* * Me.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Modules.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Modules.kt index 314ce99..8668bf7 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Modules.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Modules.kt @@ -1,7 +1,7 @@ /* * Modules.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Msg.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Msg.kt index bddd56c..14d8d8e 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Msg.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Msg.kt @@ -1,7 +1,7 @@ /* * Msg.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Nick.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Nick.kt index 59b474a..21c96b5 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Nick.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Nick.kt @@ -1,7 +1,7 @@ /* * Nick.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Recap.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Recap.kt index 886b26c..500fd85 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Recap.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Recap.kt @@ -1,7 +1,7 @@ /* * Recap.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Say.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Say.kt index 90f3c04..b9d410d 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Say.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Say.kt @@ -1,7 +1,7 @@ /* * Say.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Users.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Users.kt index 54a85b2..960b8aa 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Users.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Users.kt @@ -1,7 +1,7 @@ /* * Users.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Versions.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Versions.kt index f422566..62cb044 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Versions.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Versions.kt @@ -1,7 +1,7 @@ /* * Versions.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Comment.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Comment.kt index 2fade4e..f0d9d0c 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Comment.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Comment.kt @@ -1,7 +1,7 @@ /* * Comment.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManager.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManager.kt index ea18613..e688092 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManager.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManager.kt @@ -1,7 +1,7 @@ /* * LinksManager.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Posting.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Posting.kt index 2d24ba7..a47021b 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Posting.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Posting.kt @@ -1,7 +1,7 @@ /* * Posting.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Tags.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Tags.kt index 1a582a9..0d73f6e 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Tags.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Tags.kt @@ -1,7 +1,7 @@ /* * Tags.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/View.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/View.kt index e6971ef..6891c2d 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/View.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/View.kt @@ -1,7 +1,7 @@ /* * View.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt index e51a6bf..f44b357 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt @@ -1,7 +1,7 @@ /* * NickComparator.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt index 1ad12f6..8af98dc 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt @@ -1,7 +1,7 @@ /* * Seen.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt index 69923db..21d7cb9 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt @@ -1,7 +1,7 @@ /* * SeenNick.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt index 790ce0e..c204062 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt @@ -1,7 +1,7 @@ /* * Tell.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellManager.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellManager.kt index f34af98..f193a3c 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellManager.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellManager.kt @@ -1,7 +1,7 @@ /* * TellManager.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt index ac15595..1f55687 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt @@ -1,7 +1,7 @@ /* * TellMessage.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/Entries.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/Entries.kt index 676fbee..4e187d4 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/Entries.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/Entries.kt @@ -1,7 +1,7 @@ /* * Entries.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt index ea536bc..1588704 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt @@ -1,7 +1,7 @@ /* * EntriesUtils.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryComment.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryComment.kt index d9d5587..1826101 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryComment.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryComment.kt @@ -1,7 +1,7 @@ /* * EntryComment.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt index c88f8a4..a807f07 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt @@ -1,7 +1,7 @@ /* * EntryLink.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt index 4dc8e9e..a881204 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt @@ -1,7 +1,7 @@ /* * FeedsManager.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/AbstractModule.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/AbstractModule.kt index 17dbde2..1ced830 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/AbstractModule.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/AbstractModule.kt @@ -1,7 +1,7 @@ /* * AbstractModule.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Calc.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Calc.kt index b5fe5b1..7fd320f 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Calc.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Calc.kt @@ -1,7 +1,7 @@ /* * Calc.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt2.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt2.kt index 854bb9f..9d654c8 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt2.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt2.kt @@ -1,7 +1,7 @@ /* - * ChatGpt.kt + * ChatGpt2.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt index fe95fe0..2186d73 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt @@ -1,7 +1,7 @@ /* * CryptoPrices.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt index 3c8ea92..2ff4715 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt @@ -1,7 +1,7 @@ /* * CurrencyConverter.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Dice.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Dice.kt index b6d69ec..5c1dd09 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Dice.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Dice.kt @@ -1,7 +1,7 @@ /* * Dice.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini2.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini2.kt index 365fe60..385e96e 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini2.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini2.kt @@ -1,7 +1,7 @@ /* - * Gemini.kt + * Gemini2.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt index 1611130..26f3e71 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt @@ -1,7 +1,7 @@ /* * GoogleSearch.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Joke.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Joke.kt index 1c6a5eb..e792ed4 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Joke.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Joke.kt @@ -1,7 +1,7 @@ /* * Joke.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Lookup.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Lookup.kt index baeebba..f700757 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Lookup.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Lookup.kt @@ -1,7 +1,7 @@ /* * Lookup.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Mastodon.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Mastodon.kt index 166e39f..d4c2614 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Mastodon.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Mastodon.kt @@ -1,7 +1,7 @@ /* * Mastodon.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ModuleException.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ModuleException.kt index 32240ca..26d374a 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ModuleException.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ModuleException.kt @@ -1,7 +1,7 @@ /* * ModuleException.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Ping.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Ping.kt index 4b56df5..ca18216 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Ping.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Ping.kt @@ -1,7 +1,7 @@ /* * Ping.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt index 13afbb7..b8c81f1 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt @@ -1,7 +1,7 @@ /* * RockPaperScissors.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt index 13b9329..d71c91a 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt @@ -1,7 +1,7 @@ /* * StockQuote.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/War.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/War.kt index e0fd947..70ac4ec 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/War.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/War.kt @@ -1,7 +1,7 @@ /* * War.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt index 21bf0ae..074edd0 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt @@ -1,7 +1,7 @@ /* * Weather2.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt index ba88711..2e2e7ec 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt @@ -1,7 +1,7 @@ /* * WolframAlpha.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WorldTime.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WorldTime.kt index 8978275..afc0a5f 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WorldTime.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WorldTime.kt @@ -1,7 +1,7 @@ /* * WorldTime.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/ErrorMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/ErrorMessage.kt index abcd043..56e7b92 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/ErrorMessage.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/msg/ErrorMessage.kt @@ -1,7 +1,7 @@ /* * ErrorMessage.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/Message.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/Message.kt index 4b788ba..1a6e58b 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/Message.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/msg/Message.kt @@ -1,7 +1,7 @@ /* * Message.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/NoticeMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/NoticeMessage.kt index ea11c9c..f06ce89 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/NoticeMessage.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/msg/NoticeMessage.kt @@ -1,7 +1,7 @@ /* * NoticeMessage.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/PrivateMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/PrivateMessage.kt index 27b1cbd..ef0eeb1 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/PrivateMessage.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/msg/PrivateMessage.kt @@ -1,7 +1,7 @@ /* * PrivateMessage.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/PublicMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/PublicMessage.kt index ae909f6..be6583f 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/PublicMessage.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/msg/PublicMessage.kt @@ -1,7 +1,7 @@ /* * PublicMessage.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialManager.kt b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialManager.kt index c785106..de9653d 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialManager.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialManager.kt @@ -1,7 +1,7 @@ /* * SocialManager.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialModule.kt b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialModule.kt index a13b429..d45cf5c 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialModule.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialModule.kt @@ -1,7 +1,7 @@ /* * SocialModule.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialTimer.kt b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialTimer.kt index e722ed8..aadebf5 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialTimer.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialTimer.kt @@ -1,7 +1,7 @@ /* * SocialTimer.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt index 4555884..27163fb 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt @@ -1,7 +1,7 @@ /* * AddonsTest.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCi.kt b/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCi.kt index 8d73a5e..75a1cf9 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCi.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCi.kt @@ -1,7 +1,7 @@ /* * DisableOnCi.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCiCondition.kt b/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCiCondition.kt index b0f4771..d887b55 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCiCondition.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCiCondition.kt @@ -1,7 +1,7 @@ /* * DisableOnCiCondition.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/ExceptionSanitizer.kt b/src/test/kotlin/net/thauvin/erik/mobibot/ExceptionSanitizer.kt index d1ca71d..3a4adb0 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/ExceptionSanitizer.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/ExceptionSanitizer.kt @@ -1,7 +1,7 @@ /* * ExceptionSanitizer.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt index 1cb2645..0c3d1c6 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt @@ -1,7 +1,7 @@ /* * FeedReaderTest.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/LocalProperties.kt b/src/test/kotlin/net/thauvin/erik/mobibot/LocalProperties.kt index c290262..646a0ea 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/LocalProperties.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/LocalProperties.kt @@ -1,7 +1,7 @@ /* * LocalProperties.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/PinboardTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/PinboardTest.kt index 7e56912..dafb862 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/PinboardTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/PinboardTest.kt @@ -1,7 +1,7 @@ /* * PinboardTest.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt index 49ee7fa..bd05f70 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt @@ -1,7 +1,7 @@ /* * UtilsTest.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/InfoTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/InfoTest.kt index add701e..f332005 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/InfoTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/InfoTest.kt @@ -1,7 +1,7 @@ /* * InfoTest.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/RecapTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/RecapTest.kt index 875342b..ef6f461 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/RecapTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/RecapTest.kt @@ -1,7 +1,7 @@ /* * RecapTest.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt index 59338f4..676c5b6 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt @@ -1,7 +1,7 @@ /* * LinksManagerTest.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/ViewTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/ViewTest.kt index 9eb433a..abf8224 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/ViewTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/ViewTest.kt @@ -1,7 +1,7 @@ /* * ViewTest.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt index 6d5ba78..7b946dc 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt @@ -1,7 +1,7 @@ /* * SeenTest.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt index 33b3598..443c1f9 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt @@ -1,7 +1,7 @@ /* * TellMessageTest.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt index d7bde4c..6d3bb6b 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt @@ -1,7 +1,7 @@ /* * TellMessagesMgrTest.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt index 983e225..f67a057 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt @@ -1,7 +1,7 @@ /* * EntriesUtilsTest.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt index 577f425..3479108 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt @@ -1,7 +1,7 @@ /* * EntryLinkTest.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt index d2b959e..5803092 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt @@ -1,7 +1,7 @@ /* * FeedMgrTest.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt index e7ef601..140b8a1 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt @@ -1,7 +1,7 @@ /* * CalcTest.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt2Test.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt2Test.kt index 4332a52..c4699a5 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt2Test.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt2Test.kt @@ -1,7 +1,7 @@ /* - * ChatGptTest.kt + * ChatGpt2Test.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt index 0e2ef84..34b8369 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt @@ -1,7 +1,7 @@ /* * CryptoPricesTest.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt index 5ebb7dc..c1c0efc 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt @@ -1,7 +1,7 @@ /* * CurrencyConverterTest.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/DiceTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/DiceTest.kt index 007f22f..e34de7b 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/DiceTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/DiceTest.kt @@ -1,7 +1,7 @@ /* * DiceTest.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/Gemini2Test.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/Gemini2Test.kt index 226ff6a..269874a 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/Gemini2Test.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/Gemini2Test.kt @@ -1,7 +1,7 @@ /* - * GeminiTest.kt + * Gemini2Test.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt index 752b49e..f9b0832 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt @@ -1,7 +1,7 @@ /* * GoogleSearchTest.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/JokeTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/JokeTest.kt index 118d736..cf6d03c 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/JokeTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/JokeTest.kt @@ -1,7 +1,7 @@ /* * JokeTest.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt index 048d91a..abb9235 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt @@ -1,7 +1,7 @@ /* * LookupTest.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt index 11d4a51..a9e1d43 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt @@ -1,7 +1,7 @@ /* * MastodonTest.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt index ff706fd..6c3c54c 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt @@ -1,7 +1,7 @@ /* * ModuleExceptionTest.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/PingTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/PingTest.kt index 5532e30..f51e203 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/PingTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/PingTest.kt @@ -1,7 +1,7 @@ /* * PingTest.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt index 0e4b4ec..519037a 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt @@ -1,7 +1,7 @@ /* * RockPaperScissorsTest.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt index 3fe9189..955a267 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt @@ -1,7 +1,7 @@ /* * StockQuoteTest.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt index f4f85f8..5d04560 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt @@ -1,7 +1,7 @@ /* * Weather2Test.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt index 4f827bb..099f3f9 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt @@ -1,7 +1,7 @@ /* * WolframAlphaTest.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt index 1211ea4..396efaf 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt @@ -1,7 +1,7 @@ /* * WordTimeTest.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/msg/MessageTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/msg/MessageTest.kt index 44054f1..6e85ed1 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/msg/MessageTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/msg/MessageTest.kt @@ -1,7 +1,7 @@ /* * MessageTest.kt * - * Copyright 2004-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: From 1a1195ca285df29351f72c882aa9ea8e4e4bda46 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Tue, 18 Mar 2025 05:06:57 -0700 Subject: [PATCH 812/844] Bump bld to version 2.2.1 --- .idea/libraries/bld.xml | 4 ++-- README.md | 2 +- lib/bld/bld-wrapper.jar | Bin 30440 -> 30440 bytes lib/bld/bld-wrapper.properties | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.idea/libraries/bld.xml b/.idea/libraries/bld.xml index 5c4010c..153a060 100644 --- a/.idea/libraries/bld.xml +++ b/.idea/libraries/bld.xml @@ -2,12 +2,12 @@ - + - + diff --git a/README.md b/README.md index b31ec67..8d62a9f 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # mobibot [![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) -[![Kotlin](https://img.shields.io/badge/kotlin-2.1.0-7f52ff.svg)](https://kotlinlang.org) [![bld](https://img.shields.io/badge/2.1.0-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) +[![bld](https://img.shields.io/badge/2.2.1-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ethauvin_mobibot&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=ethauvin_mobibot) [![GitHub CI](https://github.com/ethauvin/mobibot/actions/workflows/bld.yml/badge.svg)](https://github.com/ethauvin/mobibot/actions/workflows/bld.yml) [![CircleCI](https://circleci.com/gh/ethauvin/mobibot/tree/master.svg?style=shield)](https://circleci.com/gh/ethauvin/mobibot/tree/master) diff --git a/lib/bld/bld-wrapper.jar b/lib/bld/bld-wrapper.jar index 5425f1c05b18a00f2f1d69df4fc5885b310c372a..73cde27f29a182647776c29655512b0bfa0749f0 100644 GIT binary patch delta 203 zcmaFymhr_~M!o=VW)=|!4h{|mzs(U*6ZvXcK=j6b6B{sNa-Y4%=Jz(UnZUfwefC{Y zmW&gd9z;y7;2a}_^`p=LB0E{9L{8*i9|;9^1_lOJAP(?mWD;RO*f%+^ q#0g^0mJ$yzV^V1_L?9f-SXb%-5&2dc3zaJK;{dr5Wb)*-W!3VxO6ZvXcK=j6b6B{sNa-Y4%=Jz(UnZUfwefC{Y zmW&gd9z;y7;2a}_^`p=LB0E{9L{8<3F#|(@H#^70qR3Eo1_lOJAP(?mWD;RO*f%+^ q#0g^0mJ$yzV^V1_L?9f-SXb%-5&2dc3zaJK;{dr5Wb)*-W!3<}MnA^@ diff --git a/lib/bld/bld-wrapper.properties b/lib/bld/bld-wrapper.properties index ae6925d..478b956 100644 --- a/lib/bld/bld-wrapper.properties +++ b/lib/bld/bld-wrapper.properties @@ -7,4 +7,4 @@ bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.8 bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.0.3 bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES bld.sourceDirectories= -bld.version=2.1.0 +bld.version=2.2.1 From 765279c88718837b52d84792e979ad29b3a59d33 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Tue, 18 Mar 2025 05:08:37 -0700 Subject: [PATCH 813/844] Bump Kotlin to version 2.1.10 --- .circleci/config.yml | 2 +- .github/workflows/bld.yml | 2 +- README.md | 2 +- lib/bld/bld-wrapper.properties | 4 +--- src/bld/java/net/thauvin/erik/MobibotBuild.java | 2 +- 5 files changed, 5 insertions(+), 7 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 8dabc3f..8814d91 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -21,7 +21,7 @@ commands: - sdkman/setup-sdkman - sdkman/sdkman-install: candidate: kotlin - version: 2.0.20 + version: 2.1.10 - run: name: Download dependencies command: ./bld download diff --git a/.github/workflows/bld.yml b/.github/workflows/bld.yml index cf1ac97..48f1a71 100644 --- a/.github/workflows/bld.yml +++ b/.github/workflows/bld.yml @@ -23,7 +23,7 @@ jobs: strategy: matrix: java-version: [17, 21, 23] - kotlin-version: [1.9.24, 2.0.20, 2.1.0] + kotlin-version: [1.9.25, 2.0.20, 2.1.10] steps: - name: Checkout source repository diff --git a/README.md b/README.md index 8d62a9f..84d0ebc 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # mobibot [![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) -[![bld](https://img.shields.io/badge/2.1.0-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) +[![Kotlin](https://img.shields.io/badge/kotlin-2.1.10-7f52ff.svg)](https://kotlinlang.org) [![bld](https://img.shields.io/badge/2.2.1-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ethauvin_mobibot&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=ethauvin_mobibot) [![GitHub CI](https://github.com/ethauvin/mobibot/actions/workflows/bld.yml/badge.svg)](https://github.com/ethauvin/mobibot/actions/workflows/bld.yml) diff --git a/lib/bld/bld-wrapper.properties b/lib/bld/bld-wrapper.properties index 478b956..0a01ba1 100644 --- a/lib/bld/bld-wrapper.properties +++ b/lib/bld/bld-wrapper.properties @@ -1,10 +1,8 @@ bld.downloadExtensionJavadoc=false bld.downloadExtensionSources=true bld.downloadLocation= -bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.7 -bld.extension-gv=com.uwyn.rife2:bld-generated-version:0.9.9 -bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.8 bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.0.3 +bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.0.4 bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES bld.sourceDirectories= bld.version=2.2.1 diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index 6aa683c..6a9386a 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -77,7 +77,7 @@ public class MobibotBuild extends Project { SONATYPE_SNAPSHOTS_LEGACY); var log4j = version(2, 24, 3); - var kotlin = version(2, 1, 0); + var kotlin = version(2, 1, 10); var langchain = version(0, 36, 2); scope(compile) // PircBotX From 4d2f1e7978315c4b3aad5d41f81d7e295138a1fb Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Tue, 18 Mar 2025 05:15:01 -0700 Subject: [PATCH 814/844] Update dependencies Bump Detekt extension to version 0.9.9 Bump Generated Version extension t version 1.0.0 Bump Commons Codec to version 1.18.8 Bump Gson to version 2.12.1 Bump SLF4J to version 2.0.17 Bump org.json to version 20250107 Bump Jsoup to version 1.19.1 Bump Junit to version 5.12.1 --- lib/bld/bld-wrapper.properties | 4 +++- pom.xml | 24 +++++++++---------- .../java/net/thauvin/erik/MobibotBuild.java | 19 ++++++++------- 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/lib/bld/bld-wrapper.properties b/lib/bld/bld-wrapper.properties index 0a01ba1..c1b1941 100644 --- a/lib/bld/bld-wrapper.properties +++ b/lib/bld/bld-wrapper.properties @@ -1,7 +1,9 @@ bld.downloadExtensionJavadoc=false bld.downloadExtensionSources=true bld.downloadLocation= -bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.0.3 +bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.9 +bld.extension-gv=com.uwyn.rife2:bld-generated-version:1.0.0 +bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.9 bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.0.4 bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES bld.sourceDirectories= diff --git a/pom.xml b/pom.xml index 5b7ef1c..3543235 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 net.thauvin.erik.mobibot mobibot - 0.8.0-rc+20250102175731 + 0.8.0-rc+20250318045311 mobibot @@ -30,7 +30,7 @@ commons-codec commons-codec - 1.17.1 + 1.18.0 compile @@ -42,7 +42,7 @@ com.google.code.gson gson - 2.11.0 + 2.12.1 compile @@ -54,25 +54,25 @@ org.jetbrains.kotlin kotlin-stdlib - 2.1.0 + 2.1.10 compile org.jetbrains.kotlin kotlin-stdlib-common - 2.1.0 + 2.1.10 compile org.jetbrains.kotlin kotlin-stdlib-jdk7 - 2.1.0 + 2.1.10 compile org.jetbrains.kotlin kotlin-stdlib-jdk8 - 2.1.0 + 2.1.10 compile @@ -90,7 +90,7 @@ org.slf4j slf4j-api - 2.0.16 + 2.0.17 compile @@ -162,13 +162,13 @@ org.json json - 20241224 + 20250107 compile org.jsoup jsoup - 1.18.3 + 1.19.1 compile @@ -180,13 +180,13 @@ net.thauvin.erik jokeapi - 1.0.0-SNAPSHOT + 1.0.0 compile net.thauvin.erik pinboard-poster - 1.1.2-SNAPSHOT + 1.2.0 compile diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index 6a9386a..9ffb588 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -85,10 +85,10 @@ public class MobibotBuild extends Project { // Commons (mostly for PircBotX) .include(dependency("org.apache.commons", "commons-lang3", "3.17.0")) .include(dependency("org.apache.commons", "commons-text", "1.13.0")) - .include(dependency("commons-codec", "commons-codec", "1.17.1")) + .include(dependency("commons-codec", "commons-codec", "1.18.0")) .include(dependency("commons-net", "commons-net", "3.11.1")) // Google - .include(dependency("com.google.code.gson", "gson", "2.11.0")) + .include(dependency("com.google.code.gson", "gson", "2.12.1")) .include(dependency("com.google.guava", "guava", "33.2.1-jre")) // Kotlin .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlin)) @@ -98,7 +98,7 @@ public class MobibotBuild extends Project { .include(dependency("org.jetbrains.kotlinx", "kotlinx-coroutines-core", "1.10.1")) .include(dependency("org.jetbrains.kotlinx", "kotlinx-cli-jvm", "0.3.6")) // Logging - .include(dependency("org.slf4j", "slf4j-api", "2.0.16")) + .include(dependency("org.slf4j", "slf4j-api", "2.0.17")) .include(dependency("org.apache.logging.log4j", "log4j-api", log4j)) .include(dependency("org.apache.logging.log4j", "log4j-core", log4j)) .include(dependency("org.apache.logging.log4j", "log4j-slf4j2-impl", log4j)) @@ -112,18 +112,19 @@ public class MobibotBuild extends Project { .include(dependency("com.squareup.okhttp3", "okhttp", "4.12.0")) .include(dependency("net.aksingh", "owm-japis", "2.5.3.0")) .include(dependency("net.objecthunter", "exp4j", "0.4.8")) - .include(dependency("org.json", "json", "20241224")) - .include(dependency("org.jsoup", "jsoup", "1.18.3")) + .include(dependency("org.json", "json", "20250107")) + .include(dependency("org.jsoup", "jsoup", "1.19.1")) // Thauvin .include(dependency("net.thauvin.erik", "cryptoprice", "1.0.3-SNAPSHOT")) - .include(dependency("net.thauvin.erik", "jokeapi", "1.0.0-SNAPSHOT")) - .include(dependency("net.thauvin.erik", "pinboard-poster", "1.1.2-SNAPSHOT")) + .include(dependency("net.thauvin.erik", "jokeapi", "1.0.0")) + .include(dependency("net.thauvin.erik", "pinboard-poster", "1.2.0")) .include(dependency("net.thauvin.erik.urlencoder", "urlencoder-lib-jvm", "1.6.0")); scope(test) .include(dependency("com.willowtreeapps.assertk", "assertk-jvm", version(0, 28, 1))) .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", kotlin)) - .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 11, 4))) - .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 11, 4))); + .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 12, 1))) + .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 12, 1))) + .include(dependency("org.junit.platform", "junit-platform-launcher", version(1, 12, 1))); List jars = new ArrayList<>(); runtimeClasspathJars().forEach(f -> jars.add("./lib/" + f.getName())); From bfc468de5bd10bfa0631f04ad81551f18f19a7d7 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Tue, 18 Mar 2025 05:16:20 -0700 Subject: [PATCH 815/844] Bump JDK from version 20 to 21 --- .circleci/config.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 8814d91..c781fdc 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -46,11 +46,11 @@ jobs: steps: - build_and_test - bld_jdk20: + bld_jdk21: <<: *defaults docker: - - image: cimg/openjdk:20.0 + - image: cimg/openjdk:21.0 steps: - build_and_test @@ -59,4 +59,4 @@ workflows: bld: jobs: - bld_jdk17 - - bld_jdk20 + - bld_jdk21 From 00178b4e168eb4702c5e9d0f6f830d752b814e75 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Tue, 18 Mar 2025 14:55:36 -0700 Subject: [PATCH 816/844] Update User-Agent --- src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt | 3 +-- src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt index d00939e..0dea8d5 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt @@ -62,8 +62,7 @@ object Constants { /** * User-Agent */ - const val USER_AGENT = - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36" + const val USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0" /** * The help command. diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt index fc5ee7d..97797ef 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt @@ -424,7 +424,7 @@ object Utils { try { connection.setRequestProperty( "User-Agent", - "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/109.0" + Constants.USER_AGENT ) return if (connection.responseCode.isHttpSuccess()) { UrlReaderResponse( From daf5cad807417cb65735de31cdec23dcfa612bbd Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Tue, 18 Mar 2025 23:14:34 -0700 Subject: [PATCH 817/844] JDK 24 --- .github/workflows/bld.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/bld.yml b/.github/workflows/bld.yml index 48f1a71..3511dc4 100644 --- a/.github/workflows/bld.yml +++ b/.github/workflows/bld.yml @@ -22,7 +22,7 @@ jobs: strategy: matrix: - java-version: [17, 21, 23] + java-version: [17, 21, 24] kotlin-version: [1.9.25, 2.0.20, 2.1.10] steps: From e974f3f4bc08484733bf7679968b0e57d80b6a45 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Tue, 18 Mar 2025 23:55:13 -0700 Subject: [PATCH 818/844] Bump to GPT4 --- src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt2.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt2.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt2.kt index 9d654c8..fbf0e94 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt2.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt2.kt @@ -96,7 +96,7 @@ class ChatGpt2 : AbstractModule() { try { val model = OpenAiChatModel.builder() .apiKey(apiKey) - .modelName(OpenAiChatModelName.GPT_4_O) + .modelName(OpenAiChatModelName.GPT_4) .maxTokens(maxTokens) .build() From 068ba7b6e5290257326d1989fe9ac1a97feec408 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Tue, 18 Mar 2025 23:55:29 -0700 Subject: [PATCH 819/844] Bump to Gemini 2.0 Flash --- src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini2.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini2.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini2.kt index 385e96e..e85ea7b 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini2.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini2.kt @@ -98,7 +98,7 @@ class Gemini2 : AbstractModule() { try { val gemini = GoogleAiGeminiChatModel.builder() .apiKey(apiKey) - .modelName("gemini-1.5-flash") + .modelName("gemini-2.0-flash") .maxOutputTokens(maxTokens) .build() From 23797a2a04d7da96c6413c6ae30fe0b5f73e5bea Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Thu, 20 Mar 2025 10:38:09 -0700 Subject: [PATCH 820/844] Bump Kotlin to version 2.1.20 --- README.md | 2 +- pom.xml | 10 +++++----- src/bld/java/net/thauvin/erik/MobibotBuild.java | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 84d0ebc..d43ba67 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # mobibot [![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) -[![Kotlin](https://img.shields.io/badge/kotlin-2.1.10-7f52ff.svg)](https://kotlinlang.org) +[![Kotlin](https://img.shields.io/badge/kotlin-2.1.20-7f52ff.svg)](https://kotlinlang.org) [![bld](https://img.shields.io/badge/2.2.1-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ethauvin_mobibot&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=ethauvin_mobibot) [![GitHub CI](https://github.com/ethauvin/mobibot/actions/workflows/bld.yml/badge.svg)](https://github.com/ethauvin/mobibot/actions/workflows/bld.yml) diff --git a/pom.xml b/pom.xml index 3543235..c278f8f 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 net.thauvin.erik.mobibot mobibot - 0.8.0-rc+20250318045311 + 0.8.0-rc+20250320103735 mobibot @@ -54,25 +54,25 @@ org.jetbrains.kotlin kotlin-stdlib - 2.1.10 + 2.1.20 compile org.jetbrains.kotlin kotlin-stdlib-common - 2.1.10 + 2.1.20 compile org.jetbrains.kotlin kotlin-stdlib-jdk7 - 2.1.10 + 2.1.20 compile org.jetbrains.kotlin kotlin-stdlib-jdk8 - 2.1.10 + 2.1.20 compile diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index 9ffb588..1ac9eab 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -77,7 +77,7 @@ public class MobibotBuild extends Project { SONATYPE_SNAPSHOTS_LEGACY); var log4j = version(2, 24, 3); - var kotlin = version(2, 1, 10); + var kotlin = version(2, 1, 20); var langchain = version(0, 36, 2); scope(compile) // PircBotX From 8537c8a436b449df90eaf5a1895a1f5381231c9c Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Thu, 20 Mar 2025 10:40:29 -0700 Subject: [PATCH 821/844] Add Kotlin compile options for JDK 24 --- src/bld/java/net/thauvin/erik/MobibotBuild.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index 1ac9eab..8a8edd9 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -38,6 +38,7 @@ import rife.bld.extension.CompileKotlinOperation; import rife.bld.extension.DetektOperation; import rife.bld.extension.GeneratedVersionOperation; import rife.bld.extension.JacocoReportOperation; +import rife.bld.extension.kotlin.CompileOptions; import rife.bld.operations.exceptions.ExitStatusException; import rife.bld.publish.PomBuilder; import rife.tools.FileUtils; @@ -153,10 +154,12 @@ public class MobibotBuild extends Project { @Override public void compile() throws Exception { releaseInfo(); + final var options = new CompileOptions(); + options.verbose(true).jvmOptions().add("--enable-native-access=ALL-UNNAMED"); var op = new CompileKotlinOperation() .kotlinHome("/opt/kotlinc/") + .compileOptions(options) .fromProject(this); - op.compileOptions().verbose(true); op.execute(); } From 5f1eb63c4fdb798d9a25c5e706ed61f7af6d6659 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Thu, 20 Mar 2025 10:54:32 -0700 Subject: [PATCH 822/844] Combine Kotlin compile options --- src/bld/java/net/thauvin/erik/MobibotBuild.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index 8a8edd9..65e7e0c 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -154,8 +154,7 @@ public class MobibotBuild extends Project { @Override public void compile() throws Exception { releaseInfo(); - final var options = new CompileOptions(); - options.verbose(true).jvmOptions().add("--enable-native-access=ALL-UNNAMED"); + var options = new CompileOptions().verbose(true).jvmOptions("--enable-native-access=ALL-UNNAMED"); var op = new CompileKotlinOperation() .kotlinHome("/opt/kotlinc/") .compileOptions(options) From 4b7f41660fdd717aa2312c476f0ab90a70f9fcb0 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Fri, 21 Mar 2025 23:36:28 -0700 Subject: [PATCH 823/844] Bump Kotlin extension to version 1.1.0-SNAPSHOT --- lib/bld/bld-wrapper.properties | 2 +- src/bld/java/net/thauvin/erik/MobibotBuild.java | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/bld/bld-wrapper.properties b/lib/bld/bld-wrapper.properties index c1b1941..4986847 100644 --- a/lib/bld/bld-wrapper.properties +++ b/lib/bld/bld-wrapper.properties @@ -4,7 +4,7 @@ bld.downloadLocation= bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.9 bld.extension-gv=com.uwyn.rife2:bld-generated-version:1.0.0 bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.9 -bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.0.4 +bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.1.0-SNAPSHOT bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES bld.sourceDirectories= bld.version=2.2.1 diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index 65e7e0c..42436b7 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -39,6 +39,7 @@ import rife.bld.extension.DetektOperation; import rife.bld.extension.GeneratedVersionOperation; import rife.bld.extension.JacocoReportOperation; import rife.bld.extension.kotlin.CompileOptions; +import rife.bld.extension.kotlin.JvmOptions; import rife.bld.operations.exceptions.ExitStatusException; import rife.bld.publish.PomBuilder; import rife.tools.FileUtils; @@ -154,12 +155,12 @@ public class MobibotBuild extends Project { @Override public void compile() throws Exception { releaseInfo(); - var options = new CompileOptions().verbose(true).jvmOptions("--enable-native-access=ALL-UNNAMED"); - var op = new CompileKotlinOperation() - .kotlinHome("/opt/kotlinc/") + var options = new CompileOptions().verbose(true); + options.jvmOptions().enableNativeAccess(JvmOptions.ALL_UNNAMED); + new CompileKotlinOperation() .compileOptions(options) - .fromProject(this); - op.execute(); + .fromProject(this) + .execute(); } @Override From 45f602fbe2af7cbfccd1f2b2020539e2ee6f6d87 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Fri, 21 Mar 2025 23:37:17 -0700 Subject: [PATCH 824/844] Update snapshot dependencies Bump Pinboard Poster to version 1.2.1-SNAPSHOT Bump JokeApi to version 1.0.1-SNAPSHOT --- pom.xml | 6 +++--- src/bld/java/net/thauvin/erik/MobibotBuild.java | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index c278f8f..a3a9f14 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 net.thauvin.erik.mobibot mobibot - 0.8.0-rc+20250320103735 + 0.8.0-rc+20250321233454 mobibot @@ -180,13 +180,13 @@ net.thauvin.erik jokeapi - 1.0.0 + 1.0.1-SNAPSHOT compile net.thauvin.erik pinboard-poster - 1.2.0 + 1.2.1-SNAPSHOT compile diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index 42436b7..c2c5f38 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -118,8 +118,8 @@ public class MobibotBuild extends Project { .include(dependency("org.jsoup", "jsoup", "1.19.1")) // Thauvin .include(dependency("net.thauvin.erik", "cryptoprice", "1.0.3-SNAPSHOT")) - .include(dependency("net.thauvin.erik", "jokeapi", "1.0.0")) - .include(dependency("net.thauvin.erik", "pinboard-poster", "1.2.0")) + .include(dependency("net.thauvin.erik", "jokeapi", "1.0.1-SNAPSHOT")) + .include(dependency("net.thauvin.erik", "pinboard-poster", "1.2.1-SNAPSHOT")) .include(dependency("net.thauvin.erik.urlencoder", "urlencoder-lib-jvm", "1.6.0")); scope(test) .include(dependency("com.willowtreeapps.assertk", "assertk-jvm", version(0, 28, 1))) From 6f1aa72ad018034120c49c4d8f69808a72ac51dd Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sat, 22 Mar 2025 00:15:10 -0700 Subject: [PATCH 825/844] Add build/test job for Windows --- .github/workflows/bld.yml | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/.github/workflows/bld.yml b/.github/workflows/bld.yml index 3511dc4..2627b79 100644 --- a/.github/workflows/bld.yml +++ b/.github/workflows/bld.yml @@ -23,7 +23,7 @@ jobs: strategy: matrix: java-version: [17, 21, 24] - kotlin-version: [1.9.25, 2.0.20, 2.1.10] + kotlin-version: [1.9.25, 2.0.20, 2.1.20] steps: - name: Checkout source repository @@ -56,3 +56,27 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + + build-bld-windows: + runs-on: windows-latest + + steps: + - name: Checkout source repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up JDK + uses: actions/setup-java@v4 + with: + distribution: "zulu" + java-version: "17" + + - name: Download dependencies + run: bld.bat download + + - name: Compile source + run: bld.bat compile + + - name: Run tests + run: bld.bat jacoco From 1f5903c5e92a2cb3829a4737f5517ab83bba3353 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sat, 22 Mar 2025 00:19:17 -0700 Subject: [PATCH 826/844] Fix bld executable name under Windows --- .github/workflows/bld.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/bld.yml b/.github/workflows/bld.yml index 2627b79..1d57288 100644 --- a/.github/workflows/bld.yml +++ b/.github/workflows/bld.yml @@ -72,11 +72,13 @@ jobs: distribution: "zulu" java-version: "17" + - run: dir + - name: Download dependencies - run: bld.bat download + run: bld download - name: Compile source - run: bld.bat compile + run: bld compile - name: Run tests - run: bld.bat jacoco + run: bld jacoco From 93d761b13bd7289aebf62f1c4a671c7232229420 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sat, 22 Mar 2025 00:24:22 -0700 Subject: [PATCH 827/844] Change run to script in Windows job --- .github/workflows/bld.yml | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/.github/workflows/bld.yml b/.github/workflows/bld.yml index 1d57288..6d9f43f 100644 --- a/.github/workflows/bld.yml +++ b/.github/workflows/bld.yml @@ -1,6 +1,6 @@ name: bld-ci -on: [push, pull_request, workflow_dispatch] +on: [ push, pull_request, workflow_dispatch ] env: ALPHAVANTAGE_API_KEY: ${{ secrets.ALPHAVANTAGE_API_KEY }} @@ -22,8 +22,8 @@ jobs: strategy: matrix: - java-version: [17, 21, 24] - kotlin-version: [1.9.25, 2.0.20, 2.1.20] + java-version: [ 17, 21, 24 ] + kotlin-version: [ 1.9.25, 2.0.20, 2.1.20 ] steps: - name: Checkout source repository @@ -72,13 +72,11 @@ jobs: distribution: "zulu" java-version: "17" - - run: dir - - name: Download dependencies - run: bld download + script: bld.bat download - name: Compile source - run: bld compile + script: bld.bat compile - name: Run tests - run: bld jacoco + script: bld.bat jacoco From 599d819dc9a9d6d2f04730262ba40ff0e797d917 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sat, 22 Mar 2025 00:28:21 -0700 Subject: [PATCH 828/844] Add call to Windows run steps --- .github/workflows/bld.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/bld.yml b/.github/workflows/bld.yml index 6d9f43f..4f69f88 100644 --- a/.github/workflows/bld.yml +++ b/.github/workflows/bld.yml @@ -1,6 +1,6 @@ name: bld-ci -on: [ push, pull_request, workflow_dispatch ] +on: [push, pull_request, workflow_dispatch] env: ALPHAVANTAGE_API_KEY: ${{ secrets.ALPHAVANTAGE_API_KEY }} @@ -22,8 +22,8 @@ jobs: strategy: matrix: - java-version: [ 17, 21, 24 ] - kotlin-version: [ 1.9.25, 2.0.20, 2.1.20 ] + java-version: [17, 21, 24] + kotlin-version: [1.9.25, 2.0.20, 2.1.20] steps: - name: Checkout source repository @@ -73,10 +73,10 @@ jobs: java-version: "17" - name: Download dependencies - script: bld.bat download + run: call bld.bat download - name: Compile source - script: bld.bat compile + run: call bld.bat compile - name: Run tests - script: bld.bat jacoco + run: call bld.bat jacoco From 48b92c33fdd8d2f973f346e1c0da7c29c16915c2 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sat, 22 Mar 2025 00:35:11 -0700 Subject: [PATCH 829/844] Set the shell cmd under Windows --- .github/workflows/bld.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/bld.yml b/.github/workflows/bld.yml index 4f69f88..13359e8 100644 --- a/.github/workflows/bld.yml +++ b/.github/workflows/bld.yml @@ -73,10 +73,13 @@ jobs: java-version: "17" - name: Download dependencies - run: call bld.bat download + run: bld.bat download + shell: cmd - name: Compile source - run: call bld.bat compile + run: bld.bat compile + shell: cmd - name: Run tests - run: call bld.bat jacoco + run: bld.bat jacoco + shell: cmd From 7e58e5840f685ef66908640342fb5f2b5a75219d Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sat, 22 Mar 2025 00:45:24 -0700 Subject: [PATCH 830/844] Revert "Add build/test job for Windows" This reverts commit 6f1aa72a --- .github/workflows/bld.yml | 29 +-------------- .../net/thauvin/erik/mobibot/ReleaseInfo.kt | 35 ++----------------- .../erik/mobibot/commands/tell/Tell.kt | 2 +- 3 files changed, 4 insertions(+), 62 deletions(-) diff --git a/.github/workflows/bld.yml b/.github/workflows/bld.yml index 13359e8..3511dc4 100644 --- a/.github/workflows/bld.yml +++ b/.github/workflows/bld.yml @@ -23,7 +23,7 @@ jobs: strategy: matrix: java-version: [17, 21, 24] - kotlin-version: [1.9.25, 2.0.20, 2.1.20] + kotlin-version: [1.9.25, 2.0.20, 2.1.10] steps: - name: Checkout source repository @@ -56,30 +56,3 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - - build-bld-windows: - runs-on: windows-latest - - steps: - - name: Checkout source repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Set up JDK - uses: actions/setup-java@v4 - with: - distribution: "zulu" - java-version: "17" - - - name: Download dependencies - run: bld.bat download - shell: cmd - - - name: Compile source - run: bld.bat compile - shell: cmd - - - name: Run tests - run: bld.bat jacoco - shell: cmd diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt b/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt index 7571a9f..42a61aa 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt @@ -1,34 +1,3 @@ -/* - * ReleaseInfo.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - /* * This file is automatically generated * Do not modify! -- ALL CHANGES WILL BE ERASED! @@ -45,12 +14,12 @@ import java.time.ZoneId */ object ReleaseInfo { const val PROJECT = "mobibot" - const val VERSION = "0.8.0-rc+20250102175731" + const val VERSION = "0.8.0-rc+20250322004101" @JvmField @Suppress("MagicNumber") val BUILD_DATE: LocalDateTime = LocalDateTime.ofInstant( - Instant.ofEpochMilli(1735869451156L), ZoneId.systemDefault() + Instant.ofEpochMilli(1742629261438L), ZoneId.systemDefault() ) const val WEBSITE = "https://mobitopia.org/mobibot/" diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt index c204062..26fe803 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt @@ -287,7 +287,7 @@ class Tell(private val serialObject: String) : AbstractCommand() { // All keyword private const val TELL_ALL_KEYWORD = "all" - //T he delete command. + // The delete command. private const val TELL_DEL_KEYWORD = "del" } From 6173639cdd9cc2fb3b093aa2fdfa600dafd12899 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sat, 22 Mar 2025 00:47:11 -0700 Subject: [PATCH 831/844] Bump Kotlin matrix version to 2.1.20 --- .github/workflows/bld.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/bld.yml b/.github/workflows/bld.yml index 3511dc4..8e7d939 100644 --- a/.github/workflows/bld.yml +++ b/.github/workflows/bld.yml @@ -23,7 +23,7 @@ jobs: strategy: matrix: java-version: [17, 21, 24] - kotlin-version: [1.9.25, 2.0.20, 2.1.10] + kotlin-version: [1.9.25, 2.0.20, 2.1.20] steps: - name: Checkout source repository From 75ccf1a0ed649f50881e32438a8b154238ecba92 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 23 Mar 2025 20:02:55 -0700 Subject: [PATCH 832/844] Set progressive compiling --- .../java/net/thauvin/erik/MobibotBuild.java | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index c2c5f38..940ff0d 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -52,6 +52,9 @@ import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List; import java.util.jar.Attributes; +import java.util.logging.ConsoleHandler; +import java.util.logging.Level; +import java.util.logging.Logger; import static rife.bld.dependencies.Repository.*; import static rife.bld.dependencies.Scope.compile; @@ -139,6 +142,15 @@ public class MobibotBuild extends Project { } public static void main(String[] args) { + var level = Level.ALL; + var logger = Logger.getLogger("rife.bld.extension"); + var consoleHandler = new ConsoleHandler(); + + consoleHandler.setLevel(level); + logger.addHandler(consoleHandler); + logger.setLevel(level); + logger.setUseParentHandlers(false); + new MobibotBuild().start(args); } @@ -155,12 +167,11 @@ public class MobibotBuild extends Project { @Override public void compile() throws Exception { releaseInfo(); - var options = new CompileOptions().verbose(true); - options.jvmOptions().enableNativeAccess(JvmOptions.ALL_UNNAMED); - new CompileKotlinOperation() - .compileOptions(options) - .fromProject(this) - .execute(); + var options = new CompileOptions().progressive(true).verbose(true); + var op = new CompileKotlinOperation().compileOptions(options).fromProject(this); + + op.jvmOptions().enableNativeAccess(JvmOptions.ALL_UNNAMED); + op.execute(); } @Override From eed8277ed630a24361f65b5f70593b0229bddef5 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Wed, 26 Mar 2025 23:32:56 -0700 Subject: [PATCH 833/844] Add API response logging --- .../thauvin/erik/mobibot/modules/CryptoPrices.kt | 2 +- .../erik/mobibot/modules/CryptoPricesTest.kt | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt index 2186d73..3334a90 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt @@ -52,7 +52,7 @@ class CryptoPrices : AbstractModule() { /** * Returns the cryptocurrency market price from - * [Coinbase](https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-prices#get-spot-price). + * [Coinbase](https://docs.cdp.coinbase.com/coinbase-app/docs/api-prices#get-spot-price). */ override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { if (CURRENCIES.isEmpty()) { diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt index 34b8369..94a40d9 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt @@ -39,6 +39,9 @@ import net.thauvin.erik.crypto.CryptoPrice import net.thauvin.erik.mobibot.modules.CryptoPrices.Companion.currentPrice import net.thauvin.erik.mobibot.modules.CryptoPrices.Companion.getCurrencyName import net.thauvin.erik.mobibot.modules.CryptoPrices.Companion.loadCurrencies +import org.junit.jupiter.api.BeforeAll +import java.util.logging.ConsoleHandler +import java.util.logging.Level import kotlin.test.Test class CryptoPricesTest { @@ -69,4 +72,16 @@ class CryptoPricesTest { assertThat(getCurrencyName("USD"), "USD").isEqualTo("United States Dollar") assertThat(getCurrencyName("EUR"), "EUR").isEqualTo("Euro") } + + companion object { + @JvmStatic + @BeforeAll + fun beforeAll() { + with(CryptoPrice.logger) { + addHandler(ConsoleHandler().apply { level = Level.FINE }) + level = Level.FINE + useParentHandlers = false + } + } + } } From 310687cdce336af58c2be739196fefc775884d68 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Wed, 26 Mar 2025 23:33:32 -0700 Subject: [PATCH 834/844] Update to latest extensions snapshots --- lib/bld/bld-wrapper.properties | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/bld/bld-wrapper.properties b/lib/bld/bld-wrapper.properties index 4986847..976017e 100644 --- a/lib/bld/bld-wrapper.properties +++ b/lib/bld/bld-wrapper.properties @@ -1,9 +1,9 @@ bld.downloadExtensionJavadoc=false bld.downloadExtensionSources=true bld.downloadLocation= -bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.9 -bld.extension-gv=com.uwyn.rife2:bld-generated-version:1.0.0 -bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.9 +bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.10-SNAPSHOT +bld.extension-gv=com.uwyn.rife2:bld-generated-version:1.0.1-SNAPSHOT +bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.10-SNAPSHOT bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.1.0-SNAPSHOT bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES bld.sourceDirectories= From fedebc7ed41e59c7decb0ede800992060f140e66 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Wed, 26 Mar 2025 23:34:14 -0700 Subject: [PATCH 835/844] Cleanup compile command --- src/bld/java/net/thauvin/erik/MobibotBuild.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index 940ff0d..4f6868d 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -39,7 +39,6 @@ import rife.bld.extension.DetektOperation; import rife.bld.extension.GeneratedVersionOperation; import rife.bld.extension.JacocoReportOperation; import rife.bld.extension.kotlin.CompileOptions; -import rife.bld.extension.kotlin.JvmOptions; import rife.bld.operations.exceptions.ExitStatusException; import rife.bld.publish.PomBuilder; import rife.tools.FileUtils; @@ -167,11 +166,10 @@ public class MobibotBuild extends Project { @Override public void compile() throws Exception { releaseInfo(); - var options = new CompileOptions().progressive(true).verbose(true); - var op = new CompileKotlinOperation().compileOptions(options).fromProject(this); - - op.jvmOptions().enableNativeAccess(JvmOptions.ALL_UNNAMED); - op.execute(); + new CompileKotlinOperation() + .compileOptions(new CompileOptions().progressive(true).verbose(true)) + .fromProject(this) + .execute(); } @Override From abc33d05f734c95860cd4717969551019ff06ea2 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 13 Apr 2025 13:28:38 -0700 Subject: [PATCH 836/844] Bump JUnit to version 5.12.2 --- src/bld/java/net/thauvin/erik/MobibotBuild.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index 4f6868d..ec448d7 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -126,9 +126,9 @@ public class MobibotBuild extends Project { scope(test) .include(dependency("com.willowtreeapps.assertk", "assertk-jvm", version(0, 28, 1))) .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", kotlin)) - .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 12, 1))) - .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 12, 1))) - .include(dependency("org.junit.platform", "junit-platform-launcher", version(1, 12, 1))); + .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 12, 2))) + .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 12, 2))) + .include(dependency("org.junit.platform", "junit-platform-launcher", version(1, 12, 2))); List jars = new ArrayList<>(); runtimeClasspathJars().forEach(f -> jars.add("./lib/" + f.getName())); From 82b40a49b273e469393e40d5f83852a8ce48a541 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 13 Apr 2025 13:29:32 -0700 Subject: [PATCH 837/844] Update extensions Bump JaCoCo Reports to version 0.9.10 Bump Generated Version to version 1.0.1 --- lib/bld/bld-wrapper.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/bld/bld-wrapper.properties b/lib/bld/bld-wrapper.properties index 976017e..8b96558 100644 --- a/lib/bld/bld-wrapper.properties +++ b/lib/bld/bld-wrapper.properties @@ -2,8 +2,8 @@ bld.downloadExtensionJavadoc=false bld.downloadExtensionSources=true bld.downloadLocation= bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.10-SNAPSHOT -bld.extension-gv=com.uwyn.rife2:bld-generated-version:1.0.1-SNAPSHOT -bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.10-SNAPSHOT +bld.extension-gv=com.uwyn.rife2:bld-generated-version:1.0.1 +bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.10 bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.1.0-SNAPSHOT bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES bld.sourceDirectories= From 491f451acb90d7d74f926d5c5c6cc9e83811f867 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 13 Apr 2025 13:30:07 -0700 Subject: [PATCH 838/844] Bump Commons Text to version 1.13.1 --- src/bld/java/net/thauvin/erik/MobibotBuild.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index ec448d7..63957d4 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -88,7 +88,7 @@ public class MobibotBuild extends Project { .include(dependency("com.github.pircbotx", "pircbotx", "2.3.1")) // Commons (mostly for PircBotX) .include(dependency("org.apache.commons", "commons-lang3", "3.17.0")) - .include(dependency("org.apache.commons", "commons-text", "1.13.0")) + .include(dependency("org.apache.commons", "commons-text", "1.13.1")) .include(dependency("commons-codec", "commons-codec", "1.18.0")) .include(dependency("commons-net", "commons-net", "3.11.1")) // Google From ef9bbe6e1fd27984f40f0a6639bf64c8f982cec1 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 13 Apr 2025 13:30:30 -0700 Subject: [PATCH 839/844] Bump Gson to version 2.13.0 --- src/bld/java/net/thauvin/erik/MobibotBuild.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index 63957d4..b152cd3 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -92,7 +92,7 @@ public class MobibotBuild extends Project { .include(dependency("commons-codec", "commons-codec", "1.18.0")) .include(dependency("commons-net", "commons-net", "3.11.1")) // Google - .include(dependency("com.google.code.gson", "gson", "2.12.1")) + .include(dependency("com.google.code.gson", "gson", "2.13.0")) .include(dependency("com.google.guava", "guava", "33.2.1-jre")) // Kotlin .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlin)) From 9e49da5d56187b788363bb07a3be715af9413684 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 13 Apr 2025 13:30:58 -0700 Subject: [PATCH 840/844] Bump Kotlinx Coroutines to version 1.10.2 --- src/bld/java/net/thauvin/erik/MobibotBuild.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index b152cd3..6ed1d06 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -99,7 +99,7 @@ public class MobibotBuild extends Project { .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-common", kotlin)) .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-jdk7", kotlin)) .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-jdk8", kotlin)) - .include(dependency("org.jetbrains.kotlinx", "kotlinx-coroutines-core", "1.10.1")) + .include(dependency("org.jetbrains.kotlinx", "kotlinx-coroutines-core", "1.10.2")) .include(dependency("org.jetbrains.kotlinx", "kotlinx-cli-jvm", "0.3.6")) // Logging .include(dependency("org.slf4j", "slf4j-api", "2.0.17")) From 749334493bca7090c1fcb549a064802995c30e4a Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Fri, 18 Apr 2025 15:55:57 -0700 Subject: [PATCH 841/844] Add JitPack token --- .circleci/config.yml | 2 +- .github/workflows/bld.yml | 2 +- .gitlab-ci.yml | 2 +- bitbucket-pipelines.yml | 2 +- src/bld/java/net/thauvin/erik/MobibotBuild.java | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index c781fdc..9586fcd 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -24,7 +24,7 @@ commands: version: 2.1.10 - run: name: Download dependencies - command: ./bld download + command: ./bld -Djitpack.token=$JITPACK_TOKEN download - run: name: Compile source command: ./bld compile diff --git a/.github/workflows/bld.yml b/.github/workflows/bld.yml index 8e7d939..5b88e5a 100644 --- a/.github/workflows/bld.yml +++ b/.github/workflows/bld.yml @@ -41,7 +41,7 @@ jobs: run: ./bld download - name: Compile source - run: ./bld compile + run: ./bld -Djitpack.token=${{ secrets.JITPACK_TOKEN }} compile - name: Run tests run: ./bld jacoco diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 10b9b0f..a2a4384 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -19,6 +19,6 @@ before_script: test: stage: test script: - - ./bld download + - ./bld -Djitpack.token=$JITPACK_TOKEN download - ./bld compile - ./bld test diff --git a/bitbucket-pipelines.yml b/bitbucket-pipelines.yml index ace99d2..132ed8d 100644 --- a/bitbucket-pipelines.yml +++ b/bitbucket-pipelines.yml @@ -15,6 +15,6 @@ pipelines: - sdk install kotlin - source "$HOME/.sdkman/bin/sdkman-init.sh" # Download, compile and test with bld - - ./bld download + - ./bld -Djitpack.token=$JITPACK_TOKEN download - ./bld compile - ./bld test diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index 6ed1d06..e4da3b1 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -67,7 +67,7 @@ public class MobibotBuild extends Project { pkg = "net.thauvin.erik.mobibot"; name = "mobibot"; version = version(0, 8, 0, "rc+" + - DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now())); + DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now())); mainClass = pkg + ".Mobibot"; @@ -77,7 +77,7 @@ public class MobibotBuild extends Project { repositories = List.of( MAVEN_LOCAL, MAVEN_CENTRAL, - new Repository("https://jitpack.io"), + new Repository("https://jitpack.io").withCredentials(property("jitpack.token"), "."), SONATYPE_SNAPSHOTS_LEGACY); var log4j = version(2, 24, 3); From 31e882eb42741adeea637a34b48d573d31ee860d Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Fri, 18 Apr 2025 17:02:45 -0700 Subject: [PATCH 842/844] Remove test on coverage --- .../net/thauvin/erik/mobibot/modules/ChatGpt2Test.kt | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt2Test.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt2Test.kt index c4699a5..ee3e534 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt2Test.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt2Test.kt @@ -47,15 +47,6 @@ class ChatGpt2Test : LocalProperties() { .hasNoCause() } - @Test - fun testChatOnCoverage() { - if (System.getenv("CI") == null || System.getenv("COVERAGE_JDK") != null) { - assertThat( - ChatGpt2.chat("how do I encode a URL in java?", getProperty(ChatGpt2.API_KEY_PROP), 60) - ).contains("URLEncoder") - } - } - @Test @DisableOnCi fun testChat() { From 86522d6b3ef8b5a2a46aca4220c232292c702b7c Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Fri, 18 Apr 2025 17:24:30 -0700 Subject: [PATCH 843/844] Revert "Add JitPack token" This reverts commit 749334493bca7090c1fcb549a064802995c30e4a. --- .circleci/config.yml | 2 +- .github/workflows/bld.yml | 2 +- .gitlab-ci.yml | 2 +- bitbucket-pipelines.yml | 2 +- src/bld/java/net/thauvin/erik/MobibotBuild.java | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 9586fcd..c781fdc 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -24,7 +24,7 @@ commands: version: 2.1.10 - run: name: Download dependencies - command: ./bld -Djitpack.token=$JITPACK_TOKEN download + command: ./bld download - run: name: Compile source command: ./bld compile diff --git a/.github/workflows/bld.yml b/.github/workflows/bld.yml index 5b88e5a..8e7d939 100644 --- a/.github/workflows/bld.yml +++ b/.github/workflows/bld.yml @@ -41,7 +41,7 @@ jobs: run: ./bld download - name: Compile source - run: ./bld -Djitpack.token=${{ secrets.JITPACK_TOKEN }} compile + run: ./bld compile - name: Run tests run: ./bld jacoco diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a2a4384..10b9b0f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -19,6 +19,6 @@ before_script: test: stage: test script: - - ./bld -Djitpack.token=$JITPACK_TOKEN download + - ./bld download - ./bld compile - ./bld test diff --git a/bitbucket-pipelines.yml b/bitbucket-pipelines.yml index 132ed8d..ace99d2 100644 --- a/bitbucket-pipelines.yml +++ b/bitbucket-pipelines.yml @@ -15,6 +15,6 @@ pipelines: - sdk install kotlin - source "$HOME/.sdkman/bin/sdkman-init.sh" # Download, compile and test with bld - - ./bld -Djitpack.token=$JITPACK_TOKEN download + - ./bld download - ./bld compile - ./bld test diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index e4da3b1..6ed1d06 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -67,7 +67,7 @@ public class MobibotBuild extends Project { pkg = "net.thauvin.erik.mobibot"; name = "mobibot"; version = version(0, 8, 0, "rc+" + - DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now())); + DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now())); mainClass = pkg + ".Mobibot"; @@ -77,7 +77,7 @@ public class MobibotBuild extends Project { repositories = List.of( MAVEN_LOCAL, MAVEN_CENTRAL, - new Repository("https://jitpack.io").withCredentials(property("jitpack.token"), "."), + new Repository("https://jitpack.io"), SONATYPE_SNAPSHOTS_LEGACY); var log4j = version(2, 24, 3); From b4754f13115e16a10073bdef12eeacd0152174af Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Thu, 24 Apr 2025 11:32:11 -0700 Subject: [PATCH 844/844] Bump Gson to version 2.13.1 --- pom.xml | 8 ++++---- src/bld/java/net/thauvin/erik/MobibotBuild.java | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index a3a9f14..58768ef 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 net.thauvin.erik.mobibot mobibot - 0.8.0-rc+20250321233454 + 0.8.0-rc+20250424113056 mobibot @@ -24,7 +24,7 @@ org.apache.commons commons-text - 1.13.0 + 1.13.1 compile @@ -42,7 +42,7 @@ com.google.code.gson gson - 2.12.1 + 2.13.1 compile @@ -78,7 +78,7 @@ org.jetbrains.kotlinx kotlinx-coroutines-core - 1.10.1 + 1.10.2 compile diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index 6ed1d06..08367ef 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -92,7 +92,7 @@ public class MobibotBuild extends Project { .include(dependency("commons-codec", "commons-codec", "1.18.0")) .include(dependency("commons-net", "commons-net", "3.11.1")) // Google - .include(dependency("com.google.code.gson", "gson", "2.13.0")) + .include(dependency("com.google.code.gson", "gson", "2.13.1")) .include(dependency("com.google.guava", "guava", "33.2.1-jre")) // Kotlin .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlin))

    Q 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 diff --git a/lib/delicious-1.14.jar b/lib/delicious-1.14.jar deleted file mode 100644 index bf441fa52faa2f93f05d8c4ca5334e10189f29ac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23859 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 diff --git a/lib/jakarta-oro-2.0.8.jar b/lib/jakarta-oro-2.0.8.jar deleted file mode 100644 index 23488d2600f5f4784c0ba2be5baa4c41f396f616..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65261 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 EKLN5E{r~^~ diff --git a/lib/jdom-1.1.jar b/lib/jdom-1.1.jar deleted file mode 100644 index 97c85f564e3faca58e3e88e5e33ea3f425bf1921..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 153115 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 tc` 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 te}nOVCD`j|-apix?}<1@fDFJGl diff --git a/lib/commons-logging-1.1.1.jar b/lib/commons-logging-1.1.1.jar deleted file mode 100644 index 8758a96b70cfba9466bacca19c0d99b87cf53734..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 60841 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