diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..f904d2e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+/nbproject/private/
+/build/
+/dist/
\ No newline at end of file
diff --git a/MyList.db b/MyList.db
new file mode 100644
index 0000000..6c7625a
Binary files /dev/null and b/MyList.db differ
diff --git a/MyRepository/README_DO_NOT_TOUCH_FILES.txt b/MyRepository/README_DO_NOT_TOUCH_FILES.txt
new file mode 100644
index 0000000..a4bc145
--- /dev/null
+++ b/MyRepository/README_DO_NOT_TOUCH_FILES.txt
@@ -0,0 +1,9 @@
+
+# *************************************************************************
+# *** DO NOT TOUCH FILES IN THIS DIRECTORY! ***
+# *** FILES IN THIS DIRECTORY AND SUBDIRECTORIES CONSTITUTE A DERBY ***
+# *** DATABASE, WHICH INCLUDES THE DATA (USER AND SYSTEM) AND THE ***
+# *** FILES NECESSARY FOR DATABASE RECOVERY. ***
+# *** EDITING, ADDING, OR DELETING ANY OF THESE FILES MAY CAUSE DATA ***
+# *** CORRUPTION AND LEAVE THE DATABASE IN A NON-RECOVERABLE STATE. ***
+# *************************************************************************
\ No newline at end of file
diff --git a/MyRepository/db.lck b/MyRepository/db.lck
new file mode 100644
index 0000000..056a832
Binary files /dev/null and b/MyRepository/db.lck differ
diff --git a/MyRepository/log/README_DO_NOT_TOUCH_FILES.txt b/MyRepository/log/README_DO_NOT_TOUCH_FILES.txt
new file mode 100644
index 0000000..56df292
--- /dev/null
+++ b/MyRepository/log/README_DO_NOT_TOUCH_FILES.txt
@@ -0,0 +1,8 @@
+
+# *************************************************************************
+# *** DO NOT TOUCH FILES IN THIS DIRECTORY! ***
+# *** FILES IN THIS DIRECTORY ARE USED BY THE DERBY DATABASE RECOVERY ***
+# *** SYSTEM. EDITING, ADDING, OR DELETING FILES IN THIS DIRECTORY ***
+# *** WILL CAUSE THE DERBY RECOVERY SYSTEM TO FAIL, LEADING TO ***
+# *** NON-RECOVERABLE CORRUPT DATABASES. ***
+# *************************************************************************
\ No newline at end of file
diff --git a/MyRepository/log/log.ctrl b/MyRepository/log/log.ctrl
new file mode 100644
index 0000000..b317752
Binary files /dev/null and b/MyRepository/log/log.ctrl differ
diff --git a/MyRepository/log/log1.dat b/MyRepository/log/log1.dat
new file mode 100644
index 0000000..14e524b
Binary files /dev/null and b/MyRepository/log/log1.dat differ
diff --git a/MyRepository/log/logmirror.ctrl b/MyRepository/log/logmirror.ctrl
new file mode 100644
index 0000000..b317752
Binary files /dev/null and b/MyRepository/log/logmirror.ctrl differ
diff --git a/MyRepository/seg0/README_DO_NOT_TOUCH_FILES.txt b/MyRepository/seg0/README_DO_NOT_TOUCH_FILES.txt
new file mode 100644
index 0000000..2bdad06
--- /dev/null
+++ b/MyRepository/seg0/README_DO_NOT_TOUCH_FILES.txt
@@ -0,0 +1,8 @@
+
+# *************************************************************************
+# *** DO NOT TOUCH FILES IN THIS DIRECTORY! ***
+# *** FILES IN THIS DIRECTORY ARE USED BY THE DERBY DATABASE TO STORE ***
+# *** USER AND SYSTEM DATA. EDITING, ADDING, OR DELETING FILES IN THIS ***
+# *** DIRECTORY WILL CORRUPT THE ASSOCIATED DERBY DATABASE AND MAKE ***
+# *** IT NON-RECOVERABLE. ***
+# *************************************************************************
\ No newline at end of file
diff --git a/MyRepository/seg0/c10.dat b/MyRepository/seg0/c10.dat
new file mode 100644
index 0000000..7847544
Binary files /dev/null and b/MyRepository/seg0/c10.dat differ
diff --git a/MyRepository/seg0/c101.dat b/MyRepository/seg0/c101.dat
new file mode 100644
index 0000000..461b98d
Binary files /dev/null and b/MyRepository/seg0/c101.dat differ
diff --git a/MyRepository/seg0/c111.dat b/MyRepository/seg0/c111.dat
new file mode 100644
index 0000000..6cf4a46
Binary files /dev/null and b/MyRepository/seg0/c111.dat differ
diff --git a/MyRepository/seg0/c121.dat b/MyRepository/seg0/c121.dat
new file mode 100644
index 0000000..a79dd7c
Binary files /dev/null and b/MyRepository/seg0/c121.dat differ
diff --git a/MyRepository/seg0/c130.dat b/MyRepository/seg0/c130.dat
new file mode 100644
index 0000000..54c8b91
Binary files /dev/null and b/MyRepository/seg0/c130.dat differ
diff --git a/MyRepository/seg0/c141.dat b/MyRepository/seg0/c141.dat
new file mode 100644
index 0000000..67a2da4
Binary files /dev/null and b/MyRepository/seg0/c141.dat differ
diff --git a/MyRepository/seg0/c150.dat b/MyRepository/seg0/c150.dat
new file mode 100644
index 0000000..eac1fd1
Binary files /dev/null and b/MyRepository/seg0/c150.dat differ
diff --git a/MyRepository/seg0/c161.dat b/MyRepository/seg0/c161.dat
new file mode 100644
index 0000000..7dd5151
Binary files /dev/null and b/MyRepository/seg0/c161.dat differ
diff --git a/MyRepository/seg0/c171.dat b/MyRepository/seg0/c171.dat
new file mode 100644
index 0000000..0ccb5b6
Binary files /dev/null and b/MyRepository/seg0/c171.dat differ
diff --git a/MyRepository/seg0/c180.dat b/MyRepository/seg0/c180.dat
new file mode 100644
index 0000000..46d5c16
Binary files /dev/null and b/MyRepository/seg0/c180.dat differ
diff --git a/MyRepository/seg0/c191.dat b/MyRepository/seg0/c191.dat
new file mode 100644
index 0000000..5e31e3b
Binary files /dev/null and b/MyRepository/seg0/c191.dat differ
diff --git a/MyRepository/seg0/c1a1.dat b/MyRepository/seg0/c1a1.dat
new file mode 100644
index 0000000..72ec38e
Binary files /dev/null and b/MyRepository/seg0/c1a1.dat differ
diff --git a/MyRepository/seg0/c1b1.dat b/MyRepository/seg0/c1b1.dat
new file mode 100644
index 0000000..edde827
Binary files /dev/null and b/MyRepository/seg0/c1b1.dat differ
diff --git a/MyRepository/seg0/c1c0.dat b/MyRepository/seg0/c1c0.dat
new file mode 100644
index 0000000..c5b91e2
Binary files /dev/null and b/MyRepository/seg0/c1c0.dat differ
diff --git a/MyRepository/seg0/c1d1.dat b/MyRepository/seg0/c1d1.dat
new file mode 100644
index 0000000..451f02f
Binary files /dev/null and b/MyRepository/seg0/c1d1.dat differ
diff --git a/MyRepository/seg0/c1e0.dat b/MyRepository/seg0/c1e0.dat
new file mode 100644
index 0000000..761408d
Binary files /dev/null and b/MyRepository/seg0/c1e0.dat differ
diff --git a/MyRepository/seg0/c1f1.dat b/MyRepository/seg0/c1f1.dat
new file mode 100644
index 0000000..78d701f
Binary files /dev/null and b/MyRepository/seg0/c1f1.dat differ
diff --git a/MyRepository/seg0/c20.dat b/MyRepository/seg0/c20.dat
new file mode 100644
index 0000000..156342b
Binary files /dev/null and b/MyRepository/seg0/c20.dat differ
diff --git a/MyRepository/seg0/c200.dat b/MyRepository/seg0/c200.dat
new file mode 100644
index 0000000..c3a7808
Binary files /dev/null and b/MyRepository/seg0/c200.dat differ
diff --git a/MyRepository/seg0/c211.dat b/MyRepository/seg0/c211.dat
new file mode 100644
index 0000000..54e1586
Binary files /dev/null and b/MyRepository/seg0/c211.dat differ
diff --git a/MyRepository/seg0/c221.dat b/MyRepository/seg0/c221.dat
new file mode 100644
index 0000000..59900bc
Binary files /dev/null and b/MyRepository/seg0/c221.dat differ
diff --git a/MyRepository/seg0/c230.dat b/MyRepository/seg0/c230.dat
new file mode 100644
index 0000000..b095ef1
Binary files /dev/null and b/MyRepository/seg0/c230.dat differ
diff --git a/MyRepository/seg0/c241.dat b/MyRepository/seg0/c241.dat
new file mode 100644
index 0000000..127fd1f
Binary files /dev/null and b/MyRepository/seg0/c241.dat differ
diff --git a/MyRepository/seg0/c251.dat b/MyRepository/seg0/c251.dat
new file mode 100644
index 0000000..c6fab1e
Binary files /dev/null and b/MyRepository/seg0/c251.dat differ
diff --git a/MyRepository/seg0/c260.dat b/MyRepository/seg0/c260.dat
new file mode 100644
index 0000000..25f81fd
Binary files /dev/null and b/MyRepository/seg0/c260.dat differ
diff --git a/MyRepository/seg0/c271.dat b/MyRepository/seg0/c271.dat
new file mode 100644
index 0000000..51cde57
Binary files /dev/null and b/MyRepository/seg0/c271.dat differ
diff --git a/MyRepository/seg0/c281.dat b/MyRepository/seg0/c281.dat
new file mode 100644
index 0000000..cfed875
Binary files /dev/null and b/MyRepository/seg0/c281.dat differ
diff --git a/MyRepository/seg0/c290.dat b/MyRepository/seg0/c290.dat
new file mode 100644
index 0000000..a85589e
Binary files /dev/null and b/MyRepository/seg0/c290.dat differ
diff --git a/MyRepository/seg0/c2a1.dat b/MyRepository/seg0/c2a1.dat
new file mode 100644
index 0000000..8e2ed6a
Binary files /dev/null and b/MyRepository/seg0/c2a1.dat differ
diff --git a/MyRepository/seg0/c2b1.dat b/MyRepository/seg0/c2b1.dat
new file mode 100644
index 0000000..2a29692
Binary files /dev/null and b/MyRepository/seg0/c2b1.dat differ
diff --git a/MyRepository/seg0/c2c1.dat b/MyRepository/seg0/c2c1.dat
new file mode 100644
index 0000000..5511575
Binary files /dev/null and b/MyRepository/seg0/c2c1.dat differ
diff --git a/MyRepository/seg0/c2d0.dat b/MyRepository/seg0/c2d0.dat
new file mode 100644
index 0000000..4adc6e4
Binary files /dev/null and b/MyRepository/seg0/c2d0.dat differ
diff --git a/MyRepository/seg0/c2e1.dat b/MyRepository/seg0/c2e1.dat
new file mode 100644
index 0000000..b37b9b2
Binary files /dev/null and b/MyRepository/seg0/c2e1.dat differ
diff --git a/MyRepository/seg0/c2f0.dat b/MyRepository/seg0/c2f0.dat
new file mode 100644
index 0000000..d854b4b
Binary files /dev/null and b/MyRepository/seg0/c2f0.dat differ
diff --git a/MyRepository/seg0/c300.dat b/MyRepository/seg0/c300.dat
new file mode 100644
index 0000000..2053e01
Binary files /dev/null and b/MyRepository/seg0/c300.dat differ
diff --git a/MyRepository/seg0/c31.dat b/MyRepository/seg0/c31.dat
new file mode 100644
index 0000000..96f48d7
Binary files /dev/null and b/MyRepository/seg0/c31.dat differ
diff --git a/MyRepository/seg0/c311.dat b/MyRepository/seg0/c311.dat
new file mode 100644
index 0000000..f60c260
Binary files /dev/null and b/MyRepository/seg0/c311.dat differ
diff --git a/MyRepository/seg0/c321.dat b/MyRepository/seg0/c321.dat
new file mode 100644
index 0000000..a9d7453
Binary files /dev/null and b/MyRepository/seg0/c321.dat differ
diff --git a/MyRepository/seg0/c331.dat b/MyRepository/seg0/c331.dat
new file mode 100644
index 0000000..85ee72b
Binary files /dev/null and b/MyRepository/seg0/c331.dat differ
diff --git a/MyRepository/seg0/c340.dat b/MyRepository/seg0/c340.dat
new file mode 100644
index 0000000..d99b11a
Binary files /dev/null and b/MyRepository/seg0/c340.dat differ
diff --git a/MyRepository/seg0/c351.dat b/MyRepository/seg0/c351.dat
new file mode 100644
index 0000000..f822f4c
Binary files /dev/null and b/MyRepository/seg0/c351.dat differ
diff --git a/MyRepository/seg0/c361.dat b/MyRepository/seg0/c361.dat
new file mode 100644
index 0000000..b5c8f25
Binary files /dev/null and b/MyRepository/seg0/c361.dat differ
diff --git a/MyRepository/seg0/c371.dat b/MyRepository/seg0/c371.dat
new file mode 100644
index 0000000..ad11f01
Binary files /dev/null and b/MyRepository/seg0/c371.dat differ
diff --git a/MyRepository/seg0/c380.dat b/MyRepository/seg0/c380.dat
new file mode 100644
index 0000000..901b4f3
Binary files /dev/null and b/MyRepository/seg0/c380.dat differ
diff --git a/MyRepository/seg0/c391.dat b/MyRepository/seg0/c391.dat
new file mode 100644
index 0000000..5bf8795
Binary files /dev/null and b/MyRepository/seg0/c391.dat differ
diff --git a/MyRepository/seg0/c3a1.dat b/MyRepository/seg0/c3a1.dat
new file mode 100644
index 0000000..0aac1e5
Binary files /dev/null and b/MyRepository/seg0/c3a1.dat differ
diff --git a/MyRepository/seg0/c3b1.dat b/MyRepository/seg0/c3b1.dat
new file mode 100644
index 0000000..c6a9ff7
Binary files /dev/null and b/MyRepository/seg0/c3b1.dat differ
diff --git a/MyRepository/seg0/c3c0.dat b/MyRepository/seg0/c3c0.dat
new file mode 100644
index 0000000..4d061cf
Binary files /dev/null and b/MyRepository/seg0/c3c0.dat differ
diff --git a/MyRepository/seg0/c3d1.dat b/MyRepository/seg0/c3d1.dat
new file mode 100644
index 0000000..45c9fa2
Binary files /dev/null and b/MyRepository/seg0/c3d1.dat differ
diff --git a/MyRepository/seg0/c3e1.dat b/MyRepository/seg0/c3e1.dat
new file mode 100644
index 0000000..48f53e6
Binary files /dev/null and b/MyRepository/seg0/c3e1.dat differ
diff --git a/MyRepository/seg0/c3f1.dat b/MyRepository/seg0/c3f1.dat
new file mode 100644
index 0000000..08acdce
Binary files /dev/null and b/MyRepository/seg0/c3f1.dat differ
diff --git a/MyRepository/seg0/c400.dat b/MyRepository/seg0/c400.dat
new file mode 100644
index 0000000..5493f04
Binary files /dev/null and b/MyRepository/seg0/c400.dat differ
diff --git a/MyRepository/seg0/c41.dat b/MyRepository/seg0/c41.dat
new file mode 100644
index 0000000..4c0cb33
Binary files /dev/null and b/MyRepository/seg0/c41.dat differ
diff --git a/MyRepository/seg0/c411.dat b/MyRepository/seg0/c411.dat
new file mode 100644
index 0000000..d3ab156
Binary files /dev/null and b/MyRepository/seg0/c411.dat differ
diff --git a/MyRepository/seg0/c421.dat b/MyRepository/seg0/c421.dat
new file mode 100644
index 0000000..13a942b
Binary files /dev/null and b/MyRepository/seg0/c421.dat differ
diff --git a/MyRepository/seg0/c430.dat b/MyRepository/seg0/c430.dat
new file mode 100644
index 0000000..55c948d
Binary files /dev/null and b/MyRepository/seg0/c430.dat differ
diff --git a/MyRepository/seg0/c441.dat b/MyRepository/seg0/c441.dat
new file mode 100644
index 0000000..3948b2a
Binary files /dev/null and b/MyRepository/seg0/c441.dat differ
diff --git a/MyRepository/seg0/c451.dat b/MyRepository/seg0/c451.dat
new file mode 100644
index 0000000..fe1ab73
Binary files /dev/null and b/MyRepository/seg0/c451.dat differ
diff --git a/MyRepository/seg0/c461.dat b/MyRepository/seg0/c461.dat
new file mode 100644
index 0000000..e6d9854
Binary files /dev/null and b/MyRepository/seg0/c461.dat differ
diff --git a/MyRepository/seg0/c470.dat b/MyRepository/seg0/c470.dat
new file mode 100644
index 0000000..c9f2eb1
Binary files /dev/null and b/MyRepository/seg0/c470.dat differ
diff --git a/MyRepository/seg0/c481.dat b/MyRepository/seg0/c481.dat
new file mode 100644
index 0000000..397b291
Binary files /dev/null and b/MyRepository/seg0/c481.dat differ
diff --git a/MyRepository/seg0/c490.dat b/MyRepository/seg0/c490.dat
new file mode 100644
index 0000000..67773fa
Binary files /dev/null and b/MyRepository/seg0/c490.dat differ
diff --git a/MyRepository/seg0/c4a1.dat b/MyRepository/seg0/c4a1.dat
new file mode 100644
index 0000000..c3daa90
Binary files /dev/null and b/MyRepository/seg0/c4a1.dat differ
diff --git a/MyRepository/seg0/c51.dat b/MyRepository/seg0/c51.dat
new file mode 100644
index 0000000..0acf809
Binary files /dev/null and b/MyRepository/seg0/c51.dat differ
diff --git a/MyRepository/seg0/c60.dat b/MyRepository/seg0/c60.dat
new file mode 100644
index 0000000..2072d1a
Binary files /dev/null and b/MyRepository/seg0/c60.dat differ
diff --git a/MyRepository/seg0/c71.dat b/MyRepository/seg0/c71.dat
new file mode 100644
index 0000000..725e077
Binary files /dev/null and b/MyRepository/seg0/c71.dat differ
diff --git a/MyRepository/seg0/c81.dat b/MyRepository/seg0/c81.dat
new file mode 100644
index 0000000..c8a94c2
Binary files /dev/null and b/MyRepository/seg0/c81.dat differ
diff --git a/MyRepository/seg0/c90.dat b/MyRepository/seg0/c90.dat
new file mode 100644
index 0000000..f327496
Binary files /dev/null and b/MyRepository/seg0/c90.dat differ
diff --git a/MyRepository/seg0/ca1.dat b/MyRepository/seg0/ca1.dat
new file mode 100644
index 0000000..6824e8e
Binary files /dev/null and b/MyRepository/seg0/ca1.dat differ
diff --git a/MyRepository/seg0/cb1.dat b/MyRepository/seg0/cb1.dat
new file mode 100644
index 0000000..8b3a83f
Binary files /dev/null and b/MyRepository/seg0/cb1.dat differ
diff --git a/MyRepository/seg0/cc0.dat b/MyRepository/seg0/cc0.dat
new file mode 100644
index 0000000..9a682fc
Binary files /dev/null and b/MyRepository/seg0/cc0.dat differ
diff --git a/MyRepository/seg0/cd1.dat b/MyRepository/seg0/cd1.dat
new file mode 100644
index 0000000..5635a86
Binary files /dev/null and b/MyRepository/seg0/cd1.dat differ
diff --git a/MyRepository/seg0/ce1.dat b/MyRepository/seg0/ce1.dat
new file mode 100644
index 0000000..f5c2d95
Binary files /dev/null and b/MyRepository/seg0/ce1.dat differ
diff --git a/MyRepository/seg0/cf0.dat b/MyRepository/seg0/cf0.dat
new file mode 100644
index 0000000..915f218
Binary files /dev/null and b/MyRepository/seg0/cf0.dat differ
diff --git a/MyRepository/service.properties b/MyRepository/service.properties
new file mode 100644
index 0000000..7f9a025
--- /dev/null
+++ b/MyRepository/service.properties
@@ -0,0 +1,23 @@
+#E:\Git\RPBot\MyRepository
+# ********************************************************************
+# *** Please do NOT edit this file. ***
+# *** CHANGING THE CONTENT OF THIS FILE MAY CAUSE DATA CORRUPTION. ***
+# ********************************************************************
+#Tue Apr 18 21:13:45 CEST 2017
+SysschemasIndex2Identifier=225
+SyscolumnsIdentifier=144
+SysconglomeratesIndex1Identifier=49
+SysconglomeratesIdentifier=32
+SyscolumnsIndex2Identifier=177
+SysschemasIndex1Identifier=209
+SysconglomeratesIndex3Identifier=81
+SystablesIndex2Identifier=129
+SyscolumnsIndex1Identifier=161
+derby.serviceProtocol=org.apache.derby.database.Database
+SysschemasIdentifier=192
+derby.storage.propertiesId=16
+SysconglomeratesIndex2Identifier=65
+derby.serviceLocale=en_US
+SystablesIdentifier=96
+SystablesIndex1Identifier=113
+#--- last line, don't put anything after this line ---
diff --git a/build.xml b/build.xml
new file mode 100644
index 0000000..7e12926
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+ Builds, tests, and runs the project RPBot.
+
+
+
diff --git a/derby.log b/derby.log
new file mode 100644
index 0000000..9022dc1
--- /dev/null
+++ b/derby.log
@@ -0,0 +1,13 @@
+----------------------------------------------------------------
+Tue Aug 22 22:40:27 CEST 2017:
+Booting Derby version The Apache Software Foundation - Apache Derby - 10.13.1.1 - (1765088): instance a816c00e-015e-0bac-cc28-0000059e8238
+on database directory E:\Git\RPBot\MyRepository with class loader sun.misc.Launcher$AppClassLoader@6bc7c054
+Loaded from file:/E:/Git/RPBot/lib/db-derby-10.13.1.1-lib/derby.jar
+java.vendor=Oracle Corporation
+java.runtime.version=1.8.0_121-b13
+user.dir=E:\Git\RPBot
+os.name=Windows 10
+os.arch=amd64
+os.version=10.0
+derby.system.home=null
+Database Class Loader started - derby.database.classpath=''
diff --git a/lib/db-derby-10.13.1.1-lib/LICENSE b/lib/db-derby-10.13.1.1-lib/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/lib/db-derby-10.13.1.1-lib/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/lib/db-derby-10.13.1.1-lib/derby.jar b/lib/db-derby-10.13.1.1-lib/derby.jar
new file mode 100644
index 0000000..6e3bb96
Binary files /dev/null and b/lib/db-derby-10.13.1.1-lib/derby.jar differ
diff --git a/lib/db-derby-10.13.1.1-lib/derbyclient.jar b/lib/db-derby-10.13.1.1-lib/derbyclient.jar
new file mode 100644
index 0000000..c014bfc
Binary files /dev/null and b/lib/db-derby-10.13.1.1-lib/derbyclient.jar differ
diff --git a/lib/sqlite/LICENSE b/lib/sqlite/LICENSE
new file mode 100644
index 0000000..7a4a3ea
--- /dev/null
+++ b/lib/sqlite/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
\ No newline at end of file
diff --git a/lib/sqlite/sqlite-jdbc-3.20.0.jar b/lib/sqlite/sqlite-jdbc-3.20.0.jar
new file mode 100644
index 0000000..f6aa562
Binary files /dev/null and b/lib/sqlite/sqlite-jdbc-3.20.0.jar differ
diff --git a/manifest.mf b/manifest.mf
new file mode 100644
index 0000000..328e8e5
--- /dev/null
+++ b/manifest.mf
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+X-COMMENT: Main-Class will be added automatically by build
+
diff --git a/nbproject/build-impl.xml b/nbproject/build-impl.xml
new file mode 100644
index 0000000..be39905
--- /dev/null
+++ b/nbproject/build-impl.xml
@@ -0,0 +1,1403 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must set src.dir
+ Must set build.dir
+ Must set dist.dir
+ Must set build.classes.dir
+ Must set dist.javadoc.dir
+ Must set build.test.classes.dir
+ Must set build.test.results.dir
+ Must set build.classes.excludes
+ Must set dist.jar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must set javac.includes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No tests executed.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must set JVM to use for profiling in profiler.info.jvm
+ Must set profiler agent JVM arguments in profiler.info.jvmargs.agent
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select some files in the IDE or set javac.includes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ To run this application from the command line without Ant, try:
+
+ java -jar "${dist.jar.resolved}"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set run.class
+
+
+
+ Must select one file in the IDE or set run.class
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set debug.class
+
+
+
+
+ Must select one file in the IDE or set debug.class
+
+
+
+
+ Must set fix.includes
+
+
+
+
+
+
+
+
+
+ This target only works when run from inside the NetBeans IDE.
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set profile.class
+ This target only works when run from inside the NetBeans IDE.
+
+
+
+
+
+
+
+
+ This target only works when run from inside the NetBeans IDE.
+
+
+
+
+
+
+
+
+
+
+
+
+ This target only works when run from inside the NetBeans IDE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set run.class
+
+
+
+
+
+ Must select some files in the IDE or set test.includes
+
+
+
+
+ Must select one file in the IDE or set run.class
+
+
+
+
+ Must select one file in the IDE or set applet.url
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select some files in the IDE or set javac.includes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Some tests failed; see details above.
+
+
+
+
+
+
+
+
+ Must select some files in the IDE or set test.includes
+
+
+
+ Some tests failed; see details above.
+
+
+
+ Must select some files in the IDE or set test.class
+ Must select some method in the IDE or set test.method
+
+
+
+ Some tests failed; see details above.
+
+
+
+
+ Must select one file in the IDE or set test.class
+
+
+
+ Must select one file in the IDE or set test.class
+ Must select some method in the IDE or set test.method
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set applet.url
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set applet.url
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/nbproject/genfiles.properties b/nbproject/genfiles.properties
new file mode 100644
index 0000000..e35c716
--- /dev/null
+++ b/nbproject/genfiles.properties
@@ -0,0 +1,8 @@
+build.xml.data.CRC32=06b197f5
+build.xml.script.CRC32=07d39356
+build.xml.stylesheet.CRC32=8064a381@1.80.1.48
+# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
+# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
+nbproject/build-impl.xml.data.CRC32=06b197f5
+nbproject/build-impl.xml.script.CRC32=3f659279
+nbproject/build-impl.xml.stylesheet.CRC32=830a3534@1.80.1.48
diff --git a/nbproject/project.properties b/nbproject/project.properties
new file mode 100644
index 0000000..0263bfd
--- /dev/null
+++ b/nbproject/project.properties
@@ -0,0 +1,84 @@
+annotation.processing.enabled=true
+annotation.processing.enabled.in.editor=false
+annotation.processing.processor.options=
+annotation.processing.processors.list=
+annotation.processing.run.all.processors=true
+annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output
+build.classes.dir=${build.dir}/classes
+build.classes.excludes=**/*.java,**/*.form
+# This directory is removed when the project is cleaned:
+build.dir=build
+build.generated.dir=${build.dir}/generated
+build.generated.sources.dir=${build.dir}/generated-sources
+# Only compile against the classpath explicitly listed here:
+build.sysclasspath=ignore
+build.test.classes.dir=${build.dir}/test/classes
+build.test.results.dir=${build.dir}/test/results
+# Uncomment to specify the preferred debugger connection transport:
+#debug.transport=dt_socket
+debug.classpath=\
+ ${run.classpath}
+debug.test.classpath=\
+ ${run.test.classpath}
+# Files in build.classes.dir which should be excluded from distribution jar
+dist.archive.excludes=
+# This directory is removed when the project is cleaned:
+dist.dir=dist
+dist.jar=${dist.dir}/RPBot.jar
+dist.javadoc.dir=${dist.dir}/javadoc
+excludes=
+file.reference.Commands4J-1.1.0.jar=lib\\Commands4J\\Commands4J-1.1.0.jar
+file.reference.derby.jar=lib\\db-derby-10.13.1.1-lib\\derby.jar
+file.reference.derbyclient.jar=lib\\db-derby-10.13.1.1-lib\\derbyclient.jar
+file.reference.Discord4j-2.7.0-shaded.jar=lib\\Discord4J\\Discord4j-2.7.0-shaded.jar
+file.reference.RPBot-src=src
+file.reference.sqlite-jdbc-3.20.0.jar=lib\\sqlite\\sqlite-jdbc-3.20.0.jar
+includes=**
+jar.compress=false
+javac.classpath=\
+ ${file.reference.Commands4J-1.1.0.jar}:\
+ ${file.reference.Discord4j-2.7.0-shaded.jar}:\
+ ${file.reference.derby.jar}:\
+ ${file.reference.derbyclient.jar}:\
+ ${file.reference.sqlite-jdbc-3.20.0.jar}
+# Space-separated list of extra javac options
+javac.compilerargs=
+javac.deprecation=false
+javac.external.vm=true
+javac.processorpath=\
+ ${javac.classpath}
+javac.source=1.8
+javac.target=1.8
+javac.test.classpath=\
+ ${javac.classpath}:\
+ ${build.classes.dir}
+javac.test.processorpath=\
+ ${javac.test.classpath}
+javadoc.additionalparam=
+javadoc.author=false
+javadoc.encoding=${source.encoding}
+javadoc.noindex=false
+javadoc.nonavbar=false
+javadoc.notree=false
+javadoc.private=false
+javadoc.splitindex=true
+javadoc.use=true
+javadoc.version=false
+javadoc.windowtitle=
+main.class=rpbot.Main
+manifest.file=manifest.mf
+meta.inf.dir=${src.dir}/META-INF
+mkdist.disabled=false
+platform.active=default_platform
+run.classpath=\
+ ${javac.classpath}:\
+ ${build.classes.dir}
+# Space-separated list of JVM arguments used when running the project.
+# You may also define separate properties like run-sys-prop.name=value instead of -Dname=value.
+# To set system properties for unit tests define test-sys-prop.name=value:
+run.jvmargs=
+run.test.classpath=\
+ ${javac.test.classpath}:\
+ ${build.test.classes.dir}
+source.encoding=UTF-8
+src.dir=${file.reference.RPBot-src}
diff --git a/nbproject/project.xml b/nbproject/project.xml
new file mode 100644
index 0000000..5c6820b
--- /dev/null
+++ b/nbproject/project.xml
@@ -0,0 +1,13 @@
+
+
+ org.netbeans.modules.java.j2seproject
+
+
+ RPBot
+
+
+
+
+
+
+
diff --git a/src/rpbot/Main.java b/src/rpbot/Main.java
index f01ea8a..88268ab 100644
--- a/src/rpbot/Main.java
+++ b/src/rpbot/Main.java
@@ -9,33 +9,45 @@
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
+import rpbot.derbydatabase.Database;
+import rpbot.derbydatabase.DatabaseHandler;
+import rpbot.derbydatabase.DerbyDatabase;
import sx.blah.discord.api.ClientBuilder;
import sx.blah.discord.util.DiscordException;
/**
* Main
+ *
* @author ivanskodje
*/
public class Main
{
+
private static String token = ""; // Bot token
/**
* @param args the command line arguments
*/
public static void main(String[] args)
- {
+ {
+ String repositoryName = "MyRepository";
+ String username = repositoryName.toLowerCase();
+ String password = "password";
+
try (BufferedReader reader = new BufferedReader(new FileReader("token.txt")))
{
// Load token
// NB: Never share your token, or upload it to any repository!
token = reader.readLine();
-
+
// Initiate Main Client
Client.init(new ClientBuilder().withToken(token).login());
- }
- catch (IOException | DiscordException ex)
+ // Create a Database and add it to the Handler
+ Database database = new DerbyDatabase(repositoryName, username, password); // This is the part that can be changed if you want to use another database
+ DatabaseHandler.init(database);
+ }
+ catch (IOException | DiscordException ex)
{
ex.printStackTrace();
}
diff --git a/src/rpbot/client/Client.java b/src/rpbot/client/Client.java
index 48b5ecc..0a3929f 100644
--- a/src/rpbot/client/Client.java
+++ b/src/rpbot/client/Client.java
@@ -5,13 +5,13 @@
*/
package rpbot.client;
-import com.darichey.discord.api.Command;
import com.darichey.discord.api.CommandRegistry;
import rpbot.command.Calc;
import rpbot.command.Help;
import rpbot.command.Name;
import rpbot.command.Roll;
import rpbot.command.Table;
+import rpbot.command.list.List;
import sx.blah.discord.api.IDiscordClient;
import sx.blah.discord.handle.obj.IChannel;
import sx.blah.discord.util.DiscordException;
@@ -20,13 +20,16 @@
/**
* Client
+ *
* @author ivanskodje
*/
public class Client
-{
+{
+
/**
* Initiates the Client singleton
- * @param client
+ *
+ * @param client
*/
public static void init(IDiscordClient client)
{
@@ -37,20 +40,22 @@ public static void init(IDiscordClient client)
CommandRegistry.getForClient(client).register(Calc.register());
CommandRegistry.getForClient(client).register(Name.register());
CommandRegistry.getForClient(client).register(Table.register());
+ CommandRegistry.getForClient(client).register(List.register());
+ // CommandRegistry.getForClient(client).register(Sheet.register());
}
-
-
+
/**
* Send message to channel
+ *
* @param channel
- * @param message
+ * @param message
*/
public static void sendMessage(IChannel channel, String message)
{
try
{
channel.sendMessage(message);
- }
+ }
catch (MissingPermissionsException | DiscordException | RateLimitException ex)
{
ex.printStackTrace();
diff --git a/src/rpbot/command/Help.java b/src/rpbot/command/Help.java
index 38442b8..f03f735 100644
--- a/src/rpbot/command/Help.java
+++ b/src/rpbot/command/Help.java
@@ -16,28 +16,30 @@
*/
public class Help
{
+
/**
* Executes the command
- * @param context
+ *
+ * @param context
*/
public static void Execute(CommandContext context)
{
// Username (@#id)
IUser userName = context.getMessage().getAuthor();
-
+
// Generate help text
// TODO: Automatically generate help text instead of hardcoding the string
String helpText = "__**Command List:**__\n"
- + "roll, calc, name, table";
-
+ + "roll, calc, name, table, list\n\n"
+ + "Run a command by adding " + "!" + " infront of a command.";
+
// Send a list of commands
Client.sendMessage(context.getMessage().getChannel(), userName + ":\n" + helpText);
}
-
-
+
/*
Used to register table as a command
- */
+ */
public static Command register()
{
// Command: help
@@ -47,7 +49,7 @@ public static Command register()
{
Help.Execute(context);
});
-
+
return help;
}
}
diff --git a/src/rpbot/command/Roll.java b/src/rpbot/command/Roll.java
index cfc78c9..09bc265 100644
--- a/src/rpbot/command/Roll.java
+++ b/src/rpbot/command/Roll.java
@@ -7,76 +7,81 @@
import sx.blah.discord.handle.obj.IUser;
/**
- * Roll - For rolling dice
- * (e.g. /roll 2d6 will generate two dice with 6-sides)
+ * Roll - For rolling dice (e.g. /roll 2d6 will generate two dice with 6-sides)
+ *
* @author ivanskodje
*/
public class Roll
-{
+{
+
// Limitations
private static final int MAX_ROLLS = 20;
private static final int MAX_DICE_SIDES = 1000;
-
+
/**
* Executes the command
- * @param context
+ *
+ * @param context
*/
public static void Execute(CommandContext context)
{
// If we have no arguments, send a warning message and return
- if(context.getArgs().length < 1)
+ if (context.getArgs().length < 1)
{
invalidExpression(context);
return;
}
-
+
// Username (@#id)
IUser userName = context.getMessage().getAuthor();
-
+
// Get our dice argument
String diceRoll = context.getArgs()[0].toLowerCase(); // Get dice roll
-
+
// Split text into dice count and dice side numbers
String[] diceCountAndSides = diceRoll.split("d");
-
+
// Error check: Make sure we have two numbers, a number before and after the 'd' (eg. 2d7 -> {2, 7})
- if(diceCountAndSides.length < 2)
+ if (diceCountAndSides.length < 2)
{
invalidExpression(context);
return;
- }
-
+ }
+
try
{
// Parse dice count and sides into integer
int diceCount = Integer.parseInt(diceCountAndSides[0]);
int diceSides = Integer.parseInt(diceCountAndSides[1]);
-
+
// Setup empty dice string and start value
String diceString = "";
- int totalValue = 0;
-
+ int totalValue = 0;
+
// Error handling : Make sure we dont try to roll an excessive amount of dice
- if(diceCount > MAX_ROLLS)
+ if (diceCount > MAX_ROLLS)
{
Client.sendMessage(context.getMessage().getChannel(), userName + ":\nYou cannot roll more than " + MAX_ROLLS + " dices at once!");
return;
}
- else if(diceSides > MAX_DICE_SIDES)
+ else if (diceSides > MAX_DICE_SIDES)
{
Client.sendMessage(context.getMessage().getChannel(), userName + ":\nYou cannot roll dice over " + MAX_DICE_SIDES + " sides!");
return;
}
-
+
// Roll Dice
- for(int i = 0; i < diceCount; i++)
+ for (int i = 0; i < diceCount; i++)
{
// Roll dice
Random random = new Random();
+
+ boolean idiotic_roll_safeguard = true;
+
int dice = random.nextInt(diceSides) + 1; // Adding +1 since we dont want 0 to be an option
-
+
// Build string
- if(i == 0)
+ if (i == 0)
{
diceString += dice;
}
@@ -84,33 +89,31 @@ else if(diceSides > MAX_DICE_SIDES)
{
diceString += ", " + dice;
}
-
+
// Add dice value to total
totalValue += dice;
}
-
+
// Send result
- Client.sendMessage(context.getMessage().getChannel(), userName + ":\n(" + diceString + ") Total value: " + totalValue);
+ Client.sendMessage(context.getMessage().getChannel(), "[v2.0] " + userName + ":\n(" + diceString + ") Total value: " + totalValue);
}
- catch(NumberFormatException ex)
+ catch (NumberFormatException ex)
{
invalidExpression(context);
}
}
-
-
+
/*
Sends a default message explaining the expression for rolling dice
- */
+ */
private static void invalidExpression(CommandContext context)
{
Client.sendMessage(context.getMessage().getChannel(), context.getMessage().getAuthor() + ":\nDice expressions contain the standard representations of dice in text form (e.g. 2d6 is two 6-sided dice).\nTry typing in '!roll 2d6'.");
}
-
-
+
/*
Used to register table as a command
- */
+ */
public static Command register()
{
// Command: roll
@@ -120,7 +123,7 @@ public static Command register()
{
Roll.Execute(context);
});
-
+
return roll;
}
}
diff --git a/src/rpbot/command/Sheet.java b/src/rpbot/command/Sheet.java
new file mode 100644
index 0000000..cb22756
--- /dev/null
+++ b/src/rpbot/command/Sheet.java
@@ -0,0 +1,158 @@
+package rpbot.command;
+
+import com.darichey.discord.api.Command;
+import com.darichey.discord.api.CommandContext;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Random;
+import rpbot.Main;
+import rpbot.client.Client;
+import rpbot.derbydatabase.DatabaseHandler;
+import rpbot.sheetdata.Item;
+import rpbot.sheetdata.SheetData;
+import sx.blah.discord.handle.obj.IUser;
+
+/**
+ * For storing and retrieving user owned character sheets
+ *
+ * @author Ivan Skodje
+ */
+public class Sheet
+{
+
+ ArrayList playerSheets = new ArrayList<>();
+
+ /* Commands
+ - create : Creates a sheet for the user
+ - edit
+ - : Returns property value(s) - Outputs the old value and new value
+
+ */
+ /**
+ * Executes the command
+ *
+ * @param context
+ */
+ public static void Execute(CommandContext context)
+ {
+ // Get our argument
+ String[] args = context.getArgs();
+
+ // If we have no arguments, send a warning message and return
+ if (args.length < 1)
+ {
+ invalidExpression(context);
+ return;
+ }
+
+ if(args[0].equals("get"))
+ {
+ String keyValue = args[1];
+ Item myItem = DatabaseHandler.getItem(context.getMessage().getAuthor(), keyValue);
+
+ if(myItem == null)
+ {
+ Client.sendMessage(context.getMessage().getChannel(), context.getMessage().getAuthor() + ":\n" + "Does not exist!");
+ return;
+ }
+
+ // Output the item
+ if(myItem.getValue() == null)
+ {
+ Client.sendMessage(context.getMessage().getChannel(), context.getMessage().getAuthor() + ":\n" + myItem.getKey());
+ }
+ else
+ {
+ Client.sendMessage(context.getMessage().getChannel(), context.getMessage().getAuthor() + ":\n" + myItem.getKey() + ": " + myItem.getValue());
+ }
+ }
+
+ if(args[0].equals("set"))
+ {
+ Item newItem = new Item();
+ for (int i = 1; i < args.length; i++)
+ {
+ // Store first value as property
+ if (i == 1)
+ {
+ // Set ID
+ newItem.setUserId(context.getMessage().getAuthor().getID());
+
+ // Add Key Value
+ newItem.setKey(args[i]);
+ }
+ else if (i == 2)
+ {
+ // Add Value
+ newItem.setValue(args[i]);
+ }
+ }
+
+ if(newItem.getUserId() != null && newItem.getKey() != null)
+ {
+ System.out.println("Adding to Database: " + newItem.toJson());
+ DatabaseHandler.addItem(newItem);
+ Client.sendMessage(context.getMessage().getChannel(), context.getMessage().getAuthor() + ":\n" + newItem.getKey() + " successfully added.");
+ }
+ }
+
+ if(args[0].equals("delete"))
+ {
+ String keyValue = args[1];
+ if(DatabaseHandler.deleteItem(context.getMessage().getAuthor(), keyValue))
+ {
+ Client.sendMessage(context.getMessage().getChannel(), context.getMessage().getAuthor() + ":\nItem deleted!");
+ }
+ else
+ {
+ Client.sendMessage(context.getMessage().getChannel(), context.getMessage().getAuthor() + ":\nItems that do not exist cannot be deleted.");
+ }
+ }
+
+
+ if(args[0].equals("list"))
+ {
+ String text = context.getMessage().getAuthor() + "\n\n";
+ for(Item item : DatabaseHandler.getItems(context.getMessage().getAuthor()))
+ {
+ // Output the item
+ if(item.getValue() == null)
+ {
+ text += item.getKey() + "\n";
+ }
+ else
+ {
+ text += item.getKey() + ": " + item.getValue() + "\n";
+ }
+ }
+
+ Client.sendMessage(context.getMessage().getChannel(), text);
+ }
+ }
+
+
+ /*
+ Used to register table as a command
+ */
+ public static Command register()
+ {
+ // Command: name
+ Command sheet = new Command("sheet");
+ sheet.onExecuted((context) ->
+ {
+ Sheet.Execute(context);
+ });
+
+ return sheet;
+ }
+
+ /*
+ Sends a default message explaining the expression for rolling dice
+ */
+ private static void invalidExpression(CommandContext context)
+ {
+ Client.sendMessage(context.getMessage().getChannel(), context.getMessage().getAuthor() + ":\nInvalid Sheet command(s)");
+ }
+}
diff --git a/src/rpbot/command/list/List.java b/src/rpbot/command/list/List.java
new file mode 100644
index 0000000..9a9aaeb
--- /dev/null
+++ b/src/rpbot/command/list/List.java
@@ -0,0 +1,434 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package rpbot.command.list;
+
+import com.darichey.discord.api.Command;
+import com.darichey.discord.api.CommandContext;
+import java.util.ArrayList;
+import java.util.Arrays;
+import org.apache.commons.lang3.StringUtils;
+import rpbot.client.Client;
+import rpbot.command.list.classes.Item;
+import rpbot.command.list.classes.ItemList;
+import rpbot.command.list.classes.Property;
+import rpbot.command.list.database.DatabaseHandler;
+import rpbot.command.list.database.SQLiteDatabase;
+import sx.blah.discord.handle.obj.IUser;
+
+/**
+ *
+ * @author Ivan Skodje
+ */
+public class List
+{
+
+ private static DatabaseHandler databaseHandler;
+
+ private final static String[] ADMINS =
+ {
+ "237888140633702400" // Me
+ };
+
+ /**
+ * Executes the command
+ *
+ * @param context
+ */
+ public static void Execute(CommandContext context)
+ {
+ // Username (@#id)
+ IUser userName = context.getMessage().getAuthor();
+
+ int argSize = context.getArgs().length;
+
+ // NO ARGUMENTS
+ // If we have no arguments, display root lists
+ if (argSize < 1)
+ {
+ ArrayList lists = databaseHandler.getLists();
+ String output = "**[** *ID* **]**\t\t**List Name**\n\n";
+ for (ItemList list : lists)
+ {
+ output += "[" + list.getId() + "] " + list.getName() + "\n";
+ }
+
+ Client.sendMessage(context.getMessage().getChannel(), userName + ":\n" + output);
+ return;
+ }
+
+ if (argSize >= 2)
+ {
+ String arg1 = context.getArgs()[0].toLowerCase();
+ String name = "";
+
+ if (arg1.equals("add"))
+ {
+ for (String arg : context.getArgs())
+ {
+ name += arg + " ";
+ }
+
+ // Remove trailing whitespaces
+ name = name.trim();
+ name = name.replaceFirst(arg1 + " ", "");
+
+ ItemList list = new ItemList(name);
+ list = databaseHandler.insertList(list);
+
+ if (list != null)
+ {
+ Client.sendMessage(context.getMessage().getChannel(), userName + ":\n" + name + " was successfully added.");
+ return;
+ }
+ }
+ else if (arg1.equals("remove"))
+ {
+ // Check if user have permission to use remove
+ if (!hasAdmin(userName.getID()))
+ {
+ System.out.println("userName.mention(): " + userName.mention());
+ Client.sendMessage(context.getMessage().getChannel(), userName + ":\n" + "For safety reasons, you do not have permission to remove a list or item.\n\n"
+ + "Contact <@!237888140633702400> for assistance if you screwed up! \n(Don't worry, it is expected. A lot of work remains to do to make this user friendly...)");
+ return;
+ }
+
+ String arg2 = context.getArgs()[1].toLowerCase(); // item | list
+
+ // Item or ID?
+ if (arg2.equals("item") && argSize >= 3)
+ {
+ String arg3 = context.getArgs()[2];
+ int id = Integer.parseInt(arg3);
+
+ // Remove item with the name ID
+ if (databaseHandler.removeItem(id))
+ {
+ Client.sendMessage(context.getMessage().getChannel(), userName + ":\n" + "Item was successfully deleted.");
+ }
+ else
+ {
+ Client.sendMessage(context.getMessage().getChannel(), userName + ":\n" + "Not a valid Item ID.");
+ }
+ }
+ // ID
+ else if (arg2.matches("^-?\\d+$"))
+ {
+ int id = Integer.parseInt(arg2);
+ // Remove item with the name ID
+ if (databaseHandler.removeList(id))
+ {
+ // Set all lists that had deleted list as deleted
+ databaseHandler.removeListsWithParentId(id);
+ databaseHandler.removeItemsWithListId(id);
+
+ // OK
+ Client.sendMessage(context.getMessage().getChannel(), userName + ":\n" + "List was successfully deleted.");
+ }
+ else
+ {
+ Client.sendMessage(context.getMessage().getChannel(), userName + ":\n" + "Not a valid List ID.");
+ return;
+ }
+ }
+ }
+ }
+
+ if (argSize == 1)
+ {
+ // Get first argument
+ String arg1 = context.getArgs()[0].toLowerCase();
+
+ if (arg1.equals("help"))
+ {
+ String helpText = "__Commands for retrieving data:__\n"
+ + "**!list** -> prints out the main lists stored\n"
+ + "**!list all** -> prints out all lists, even sub-lists.\n"
+ + "**!list [id] ** -> prints out any sublists belonging to list [id]\n"
+ + "**!list [id] items ** -> prints out a list of items belonging to list [id]\n"
+ + "**!list item [id]** -> prints out details of item [id]\n"
+ + "\n"
+ + "__Commands for adding data:__\n"
+ + "**!list add [name]** -> add a new list\n"
+ + "**!list [id] add item [item data]** -> add an item inside a List\n"
+ + "**!list [id] add list [name]** -> add a list as a child of another list\n"
+ + "\n"
+ + "__Commands for removing data (ADMINS ONLY FOR SAFETY REASONS):__\n"
+ + "**!list remove item [id]** -> Removes an Item from the list [id]\n"
+ + "**!list remove [id]** -> Removes an entire list and all its contents";
+ Client.sendMessage(context.getMessage().getChannel(), userName + ":\n" + helpText);
+ }
+
+ // ARGUMENT: ALL
+ // If the command was all, display all lists regardless of
+ if (arg1.equals("all"))
+ {
+ ArrayList lists = databaseHandler.getAllLists();
+ String output = "**[** *ID* **]**\t\t**List Name**\n\n";
+ for (ItemList list : lists)
+ {
+ output += "[" + list.getId() + "] " + list.getName() + "\n";
+ }
+
+ Client.sendMessage(context.getMessage().getChannel(), userName + ":\n" + output);
+
+ return;
+ }
+ // ARGUMENT: ID
+ else if (arg1.matches("^-?\\d+$"))
+ {
+ int id = Integer.parseInt(arg1);
+ ArrayList lists = databaseHandler.getListsFromParentId(id);
+
+ // If we got no list, then we failed finding matching ID
+ if (lists.isEmpty())
+ {
+ Client.sendMessage(context.getMessage().getChannel(), userName + ":\n" + "No matching list found. Did you enter the correct ID?");
+ }
+ else
+ {
+ String output = "**[** *ID* **]**\t\t**List Name**\n\n";
+ for (ItemList list : lists)
+ {
+ output += "[" + list.getId() + "] " + list.getName() + "\n";
+ }
+
+ Client.sendMessage(context.getMessage().getChannel(), userName + ":\n" + output);
+ }
+ return;
+ }
+ }
+ else if (argSize == 2)
+ {
+ String arg1 = context.getArgs()[0].toLowerCase();
+ String arg2 = context.getArgs()[1].toLowerCase();
+
+ // If first arg is an integer, it must be an ID
+ if (arg1.matches("^-?\\d+$"))
+ {
+ int id = Integer.parseInt(arg1);
+
+ // If second arg is items, display the items belonging to the list ID
+ if (arg2.equals("items"))
+ {
+ ArrayList- items = databaseHandler.getItemsFromListId(id);
+
+ // If we got no list, then we failed finding matching ID
+ if (items.isEmpty())
+ {
+ Client.sendMessage(context.getMessage().getChannel(), userName + ":\n" + "No matching list found. Did you enter the correct ID?");
+ }
+ else
+ {
+ String output = "**[** *ID* **]**\t\t**Item Name**\n\n";
+ for (Item item : items)
+ {
+ output += "[" + item.getId() + "] " + item.getName() + "\n";
+ }
+
+ Client.sendMessage(context.getMessage().getChannel(), userName + ":\n" + output);
+ }
+ }
+ }
+ // First argument is not an integer, must be a string
+ else if (arg1.matches("item"))
+ {
+ // If second argument is an integer, we got an ID
+ if (arg2.matches("^-?\\d+$"))
+ {
+ int id = Integer.parseInt(arg2);
+ Item item = databaseHandler.getItem(id);
+ Client.sendMessage(context.getMessage().getChannel(), userName + ":\n" + getItemInfoFromItem(item));
+ return;
+ }
+ }
+ }
+ // [ID] add item|list
+ else if (argSize >= 4)
+ {
+ // Args
+ String arg1 = context.getArgs()[0].toLowerCase(); // ID
+ String arg2 = context.getArgs()[1].toLowerCase(); // add | remove
+ String arg3 = context.getArgs()[2].toLowerCase(); // list | item
+
+ // Args that will be removed
+ String removeArgs = "!list " + arg1 + " " + arg2 + " " + arg3 + " ";
+
+ // Pure text from input
+ String dataText = context.getMessage().getContent().replaceAll(removeArgs, "");
+
+ // ARG1 - Get ID
+ if (arg1.matches("^-?\\d+$"))
+ {
+ int id = Integer.parseInt(arg1);
+
+ // Check that the List ID exists
+ if (databaseHandler.getList(id) == null)
+ {
+ // Do nothing, list ID does not exist.
+ Client.sendMessage(context.getMessage().getChannel(), userName + ":\n" + "List ID does not exist.");
+ return;
+ }
+
+ if (arg2.equals("add"))
+ {
+ // Add item, with dataText being the Item Data
+ if (arg3.equals("item"))
+ {
+ // Convert the pure text into an Item
+ Item item = getItemFromText(dataText);
+
+ // Add List ID from arg to the item
+ int listId = Integer.parseInt(arg1);
+ item.setListId(listId);
+
+ item = databaseHandler.insertItem(item);
+
+ if (item != null)
+ {
+ String itemInfo = getItemInfoFromItem(item);
+ Client.sendMessage(context.getMessage().getChannel(), userName + ":\n" + itemInfo);
+ return;
+ }
+ }
+ // Add List, with dataText being the List Name
+ else if (arg3.equals("list"))
+ {
+
+ // Add List ID from arg to the item
+ int listId = Integer.parseInt(arg1);
+
+ // Create List
+ ItemList list = new ItemList(dataText);
+
+ // Insert parent ID into the list
+ list.setParentListId(listId);
+
+ // Insert list to database
+ list = databaseHandler.insertList(list);
+
+ if (list != null)
+ {
+ ItemList parent = databaseHandler.getList(list.getParentListId());
+ Client.sendMessage(context.getMessage().getChannel(), userName + ":\n" + "Successfully added list " + list.getName() + " (" + list.getId() + ") into " + parent.getName() + " (" + parent.getId() + ").");
+ return;
+ }
+ }
+ }
+ else if (arg2.equals("remove"))
+ {
+ // TODO
+ return;
+ }
+ }
+ else
+ {
+ Client.sendMessage(context.getMessage().getChannel(), userName + ":\n" + ""
+ + "Not a valid input.\n"
+ + "**Examples of use:**\n\n"
+ + "!list [ID] add item
- \n"
+ + "!list [ID] add list
\n");
+ }
+ }
+ }
+
+ /**
+ * Returns true if the input ID matches any listed inside ADMINS array
+ *
+ * @param inputStr
+ * @return
+ */
+ public static boolean hasAdmin(String inputStr)
+ {
+ return Arrays.stream(ADMINS).parallel().anyMatch(inputStr::contains);
+ }
+
+ /*
+ Used to register table as a command
+ */
+ public static Command register()
+ {
+ // Setup database
+ SQLiteDatabase database = new SQLiteDatabase("MyList");
+ databaseHandler = new DatabaseHandler(database);
+
+ // Command: help
+ Command command = new Command("list");
+ command.withAliases("l");
+ command.onExecuted((context) ->
+ {
+ List.Execute(context);
+ });
+
+ return command;
+ }
+
+ private static Item getItemFromText(String dataText)
+ {
+ // Get text
+ String text = dataText;
+
+ // Get pasted string in array (separated by newline)
+ String[] pastedString = text.split("\\r?\\n");
+
+ // Properties belonging to the Artifact
+ ArrayList properties = new ArrayList<>();
+
+ // Artifact - First line will always be the title
+ Item newItem = new Item(pastedString[0]);
+
+ // Iterate each line (except the first)
+ for (int i = 1; i < pastedString.length; i++)
+ {
+ // Check if we have a : that indicates a "type".
+ if (pastedString[i].contains(":"))
+ {
+ // Set Property name
+ String[] splitText = pastedString[i].split(":");
+ properties.add(new Property(splitText[0]));
+
+ // Set property description
+ String description = pastedString[i].replace(splitText[0] + ":", "").replaceFirst("^\\s*", "");
+ properties.get(properties.size() - 1).setDescription(description);
+ }
+ else
+ {
+ // Does not contain : means we are appending the description to the last one
+ // Get last description string
+ if (!properties.isEmpty())
+ {
+ String description = properties.get(properties.size() - 1).getDescription();
+
+ // Append to description string
+ description += "\n" + pastedString[i];
+
+ // Set new description
+ properties.get(properties.size() - 1).setDescription(description);
+ }
+
+ }
+ }
+
+ // Set properties
+ newItem.setProperties(properties);
+
+ // Returns the Item
+ return newItem;
+ }
+
+ private static String getItemInfoFromItem(Item item)
+ {
+ // Build string
+ String text = "__**" + item.getName() + "**__\n\n";
+
+ // Get each description
+ for (Property desc : item.getProperties())
+ {
+ text += "**" + desc.getName() + "**:\n" + desc.getDescription() + "\n\n";
+ }
+
+ return text;
+ }
+}
diff --git a/src/rpbot/command/list/classes/Item.java b/src/rpbot/command/list/classes/Item.java
new file mode 100644
index 0000000..6c98c5e
--- /dev/null
+++ b/src/rpbot/command/list/classes/Item.java
@@ -0,0 +1,86 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package rpbot.command.list.classes;
+
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ *
+ * @author Ivan Skodje
+ */
+public class Item
+{
+
+ private int id;
+ private int listId;
+ private String name;
+ private ArrayList properties;
+
+ public Item(String name)
+ {
+ this.name = name;
+ }
+
+ public int getId()
+ {
+ return id;
+ }
+
+ public void setId(int id)
+ {
+ this.id = id;
+ }
+
+ public int getListId()
+ {
+ return listId;
+ }
+
+ public void setListId(int listId)
+ {
+ this.listId = listId;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+ public ArrayList getProperties()
+ {
+ return properties;
+ }
+
+ public void setProperties(ArrayList properties)
+ {
+ this.properties = properties;
+ }
+
+ public String getJsonContent()
+ {
+ Gson gson = new Gson();
+ return gson.toJson(properties);
+ }
+
+ public void setJsonContent(String jsonContent)
+ {
+ Gson gson = new Gson();
+ Type collectionType = new TypeToken>()
+ {
+ }.getType();
+ properties = gson.fromJson(jsonContent, collectionType);
+ }
+
+}
diff --git a/src/rpbot/command/list/classes/ItemList.java b/src/rpbot/command/list/classes/ItemList.java
new file mode 100644
index 0000000..d720bbd
--- /dev/null
+++ b/src/rpbot/command/list/classes/ItemList.java
@@ -0,0 +1,54 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package rpbot.command.list.classes;
+
+/**
+ *
+ * @author Ivan Skodje
+ */
+public class ItemList
+{
+
+ private int id;
+ private String name;
+ private int parentListId;
+
+ public ItemList(String name)
+ {
+ this.name = name;
+ }
+
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public int getId()
+ {
+ return id;
+ }
+
+ public void setId(int id)
+ {
+ this.id = id;
+ }
+
+ public int getParentListId()
+ {
+ return parentListId;
+ }
+
+ public void setParentListId(int parentListId)
+ {
+ this.parentListId = parentListId;
+ }
+
+}
diff --git a/src/rpbot/command/list/classes/Property.java b/src/rpbot/command/list/classes/Property.java
new file mode 100644
index 0000000..a3fa4fd
--- /dev/null
+++ b/src/rpbot/command/list/classes/Property.java
@@ -0,0 +1,78 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package rpbot.command.list.classes;
+
+/**
+ *
+ * @author Ivan Skodje
+ */
+public class Property
+{
+
+ // Property name
+ private String name;
+
+ // Property description
+ private String description;
+
+ /**
+ * An Item may contain several Properties, a Property belongs only to one
+ * List
+ *
+ * @param name
+ */
+ public Property(String name)
+ {
+ this(name, "");
+ }
+
+ public Property(String name, String description)
+ {
+ this.name = name;
+ this.description = description;
+ }
+
+ /**
+ * Set property name
+ *
+ * @param name
+ */
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+ /**
+ * Return property name
+ *
+ * @return
+ */
+ public String getName()
+ {
+ return name;
+ }
+
+ /**
+ * Set property description
+ *
+ * @param description
+ */
+ public void setDescription(String description)
+ {
+ this.description = description;
+ }
+
+ /**
+ * Return property description
+ *
+ * @return
+ */
+ public String getDescription()
+ {
+ return description;
+ }
+
+}
diff --git a/src/rpbot/command/list/database/Database.java b/src/rpbot/command/list/database/Database.java
new file mode 100644
index 0000000..24c1770
--- /dev/null
+++ b/src/rpbot/command/list/database/Database.java
@@ -0,0 +1,46 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package rpbot.command.list.database;
+
+import java.sql.ResultSet;
+import rpbot.command.list.classes.ItemList;
+import rpbot.command.list.classes.Item;
+
+/**
+ *
+ * @author Ivan Skodje
+ */
+public interface Database
+{
+
+ /* Establishes connection with server */
+ public void connect();
+
+ /* Executes a query, returns the resultset */
+ public ResultSet executeQuery(String query);
+
+ /* Executes a query action, returns a boolean to determine success or failure */
+ public boolean executeAction(String query);
+
+ /* Inserts a ItemList into database, and returns the same ItemList with the associated database ID */
+ public ItemList insertList(ItemList list);
+
+ /* Inserts a ItemList into database, and returns the same ItemList with the associated database ID */
+ public Item insertItem(Item list);
+
+ /* Removes a List from database */
+ public boolean removeList(int id);
+
+ /* Removes an Item from database */
+ public boolean removeItem(int id);
+
+ /* Remove all lists with matching parent id */
+ public boolean removeListsWithParentId(int id);
+
+ /* Remove all items with matching list id */
+ public boolean removeItemsWithListId(int id);
+
+}
diff --git a/src/rpbot/command/list/database/DatabaseHandler.java b/src/rpbot/command/list/database/DatabaseHandler.java
new file mode 100644
index 0000000..62bd80d
--- /dev/null
+++ b/src/rpbot/command/list/database/DatabaseHandler.java
@@ -0,0 +1,325 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package rpbot.command.list.database;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collections;
+import rpbot.command.list.classes.Item;
+import rpbot.command.list.classes.ItemList;
+
+/**
+ *
+ * @author Ivan Skodje
+ */
+public class DatabaseHandler
+{
+
+ // Database
+ private Database database = null;
+
+ // Setup a Gson
+ private final static Gson GSON = new GsonBuilder().setPrettyPrinting().create();
+
+ // ItemList folder path
+ private final static String PATH = "data/lists/";
+
+ /**
+ * Data Handler
+ *
+ * @param db
+ */
+ public DatabaseHandler(Database db)
+ {
+ // Setup connection
+ database = db;
+ database.connect();
+ }
+
+ public ItemList insertList(ItemList list)
+ {
+ return database.insertList(list);
+ }
+
+ public Item insertItem(Item item)
+ {
+ return database.insertItem(item);
+ }
+
+ public ArrayList getAllLists()
+ {
+ ArrayList lists = new ArrayList<>();
+
+ // Select all lists regardless of parenthood
+ String QUERY = "SELECT * FROM LIST";
+ ResultSet resultSet = database.executeQuery(QUERY);
+
+ try
+ {
+ // Iterate through all clients
+ while (resultSet.next())
+ {
+ // Id
+ int columnId = resultSet.getInt("id");
+
+ // Parent ItemList ID (if any)
+ int parentListId = resultSet.getInt("parent_list_id");
+
+ // Name
+ String columnName = resultSet.getString("name");
+
+ // Create object
+ ItemList list = new ItemList(columnName); // Name
+ list.setId(columnId); // ID
+ list.setParentListId(parentListId); // Parent ItemList ID
+
+ // Add to ArrayList
+ lists.add(list);
+
+ // Sort clients alphabetically
+ Collections.sort(lists, (o1, o2) -> o1.getName().compareTo(o2.getName()));
+ }
+ }
+ catch (SQLException ex)
+ {
+ ex.printStackTrace();
+ }
+
+ return lists;
+ }
+
+ /**
+ * Loads lists the root lists that does not have any parent lists
+ *
+ * @return
+ */
+ public ArrayList getLists()
+ {
+ ArrayList lists = new ArrayList<>();
+
+ // Select all lists that does not have any parent lists
+ String QUERY = "SELECT * FROM LIST WHERE parent_list_id is null";
+ ResultSet resultSet = database.executeQuery(QUERY);
+
+ try
+ {
+ // Iterate through all clients
+ while (resultSet.next())
+ {
+ // Id
+ int columnId = resultSet.getInt("id");
+
+ // Parent ItemList ID (if any)
+ // int parentListId = resultSet.getInt("parent_list_id");
+ // Name
+ String columnName = resultSet.getString("name");
+
+ // Create object
+ ItemList list = new ItemList(columnName);
+ list.setId(columnId);
+ // list.setParentListId(parentListId); // Parent ItemList ID
+
+ // Add to ArrayList
+ lists.add(list);
+
+ // Sort clients alphabetically
+ Collections.sort(lists, (o1, o2) -> o1.getName().compareTo(o2.getName()));
+ }
+ }
+ catch (SQLException ex)
+ {
+ ex.printStackTrace();
+ }
+
+ return lists;
+ }
+
+ /**
+ * Returns a matching ItemList, or a null if none exist
+ *
+ * @param id
+ * @return
+ */
+ public ItemList getList(int id)
+ {
+ // Select all lists that does not have any parent lists
+ String QUERY = "SELECT * FROM LIST WHERE id=" + id;
+ ResultSet resultSet = database.executeQuery(QUERY);
+
+ try
+ {
+ // Iterate through all clients
+ while (resultSet.next())
+ {
+ // Id
+ int columnId = resultSet.getInt("id");
+
+ // Parent ItemList ID (if any)
+ int parentListId = resultSet.getInt("parent_list_id");
+
+ // Name
+ String columnName = resultSet.getString("name");
+
+ // Create object
+ ItemList list = new ItemList(columnName);
+ list.setId(columnId);
+ list.setParentListId(parentListId); // Parent ItemList ID
+
+ return list;
+ }
+ }
+ catch (SQLException ex)
+ {
+ ex.printStackTrace();
+ }
+
+ return null;
+ }
+
+ public ArrayList getListsFromParentId(int id)
+ {
+ ArrayList lists = new ArrayList<>();
+
+ // Select all lists that does not have any parent lists
+ String QUERY = "SELECT * FROM LIST WHERE parent_list_id=" + id;
+ ResultSet resultSet = database.executeQuery(QUERY);
+
+ try
+ {
+ // Iterate through all clients
+ while (resultSet.next())
+ {
+ // Id
+ int columnId = resultSet.getInt("id");
+
+ // Parent ItemList ID (if any)
+ int parentListId = resultSet.getInt("parent_list_id");
+
+ // Name
+ String columnName = resultSet.getString("name");
+
+ // Create object
+ ItemList list = new ItemList(columnName);
+ list.setId(columnId);
+ list.setParentListId(parentListId); // Parent ItemList ID
+
+ // Add to array
+ lists.add(list);
+
+ // Sort clients alphabetically
+ Collections.sort(lists, (o1, o2) -> o1.getName().compareTo(o2.getName()));
+
+ }
+ }
+ catch (SQLException ex)
+ {
+ ex.printStackTrace();
+ }
+
+ return lists;
+ }
+
+ public ArrayList- getItemsFromListId(int id)
+ {
+ ArrayList
- items = new ArrayList<>();
+
+ // Select all lists that does not have any parent lists
+ String QUERY = "SELECT * FROM ITEM WHERE list_id=" + id;
+ ResultSet resultSet = database.executeQuery(QUERY);
+
+ try
+ {
+ // Iterate through all clients
+ while (resultSet.next())
+ {
+ // Id
+ int columnId = resultSet.getInt("id");
+
+ // Name
+ String columnName = resultSet.getString("name");
+
+ // Create object
+ Item item = new Item(columnName);
+ item.setId(columnId);
+
+ // Add to array
+ items.add(item);
+
+ // Sort clients alphabetically
+ Collections.sort(items, (o1, o2) -> o1.getName().compareTo(o2.getName()));
+ }
+ }
+ catch (SQLException ex)
+ {
+ ex.printStackTrace();
+ }
+
+ return items;
+ }
+
+ public Item getItem(int id)
+ {
+ // Select all lists that does not have any parent lists
+ String QUERY = "SELECT * FROM ITEM WHERE id=" + id;
+ ResultSet resultSet = database.executeQuery(QUERY);
+
+ try
+ {
+ // Iterate through all clients
+ while (resultSet.next())
+ {
+ // Id
+ int columnId = resultSet.getInt("id");
+
+ // List ID
+ int columnListId = resultSet.getInt("list_id");
+
+ // Name
+ String columnName = resultSet.getString("name");
+
+ // Json content
+ String columnJsonContent = resultSet.getString("json_content");
+
+ // Create object
+ Item item = new Item(columnName);
+ item.setId(columnId);
+ item.setListId(columnListId);
+ item.setJsonContent(columnJsonContent);
+ return item;
+ }
+ }
+ catch (SQLException ex)
+ {
+ ex.printStackTrace();
+ }
+
+ // If this runs, we failed to get item
+ return null;
+ }
+
+ public boolean removeItem(int id)
+ {
+ return database.removeItem(id);
+ }
+
+ public boolean removeList(int id)
+ {
+ return database.removeList(id);
+ }
+
+ public boolean removeListsWithParentId(int id)
+ {
+ return database.removeListsWithParentId(id);
+ }
+
+ public boolean removeItemsWithListId(int id)
+ {
+ return database.removeItemsWithListId(id);
+ }
+}
diff --git a/src/rpbot/command/list/database/SQLiteDatabase.java b/src/rpbot/command/list/database/SQLiteDatabase.java
new file mode 100644
index 0000000..c90ca9e
--- /dev/null
+++ b/src/rpbot/command/list/database/SQLiteDatabase.java
@@ -0,0 +1,429 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package rpbot.command.list.database;
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import rpbot.command.list.classes.Item;
+import rpbot.command.list.classes.ItemList;
+
+/**
+ *
+ * @author Ivan Skodje
+ */
+public class SQLiteDatabase implements Database
+{
+
+ private static String databaseURL;
+ private static Connection connection = null;
+ private static Statement statement = null;
+ private String databaseName = "UndefinedDatabase";
+ private static PreparedStatement preparedStatement = null;
+
+ /*
+ In order to work a SQLite database, we nmeed to load a database name (or create it)
+ */
+ public SQLiteDatabase(String databaseName)
+ {
+ // Put database url together
+ databaseURL = "jdbc:sqlite:" + databaseName + ".db";
+
+ // Get database name
+ this.databaseName = databaseName;
+ }
+
+ /**
+ * Connect to database
+ */
+ @Override
+ public void connect()
+ {
+ try
+ {
+ // Setup driver and establish connection
+ Class.forName("org.sqlite.JDBC");
+ }
+ catch (ClassNotFoundException ex)
+ {
+ Logger.getLogger(SQLiteDatabase.class.getName()).log(Level.SEVERE, null, ex);
+ }
+ try
+ {
+ connection = DriverManager.getConnection(databaseURL);
+ }
+ catch (SQLException ex)
+ {
+ Logger.getLogger(SQLiteDatabase.class.getName()).log(Level.SEVERE, null, ex);
+ }
+
+ // Setup tables (if they haven't been)
+ setupTables();
+ }
+
+ /**
+ * Executes a query, returns resultset
+ *
+ * @param query
+ * @return
+ */
+ @Override
+ public ResultSet executeQuery(String query)
+ {
+ ResultSet resultSet = null;
+
+ try
+ {
+ statement = connection.createStatement();
+ resultSet = statement.executeQuery(query);
+ }
+ catch (SQLException ex)
+ {
+ System.err.println(ex.getMessage());
+ }
+
+ return resultSet;
+ }
+
+ /**
+ * Executes an action, returns a boolean
+ *
+ * @param query
+ * @return
+ */
+ @Override
+ public boolean executeAction(String query)
+ {
+ try
+ {
+ statement = connection.createStatement();
+ statement.execute(query);
+ return true;
+ }
+ catch (SQLException ex)
+ {
+ System.err.println(ex.getMessage());
+ return false;
+ }
+ }
+
+ @Override
+ public ItemList insertList(ItemList list)
+ {
+ try
+ {
+ String query;
+
+ // If the parent list id is not set (0), only insert the name
+ // This implies that this list is a root list and will appear on top without any parent.
+ if (list.getParentListId() == 0)
+ {
+ query = "INSERT INTO LIST (name) values (?)";
+ preparedStatement = connection.prepareStatement(query, PreparedStatement.RETURN_GENERATED_KEYS);
+ preparedStatement.setString(1, list.getName());
+ preparedStatement.executeUpdate();
+ }
+ else
+ {
+ query = "INSERT INTO LIST (parent_list_id, name) values (?, ?)";
+ preparedStatement = connection.prepareStatement(query, PreparedStatement.RETURN_GENERATED_KEYS);
+ preparedStatement.setInt(1, list.getParentListId());
+ preparedStatement.setString(2, list.getName());
+ preparedStatement.executeUpdate();
+ }
+
+ // Get ID from inserted client
+ ResultSet rs = preparedStatement.getGeneratedKeys();
+ if (rs.next())
+ {
+ // Id
+ int id = rs.getInt(1);
+
+ // Add client id to object
+ list.setId(id);
+
+ // Return object
+ return list;
+ }
+ }
+ catch (SQLException ex)
+ {
+ String sqlState = ex.getSQLState();
+
+ System.err.println(ex.getMessage());
+
+ // Duplicate Name
+ // Error Docu: https://db.apache.org/derby/docs/10.1/ref/rrefexcept71493.html
+ if (sqlState.equals("23505"))
+ {
+ System.err.println("List name already exist.\nPlease choose another." + ex.getMessage());
+ }
+ else
+ {
+ System.err.println("Unable to execute query.\n" + ex.getMessage());
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public Item insertItem(Item item)
+ {
+ try
+ {
+ String query = "INSERT INTO ITEM (list_id, name, json_content) values (?, ?, ?)";
+ preparedStatement = connection.prepareStatement(query, PreparedStatement.RETURN_GENERATED_KEYS);
+ preparedStatement.setInt(1, item.getListId());
+ preparedStatement.setString(2, item.getName());
+ preparedStatement.setString(3, item.getJsonContent());
+ preparedStatement.executeUpdate();
+
+ // Get ID from inserted client
+ ResultSet rs = preparedStatement.getGeneratedKeys();
+ if (rs.next())
+ {
+ // Id
+ int id = rs.getInt(1);
+
+ // Add client id to object
+ item.setId(id);
+
+ // Return object
+ return item;
+ }
+ }
+ catch (SQLException ex)
+ {
+ String sqlState = ex.getSQLState();
+
+ // Duplicate Name
+ // Error Docu: https://db.apache.org/derby/docs/10.1/ref/rrefexcept71493.html
+ if (sqlState.equals("23505"))
+ {
+ System.err.println("Item name already exist.\nPlease choose another." + ex.getMessage());
+ }
+ else
+ {
+ System.err.println("Unable to execute query.\n" + ex.getMessage());
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Setup Database Tables for ItemList
+ */
+ private void setupTables()
+ {
+ setupListTable();
+ setupItemTable();
+ }
+
+
+ /*
+ Setup the ItemList Table
+ */
+ private void setupListTable()
+ {
+ String tableName = "LIST";
+ String query = "CREATE TABLE " + tableName + "("
+ + "id INTEGER NOT NULL,\n"
+ + "parent_list_id INTEGER,\n"
+ + "name VARCHAR(200) NOT NULL UNIQUE,\n"
+ + "dateCreated DATE default CURRENT_DATE,\n"
+ + "PRIMARY KEY(id), \n"
+ + "FOREIGN KEY(parent_list_id) REFERENCES list(id)"
+ + ")";
+
+ // Create table if it does not already exist
+ createTable(tableName, query);
+ }
+
+ /*
+ Setup the Item Table
+ */
+ private void setupItemTable()
+ {
+ String tableName = "ITEM";
+ String query = "CREATE TABLE " + tableName + "("
+ + "id INTEGER NOT NULL,\n"
+ + "list_id INTEGER,\n"
+ + "name VARCHAR(200) NOT NULL,\n"
+ + "json_content VARCHAR(4096),\n"
+ + "dateCreated DATE default CURRENT_DATE,\n"
+ + "PRIMARY KEY(id),\n"
+ + "FOREIGN KEY(list_id) REFERENCES list(id)"
+ + ")";
+
+ // Create table if it does not already exist
+ createTable(tableName, query);
+ }
+
+ /**
+ * Creates a table given a table name and full query
+ *
+ * @param tableName
+ * @param query
+ * @return
+ */
+ public boolean createTable(String tableName, String query)
+ {
+ try
+ {
+ statement = connection.createStatement();
+ DatabaseMetaData databaseMetaData = connection.getMetaData();
+ ResultSet tables = databaseMetaData.getTables(null, null, tableName.toUpperCase(), null);
+
+ // If table does NOT already, create the table
+ if (!tables.next())
+ {
+ statement.execute(query);
+ return true;
+ }
+ }
+ catch (SQLException ex)
+ {
+ System.err.println("Unable to create table.\n" + ex.getMessage());
+ }
+ return false;
+ }
+
+ @Override
+ public boolean removeItem(int id)
+ {
+ try
+ {
+ String query = "DELETE FROM ITEM WHERE id=" + id;
+ preparedStatement = connection.prepareStatement(query, PreparedStatement.RETURN_GENERATED_KEYS);
+ if (preparedStatement.executeUpdate() > 0)
+ {
+ return true;
+ }
+ }
+ catch (SQLException ex)
+ {
+ String sqlState = ex.getSQLState();
+
+ // Duplicate Name
+ // Error Docu: https://db.apache.org/derby/docs/10.1/ref/rrefexcept71493.html
+ if (sqlState.equals("23505"))
+ {
+ System.err.println("Item name already exist.\nPlease choose another." + ex.getMessage());
+ }
+ else
+ {
+ System.err.println("Unable to execute query.\n" + ex.getMessage());
+ }
+
+ return false;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean removeList(int id)
+ {
+ try
+ {
+ String query = "DELETE FROM LIST WHERE id=" + id;
+ preparedStatement = connection.prepareStatement(query, PreparedStatement.RETURN_GENERATED_KEYS);
+ if (preparedStatement.executeUpdate() > 0)
+ {
+ return true;
+ }
+ }
+ catch (SQLException ex)
+ {
+ String sqlState = ex.getSQLState();
+
+ // Duplicate Name
+ // Error Docu: https://db.apache.org/derby/docs/10.1/ref/rrefexcept71493.html
+ if (sqlState.equals("23505"))
+ {
+ System.err.println("Item name already exist.\nPlease choose another." + ex.getMessage());
+ }
+ else
+ {
+ System.err.println("Unable to execute query.\n" + ex.getMessage());
+ }
+
+ return false;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean removeListsWithParentId(int id)
+ {
+ try
+ {
+ String query = "DELETE FROM LIST WHERE parent_list_id=" + id;
+ preparedStatement = connection.prepareStatement(query, PreparedStatement.RETURN_GENERATED_KEYS);
+ if (preparedStatement.executeUpdate() > 0)
+ {
+ return true;
+ }
+ }
+ catch (SQLException ex)
+ {
+ String sqlState = ex.getSQLState();
+
+ // Duplicate Name
+ // Error Docu: https://db.apache.org/derby/docs/10.1/ref/rrefexcept71493.html
+ if (sqlState.equals("23505"))
+ {
+ System.err.println("Item name already exist.\nPlease choose another." + ex.getMessage());
+ }
+ else
+ {
+ System.err.println("Unable to execute query.\n" + ex.getMessage());
+ }
+
+ return false;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean removeItemsWithListId(int id)
+ {
+ try
+ {
+ String query = "DELETE FROM ITEM WHERE list_id=" + id;
+ preparedStatement = connection.prepareStatement(query, PreparedStatement.RETURN_GENERATED_KEYS);
+ if (preparedStatement.executeUpdate() > 0)
+ {
+ return true;
+ }
+ }
+ catch (SQLException ex)
+ {
+ String sqlState = ex.getSQLState();
+
+ // Duplicate Name
+ // Error Docu: https://db.apache.org/derby/docs/10.1/ref/rrefexcept71493.html
+ if (sqlState.equals("23505"))
+ {
+ System.err.println("Item name already exist.\nPlease choose another." + ex.getMessage());
+ }
+ else
+ {
+ System.err.println("Unable to execute query.\n" + ex.getMessage());
+ }
+
+ return false;
+ }
+ return false;
+ }
+}
diff --git a/src/rpbot/derbydatabase/Database.java b/src/rpbot/derbydatabase/Database.java
new file mode 100644
index 0000000..5c2b0a6
--- /dev/null
+++ b/src/rpbot/derbydatabase/Database.java
@@ -0,0 +1,43 @@
+package rpbot.derbydatabase;
+
+import java.sql.ResultSet;
+import rpbot.sheetdata.Item;
+import rpbot.sheetdata.SheetData;
+import sx.blah.discord.handle.obj.IUser;
+
+/**
+ *
+ * @author ivanskodje
+ */
+public interface Database
+{
+
+ /* Establishes connection with server */
+ public void connect();
+
+ /* Executes a query, returns the resultset */
+ public ResultSet executeQuery(String query);
+
+ /* Executes a query action, returns a boolean to determine success or failure */
+ public boolean executeAction(String query);
+
+ /* Insert an user to the database */
+ // public void insertCategory(int userId, String category);
+ /**
+ * Insert an item into the database
+ */
+ public boolean insertItem(Item item);
+
+ /**
+ * Updates an existing item (key) in the database
+ */
+ public boolean updateItem(Item item);
+
+ /**
+ * Deletes an item from the database *
+ */
+ public boolean deleteItem(Item item);
+
+ /* Sets the need for user authorization upon connecting to the database */
+ public void setAuthorization(Boolean enable);
+}
diff --git a/src/rpbot/derbydatabase/DatabaseHandler.java b/src/rpbot/derbydatabase/DatabaseHandler.java
new file mode 100644
index 0000000..8a2a004
--- /dev/null
+++ b/src/rpbot/derbydatabase/DatabaseHandler.java
@@ -0,0 +1,164 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package rpbot.derbydatabase;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collections;
+import rpbot.sheetdata.Item;
+import sx.blah.discord.handle.obj.IUser;
+
+/**
+ *
+ * @author Ivan Skodje
+ */
+public class DatabaseHandler
+{
+
+ // Database
+ private static Database database;
+
+ // All Items
+ private static ArrayList
- items = new ArrayList<>();
+
+ /**
+ * Initiate and connects with given database
+ *
+ * @param db
+ */
+ public static void init(Database db)
+ {
+ // Setup connection
+ database = db;
+ database.connect();
+
+ // Populate data
+ populateData();
+ }
+
+ /* Loads and populates all clients + projects + tasks */
+ private static void populateData()
+ {
+ loadItems();
+ }
+
+ /**
+ * Loads clients to Memory in DatabaseHandler
+ */
+ private static void loadItems()
+ {
+ System.out.println("POPULATED ITEM?");
+ String QUERY = "SELECT * FROM ITEMS";
+ ResultSet resultSet = database.executeQuery(QUERY);
+
+ try
+ {
+ // Iterate through all clients
+ while (resultSet.next())
+ {
+ Item newItem = new Item();
+ newItem.setUserId(resultSet.getString("userId"));
+ newItem.setKey(resultSet.getString("keyValue"));
+ newItem.setValue(resultSet.getString("value"));
+ items.add(newItem);
+
+
+
+ Collections.sort(items, (o1, o2) -> o1.getKey().compareTo(o2.getKey()));
+ }
+ }
+ catch (SQLException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+
+
+ public static void addItem(Item item)
+ {
+ // Before adding, check if the USER already have an item with that name
+ for(Item i : items)
+ {
+ if(i.getUserId().equals(item.getUserId()))
+ {
+ if(i.getKey().equals(item.getKey()))
+ {
+ System.out.println("item already exist!");
+ if(database.updateItem(item))
+ {
+ items.remove(i);
+ items.add(item);
+ }
+ return;
+ }
+ }
+ }
+
+
+ System.out.println("ADDING ITEM!");
+ if(database.insertItem(item))
+ {
+ items.add(item);
+ }
+ }
+
+
+ public static Item getItem(IUser user, String keyValue)
+ {
+ System.out.println("There are a total of " + items.size() + " items");
+
+ for(Item item : items)
+ {
+ System.out.println("You: " + user.getID() + "\nChecking ID: " + item.getUserId());
+ if(item.getUserId().equals(user.getID()))
+ {
+ if(item.getKey().equals(keyValue))
+ {
+ return item;
+ }
+ }
+
+ }
+ return null;
+ }
+
+
+ public static ArrayList
- getItems(IUser user)
+ {
+ ArrayList
- temp = new ArrayList<>();
+ for(Item item : items)
+ {
+ if(item.getUserId().equals(user.getID()))
+ {
+ temp.add(item);
+ }
+ }
+
+ return temp;
+ }
+
+
+ public static boolean deleteItem(IUser user, String keyValue)
+ {
+ for(Item item : items)
+ {
+ if(item.getUserId().equals(user.getID()))
+ {
+ if(item.getKey().equals(keyValue))
+ {
+ if(database.deleteItem(item))
+ {
+ items.remove(item);
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/src/rpbot/derbydatabase/DerbyDatabase.java b/src/rpbot/derbydatabase/DerbyDatabase.java
new file mode 100644
index 0000000..7ee8e86
--- /dev/null
+++ b/src/rpbot/derbydatabase/DerbyDatabase.java
@@ -0,0 +1,257 @@
+package rpbot.derbydatabase;
+
+import java.sql.Date;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import rpbot.sheetdata.Item;
+import rpbot.sheetdata.SheetData;
+
+/**
+ *
+ * @author ivanskodje
+ */
+public class DerbyDatabase implements Database
+{
+
+ // private static final String DB_URL = "jdbc:derby:database;create=true";
+ // private static final String DB_URL = "jdbc:derby:/home/ivanskodje/.netbeans-derby/TimeHoursDB;create=true;user=derby;password=derby";
+ // Derby Vars
+ private static String database_url;
+ private static Connection connection = null;
+ private static Statement statement = null;
+ private static PreparedStatement preparedStatement = null;
+
+ private String username = null;
+ private String password = null;
+ private String repository = null;
+
+ /*
+ In order to work a Derby database, we need a repository, user and password.
+ */
+ public DerbyDatabase(String repository, String username, String password)
+ {
+ // Put database url together
+ database_url = "jdbc:derby:" + repository + ";create=true;user=" + username + ";password=" + password;
+
+ // Store username and password
+ // TODO: Check if we should and how to store strings securely
+ this.repository = repository;
+ this.username = username;
+ this.password = password;
+ }
+
+ /*
+ Establishes connection with Derby DB
+ */
+ @Override
+ public void connect()
+ {
+ try
+ {
+ // Instance driver and setup connection
+ Class.forName("org.apache.derby.jdbc.EmbeddedDriver").newInstance();
+ connection = DriverManager.getConnection(database_url, username, password);
+
+ // TODO: Allow user on Repo creation to decide whether or not a password will be used
+ // Enable user authorization
+ // setAuthorization(true)
+ // Disable user authorization
+ setAuthorization(false);
+
+ // Setup database tables (if they dont exist)
+ setupTables();
+ }
+ catch (ClassNotFoundException | IllegalAccessException | InstantiationException | SQLException ex)
+ {
+ System.err.print("Unable to setup connection with database.\n" + ex.getMessage());
+ }
+ }
+
+ /*
+ Setup database tables
+ */
+ private void setupTables()
+ {
+ setupItems();
+ }
+
+ /*
+ Setup the Sheet Table
+ */
+ private void setupItems()
+ {
+ String TABLE_NAME = "ITEMS";
+ String QUERY = "CREATE TABLE " + TABLE_NAME + "("
+ + "id INTEGER PRIMARY KEY NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1),\n"
+ + "userId VARCHAR(4096) NOT NULL,\n"
+ + "keyValue VARCHAR(4096) NOT NULL,\n"
+ + "value VARCHAR(4096),\n"
+ + "dateCreated DATE default CURRENT_DATE"
+ + ")";
+ try
+ {
+ statement = connection.createStatement();
+ DatabaseMetaData databaseMetaData = connection.getMetaData();
+ ResultSet tables = databaseMetaData.getTables(null, null, TABLE_NAME.toUpperCase(), null);
+
+ // If table does not exist, create it
+ if (!tables.next())
+ {
+ statement.execute(QUERY);
+ }
+ }
+ catch (SQLException ex)
+ {
+ System.err.print("Unable to setup the item table.\n" + ex.getMessage());
+ }
+ }
+
+ /*
+ Execute Query and return a ResultSet
+ */
+ @Override
+ public ResultSet executeQuery(String query)
+ {
+ ResultSet resultSet = null;
+
+ try
+ {
+ statement = connection.createStatement();
+ resultSet = statement.executeQuery(query);
+ }
+ catch (SQLException ex)
+ {
+ System.err.println("Unable to execute query.\n" + ex.getMessage());
+ }
+
+ return resultSet;
+ }
+
+ /*
+ Execute an action and return a boolean result
+ */
+ @Override
+ public boolean executeAction(String query)
+ {
+ try
+ {
+ statement = connection.createStatement();
+ statement.execute(query);
+ return true;
+ }
+ catch (SQLException ex)
+ {
+ System.err.println("Unable to execute query.\n" + ex.getMessage());
+ return false;
+ }
+ }
+
+
+ /*
+ Shared method for enabling or disabling user authorization for the database
+ */
+ @Override
+ public void setAuthorization(Boolean is_enabled)
+ {
+ try
+ {
+ // Create statement
+ statement = connection.createStatement();
+
+ // True: Enable, False: Disable - requireAuthentication
+ statement.executeUpdate("CALL SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY('derby.connection.requireAuthentication', '" + is_enabled + "')");
+
+ // True: Add, False: Remove - password requirements for user
+ String use_pass = is_enabled ? "'" + password + "'" : "null";
+ statement.executeUpdate("CALL SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY('derby.user." + username + "', " + use_pass + ")");
+
+ }
+ catch (SQLException ex)
+ {
+ System.err.println("DatabaseHandler.java -> setAuthorization(" + is_enabled + ") \n" + ex.getMessage());
+ }
+ }
+
+ @Override
+ public boolean insertItem(Item item)
+ {
+ try
+ {
+ String query = "INSERT INTO ITEMS (userId, keyValue, value) values (?, ?, ?)";
+ preparedStatement = connection.prepareStatement(query, PreparedStatement.RETURN_GENERATED_KEYS);
+ preparedStatement.setString(1, item.getUserId());
+ preparedStatement.setString(2, item.getKey());
+ preparedStatement.setString(3, item.getValue());
+ preparedStatement.executeUpdate();
+
+ System.out.println("SUCCESSFULLY INSERTED ITEM INTO DB!");
+ return true;
+ }
+ catch (SQLException ex)
+ {
+ String sqlState = ex.getSQLState();
+
+ // Duplicate Name
+ // Error Docu: https://db.apache.org/derby/docs/10.1/ref/rrefexcept71493.html
+ if (sqlState.equals("23505"))
+ {
+ System.err.println( "Item already exist.");
+ }
+ else
+ {
+ System.err.println("Unable to execute query.\n" + ex.getMessage());
+ }
+ }
+
+ return false;
+ }
+
+
+ @Override
+ public boolean updateItem(Item item)
+ {
+ if(deleteItem(item))
+ {
+ return insertItem(item);
+ }
+
+ return false;
+ }
+
+
+ @Override
+ public boolean deleteItem(Item item)
+ {
+ try
+ {
+ String query = "DELETE FROM ITEMS WHERE userId = ? AND keyValue = ?";
+ preparedStatement = connection.prepareStatement(query, PreparedStatement.RETURN_GENERATED_KEYS);
+ preparedStatement.setString(1, item.getUserId());
+ preparedStatement.setString(2, item.getKey());
+ preparedStatement.executeUpdate();
+ return true;
+ }
+ catch (SQLException ex)
+ {
+ String sqlState = ex.getSQLState();
+
+ // Duplicate Name
+ // Error Docu: https://db.apache.org/derby/docs/10.1/ref/rrefexcept71493.html
+ if (sqlState.equals("23505"))
+ {
+ System.err.println( "Item already exist.");
+ }
+ else
+ {
+ System.err.println("Unable to execute DELETE query.\n" + ex.getMessage());
+ }
+
+ }
+ return false;
+ }
+}
diff --git a/src/rpbot/sheetdata/Item.java b/src/rpbot/sheetdata/Item.java
new file mode 100644
index 0000000..3ceba0c
--- /dev/null
+++ b/src/rpbot/sheetdata/Item.java
@@ -0,0 +1,107 @@
+package rpbot.sheetdata;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+/**
+ *
+ * @author Ivan Skodje
+ */
+public class Item
+{
+ String userId;
+ String key;
+ String value;
+
+
+ public Item()
+ {
+
+ }
+
+ public Item(String userId, String name, String value)
+ {
+ this.userId = userId;
+ this.key = name;
+ this.value = value;
+ }
+
+ public Item(String jsonString)
+ {
+ JsonElement jsonElement = new JsonParser().parse(jsonString);
+ JsonObject jsonObject = jsonElement.getAsJsonObject();
+
+ // Populate data
+ // Category ID
+ JsonElement categoryIdElement = jsonObject.get("userId");
+ if(!categoryIdElement.isJsonNull())
+ {
+ this.userId = categoryIdElement.getAsString();
+ }
+
+ // Name
+ JsonElement nameElement = jsonObject.get("name");
+ if(!nameElement.isJsonNull())
+ {
+ this.key = nameElement.getAsString();
+ }
+
+ // Value
+ JsonElement valueElement = jsonObject.get("value");
+ if(!valueElement.isJsonNull())
+ {
+ this.value = valueElement.getAsString();
+ }
+ }
+
+ public String getUserId()
+ {
+ return userId;
+ }
+
+ public void setUserId(String userId)
+ {
+ this.userId = userId;
+ }
+
+ public String getKey()
+ {
+ return key;
+ }
+
+ public void setKey(String key)
+ {
+ this.key = key;
+ }
+
+ public String getValue()
+ {
+ return value;
+ }
+
+ public void setValue(String value)
+ {
+ this.value = value;
+ }
+
+
+
+
+
+ public String toJson()
+ {
+ try
+ {
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty("categoryId", userId);
+ jsonObject.addProperty("name", key);
+ jsonObject.addProperty("value", value);
+ return jsonObject.toString();
+ }
+ catch(Exception ex)
+ {
+ return "EXCEPTION: " + ex.getMessage();
+ }
+ }
+}
diff --git a/src/rpbot/sheetdata/SheetData.java b/src/rpbot/sheetdata/SheetData.java
new file mode 100644
index 0000000..01e73f2
--- /dev/null
+++ b/src/rpbot/sheetdata/SheetData.java
@@ -0,0 +1,64 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package rpbot.sheetdata;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import java.util.ArrayList;
+
+/**
+ *
+ * @author Ivan Skodje
+ */
+public class SheetData
+{
+ /* Unique User ID */
+ private int id;
+
+ /* User data stored as json */
+ private ArrayList
- items;
+
+
+ /**
+ * Constructor
+ * @param userId
+ */
+ public SheetData(int userId)
+ {
+ this.id = userId;
+ }
+
+ /**
+ * Add new item
+ * @param newItem
+ */
+ public void addItem(Item newItem)
+ {
+ items.add(newItem);
+ }
+
+ /**
+ * Returns an array of items
+ * @return
+ */
+ public ArrayList
- getItems()
+ {
+ return items;
+ }
+
+ public String toJson()
+ {
+ try
+ {
+ return "";
+ }
+ catch(Exception ex)
+ {
+ return "EXCEPTION: " + ex.getMessage();
+ }
+ }
+}
diff --git a/token.txt b/token.txt
new file mode 100644
index 0000000..0b95b57
--- /dev/null
+++ b/token.txt
@@ -0,0 +1 @@
+Mjg2Mjg5OTUyMzkwNTEyNjQx.C5nyfw.UwotLMPT6HwireQUw9kgKYKbx0s
\ No newline at end of file