listeners = new ArrayList<>();
+
+ public interface Listener {
+ void onDateChanged();
+ }
+
+ public static Settings getInstance() {
+ return INSTANCE;
+ }
+
+ private Settings() {
+ props = new Properties();
+ }
+
+ public void addListener(Listener l) {
+ listeners.add(l);
+ }
+
+ public void removeListener(Listener l) {
+ listeners.remove(l);
+ }
+
+ public void setDate(String date) {
+ props.setProperty("Date", date);
+ listeners.forEach(Listener::onDateChanged);
+ }
+
+ public LocalDate getDate() {
+ return Utils.getLocalDate(props.getProperty("Date"));
+ }
+
+ public String getJposXmlPath() {
+ return props.getProperty("jposPath");
+ }
+
+ public Path getSheetPath() {
+ return Paths.get(props.getProperty("worksheet"));
+ }
+
+ public boolean getFun() {
+ return Boolean.getBoolean(props.getProperty("fun"));
+ }
+
+ public LoginType getLoginType(){
+ return LoginType.valueOf(props.getProperty("loginType"));
+ }
+
+ public String getAttendanceSheet() {
+ return props.getProperty("attendanceSheet");
+ }
+
+ public String getRosterSheet() {
+ return props.getProperty("rosterSheet");
+ }
+
+ public int getRosterHeaderRow() {
+ return Integer.parseInt(props.getProperty("roster.headerRow"));
+ }
+
+ public int getRosterFirstDataRow() {
+ return Integer.parseInt(props.getProperty("roster.firstRow"));
+ }
+
+ public int getAttendanceHeaderRow() {
+ return Integer.parseInt(props.getProperty("attendance.headerRow"));
+ }
+
+ public int getAttendanceFirstDataRow() {
+ return Integer.parseInt(props.getProperty("attendance.firstRow"));
+ }
+
+ public String getMentorAttendanceSheet() {
+ return props.getProperty("mentorSheet");
+ }
+
+ public String getMentorRosterSheet() {
+ return props.getProperty("mentorRSheet");
+ }
+
+ public int getMentorRosterHeaderRow() {
+ return Integer.parseInt(props.getProperty("mentorRos.headerRow"));
+ }
+
+ public int getMentorRosterFirstDataRow() {
+ return Integer.parseInt(props.getProperty("mentorRos.firstRow"));
+ }
+
+ public int getMentorAttendanceHeaderRow() {
+ return Integer.parseInt(props.getProperty("mentorAtt.headerRow"));
+ }
+
+ public int getMentorAttendanceFirstDataRow() {
+ return Integer.parseInt(props.getProperty("mentorAtt.firstRow"));
+ }
+
+ public void init(String prefsFile) throws RobotechException {
+ final DateTimeFormatter fmt = DateTimeFormatter.ofPattern("M/d");
+
+ props.setProperty("Date", LocalDate.now().format(fmt));
+ props.setProperty("Fun", "true");
+
+ final File file = new File(prefsFile);
+
+ if(file.isDirectory()) {
+ throw new RobotechException("File must not be a directory");
+ }
+
+ logger.info("Looking for prefs file at: " + file.getAbsolutePath());
+ if (!file.exists()) {
+ logger.error("Prefs file does not exist");
+ throw new RobotechException("Preference file does not exist");
+ }
+
+ try(final FileInputStream fis = new FileInputStream(file)) {
+ props.load(fis);
+ } catch (IOException e) {
+ throw new RobotechException("Unable to load preferences.", e);
+ }
+ }
+
+ public static boolean isNullOrEmpty(String value) {
+ return value == null || value.isEmpty();
+ }
+
+ public int getAttendanceFirstDataColumn() {
+ return Integer.parseInt(props.getProperty("attendance.firstColumn"));
+ }
+}
diff --git a/src/main/java/com/team871/util/ThrowingRunnable.java b/src/main/java/com/team871/util/ThrowingRunnable.java
new file mode 100644
index 0000000..444bede
--- /dev/null
+++ b/src/main/java/com/team871/util/ThrowingRunnable.java
@@ -0,0 +1,6 @@
+package com.team871.util;
+
+@FunctionalInterface
+public interface ThrowingRunnable {
+ void run(P param) throws E;
+}
diff --git a/src/main/java/com/team871/util/Utils.java b/src/main/java/com/team871/util/Utils.java
new file mode 100644
index 0000000..2f9e9b9
--- /dev/null
+++ b/src/main/java/com/team871/util/Utils.java
@@ -0,0 +1,25 @@
+package com.team871.util;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+
+public class Utils {
+ public static final String FIRST_NAME_COL = "First";
+ public static final String LAST_NAME_COL = "Last";
+ public static final String ID_COL = "ID";
+ public static final String TOTAL_COL = "Total";
+ public static final String SAFETY_COL = "Safety";
+ public static final String FIRST_REG_COL = "First Reg.";
+
+ public static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss");
+ public static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("M/d");
+
+ public static boolean isNullOrEmpty(String val) {
+ return val == null || val.isEmpty();
+ }
+
+ public static LocalDate getLocalDate(String date) {
+ final String[] dateParts = date.split("/");
+ return LocalDate.of(LocalDate.now().getYear(), Integer.parseInt(dateParts[0]), Integer.parseInt(dateParts[1]));
+ }
+}
diff --git a/src/main/resources/README.txt b/src/main/resources/README.txt
new file mode 100644
index 0000000..dd8bbf9
--- /dev/null
+++ b/src/main/resources/README.txt
@@ -0,0 +1,10 @@
+A copy of jpos.xml must be located in the user.home directory
+
+jpos/res/jpos.properties needs to stay where it is because of the way the JPOS library works.
+
+The .scncfg files are scanner configurations for 123Scan.
+
+scan.pxt is the source for the scan sound.
+ edit with SeaTone(https://www.cavestory.org/downloads/tone_pusher_rev1.zip) or the original PixTone
+scan.wav is the exported audio of scan.pxt.
+scan_compress.wav is scan.wav in the correct format for 123Scan.
\ No newline at end of file
diff --git a/src/main/resources/audio/dance0.wav b/src/main/resources/audio/dance0.wav
new file mode 100644
index 0000000..597ce49
Binary files /dev/null and b/src/main/resources/audio/dance0.wav differ
diff --git a/src/main/resources/audio/dance1.wav b/src/main/resources/audio/dance1.wav
new file mode 100644
index 0000000..9354c80
Binary files /dev/null and b/src/main/resources/audio/dance1.wav differ
diff --git a/src/main/resources/audio/dance2.wav b/src/main/resources/audio/dance2.wav
new file mode 100644
index 0000000..0665af3
Binary files /dev/null and b/src/main/resources/audio/dance2.wav differ
diff --git a/src/main/resources/audio/scan.wav b/src/main/resources/audio/scan.wav
new file mode 100644
index 0000000..64ba180
Binary files /dev/null and b/src/main/resources/audio/scan.wav differ
diff --git a/src/main/resources/audio/scan_compress.wav b/src/main/resources/audio/scan_compress.wav
new file mode 100644
index 0000000..dadfb55
Binary files /dev/null and b/src/main/resources/audio/scan_compress.wav differ
diff --git a/src/main/resources/audio/test.wav b/src/main/resources/audio/test.wav
new file mode 100644
index 0000000..ab8191f
Binary files /dev/null and b/src/main/resources/audio/test.wav differ
diff --git a/src/main/resources/audio/tim.wav b/src/main/resources/audio/tim.wav
new file mode 100644
index 0000000..af9579f
Binary files /dev/null and b/src/main/resources/audio/tim.wav differ
diff --git a/src/main/resources/audio/tim2.wav b/src/main/resources/audio/tim2.wav
new file mode 100644
index 0000000..ada63c7
Binary files /dev/null and b/src/main/resources/audio/tim2.wav differ
diff --git a/src/main/resources/config/Config File_DS9908_Config.scncfg b/src/main/resources/config/Config File_DS9908_Config.scncfg
new file mode 100644
index 0000000..1874948
Binary files /dev/null and b/src/main/resources/config/Config File_DS9908_Config.scncfg differ
diff --git a/src/main/resources/config/Config File_DS9908_Config_KEYBOARD.scncfg b/src/main/resources/config/Config File_DS9908_Config_KEYBOARD.scncfg
new file mode 100644
index 0000000..a69df99
Binary files /dev/null and b/src/main/resources/config/Config File_DS9908_Config_KEYBOARD.scncfg differ
diff --git a/src/main/resources/config/Config File_DS9908_Config_OPOS.scncfg b/src/main/resources/config/Config File_DS9908_Config_OPOS.scncfg
new file mode 100644
index 0000000..4f95951
Binary files /dev/null and b/src/main/resources/config/Config File_DS9908_Config_OPOS.scncfg differ
diff --git a/src/main/resources/config/jpos.xml b/src/main/resources/config/jpos.xml
new file mode 100644
index 0000000..66a97d0
--- /dev/null
+++ b/src/main/resources/config/jpos.xml
@@ -0,0 +1,134 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/config/scan.pxt b/src/main/resources/config/scan.pxt
new file mode 100644
index 0000000..9bf0f83
--- /dev/null
+++ b/src/main/resources/config/scan.pxt
@@ -0,0 +1,124 @@
+use :1
+size :2000
+main_model :4
+main_freq :40.00
+main_top :32
+main_offset :0
+pitch_model :4
+pitch_freq :1.00
+pitch_top :31
+pitch_offset :128
+volume_model :0
+volume_freq :0.00
+volume_top :32
+volume_offset:0
+initialY:63
+ax :64
+ay :63
+bx :128
+by :63
+cx :255
+cy :63
+
+use :0
+size :22050
+main_model :0
+main_freq :440.00
+main_top :32
+main_offset :0
+pitch_model :0
+pitch_freq :0.00
+pitch_top :32
+pitch_offset :0
+volume_model :0
+volume_freq :0.00
+volume_top :32
+volume_offset:0
+initialY:63
+ax :64
+ay :63
+bx :128
+by :63
+cx :255
+cy :63
+
+use :0
+size :22050
+main_model :0
+main_freq :440.00
+main_top :32
+main_offset :0
+pitch_model :0
+pitch_freq :0.00
+pitch_top :32
+pitch_offset :0
+volume_model :0
+volume_freq :0.00
+volume_top :32
+volume_offset:0
+initialY:63
+ax :64
+ay :63
+bx :128
+by :63
+cx :255
+cy :63
+
+use :0
+size :22050
+main_model :0
+main_freq :440.00
+main_top :32
+main_offset :0
+pitch_model :0
+pitch_freq :0.00
+pitch_top :32
+pitch_offset :0
+volume_model :0
+volume_freq :0.00
+volume_top :32
+volume_offset:0
+initialY:63
+ax :64
+ay :63
+bx :128
+by :63
+cx :255
+cy :63
+
+{1,2000,4,40.00,32,0,4,1.00,31,128,0,0.00,32,0,63,64,63,128,63,255,63},
+{0,22050,0,440.00,32,0,0,0.00,32,0,0,0.00,32,0,63,64,63,128,63,255,63},
+{0,22050,0,440.00,32,0,0,0.00,32,0,0,0.00,32,0,63,64,63,128,63,255,63},
+{0,22050,0,440.00,32,0,0,0.00,32,0,0,0.00,32,0,63,64,63,128,63,255,63},
+
+-> {0,0.00,0,0,0,0.00,32,0,0,0.00,32,0,0,0.00,32,0},
+-> {255,0,255,0,255,0,255,0},
+
+pitch2_model :4
+pitch2_freq :1.00
+pitch2_top :31
+pitch2_offset:128
+dx :255
+dy :0
+
+pitch2_model :0
+pitch2_freq :0.00
+pitch2_top :32
+pitch2_offset:0
+dx :255
+dy :0
+
+pitch2_model :0
+pitch2_freq :0.00
+pitch2_top :32
+pitch2_offset:0
+dx :255
+dy :0
+
+pitch2_model :0
+pitch2_freq :0.00
+pitch2_top :32
+pitch2_offset:0
+dx :255
+dy :0
+
diff --git a/src/main/resources/config/test.pxt b/src/main/resources/config/test.pxt
new file mode 100644
index 0000000..9080802
--- /dev/null
+++ b/src/main/resources/config/test.pxt
@@ -0,0 +1,124 @@
+use :1
+size :4000
+main_model :0
+main_freq :110.00
+main_top :32
+main_offset :0
+pitch_model :4
+pitch_freq :1.00
+pitch_top :12
+pitch_offset :0
+volume_model :0
+volume_freq :0.00
+volume_top :32
+volume_offset:0
+initialY:63
+ax :64
+ay :63
+bx :128
+by :63
+cx :255
+cy :63
+
+use :0
+size :22050
+main_model :0
+main_freq :440.00
+main_top :32
+main_offset :0
+pitch_model :0
+pitch_freq :0.00
+pitch_top :32
+pitch_offset :0
+volume_model :0
+volume_freq :0.00
+volume_top :32
+volume_offset:0
+initialY:63
+ax :64
+ay :63
+bx :128
+by :63
+cx :255
+cy :63
+
+use :0
+size :22050
+main_model :0
+main_freq :440.00
+main_top :32
+main_offset :0
+pitch_model :0
+pitch_freq :0.00
+pitch_top :32
+pitch_offset :0
+volume_model :0
+volume_freq :0.00
+volume_top :32
+volume_offset:0
+initialY:63
+ax :64
+ay :63
+bx :128
+by :63
+cx :255
+cy :63
+
+use :0
+size :22050
+main_model :0
+main_freq :440.00
+main_top :32
+main_offset :0
+pitch_model :0
+pitch_freq :0.00
+pitch_top :32
+pitch_offset :0
+volume_model :0
+volume_freq :0.00
+volume_top :32
+volume_offset:0
+initialY:63
+ax :64
+ay :63
+bx :128
+by :63
+cx :255
+cy :63
+
+{1,4000,0,110.00,32,0,4,1.00,12,0,0,0.00,32,0,63,64,63,128,63,255,63},
+{0,22050,0,440.00,32,0,0,0.00,32,0,0,0.00,32,0,63,64,63,128,63,255,63},
+{0,22050,0,440.00,32,0,0,0.00,32,0,0,0.00,32,0,63,64,63,128,63,255,63},
+{0,22050,0,440.00,32,0,0,0.00,32,0,0,0.00,32,0,63,64,63,128,63,255,63},
+
+-> {0,0.00,32,0,0,0.00,32,0,0,0.00,32,0,0,0.00,32,0},
+-> {255,0,255,0,255,0,255,0},
+
+pitch2_model :4
+pitch2_freq :1.00
+pitch2_top :12
+pitch2_offset:0
+dx :255
+dy :0
+
+pitch2_model :0
+pitch2_freq :0.00
+pitch2_top :32
+pitch2_offset:0
+dx :255
+dy :0
+
+pitch2_model :0
+pitch2_freq :0.00
+pitch2_top :32
+pitch2_offset:0
+dx :255
+dy :0
+
+pitch2_model :0
+pitch2_freq :0.00
+pitch2_top :32
+pitch2_offset:0
+dx :255
+dy :0
+
diff --git a/src/main/resources/img/cool image.png b/src/main/resources/img/cool image.png
new file mode 100644
index 0000000..f251e0a
Binary files /dev/null and b/src/main/resources/img/cool image.png differ
diff --git a/src/main/resources/img/tim.jpg b/src/main/resources/img/tim.jpg
new file mode 100644
index 0000000..b87fd5f
Binary files /dev/null and b/src/main/resources/img/tim.jpg differ
diff --git a/src/main/resources/jpos/res/jpos.properties b/src/main/resources/jpos/res/jpos.properties
new file mode 100644
index 0000000..a2ce2ac
--- /dev/null
+++ b/src/main/resources/jpos/res/jpos.properties
@@ -0,0 +1,95 @@
+#------------------------------------------------------------------------------
+# JposTestCase.createPropFile() --> ./jpos/res/jpos.properties file
+# Thu Jul 05 11:37:25 EDT 2001
+#------------------------------------------------------------------------------
+
+#------------------------------------------------------------------------------
+# Required properties
+# -------------------
+# 1) jpos.loader.serviceManagerClass
+#
+# This property specifies the manager bootstrap class for the whole JCL. Use
+# this property to replace the default "simple" JCL implementation with your
+# own. The value must be a fully qualified class name that implements the
+# interface jpos.loader.JposServiceManager
+#
+# 2) jpos.config.regPopulatorClass
+#
+# This property specifies the registry populator class---that populates the
+# entry registry. It must be a fully qualified class name that implements
+# the jpos.config.JposRegPopulator interface. If you want to specify
+# multiple populators then you should instead use the:
+# jpos.config.populator.class.
+# property---defined below---that allows you to specify many populators
+# There are 3 populators that are provided with the JCL by default:
+# a) jpos.config.simple.SimpleRegPopulator
+# This populator loads/saves JposEntry objects as serialized objects in
+# a Java serialized file, typically named: jpos.cfg
+# b) jpos.config.simple.xml.XercesRegPopulator
+# This populator uses Xerces and implements an XML parser according to
+# the jpos/res/jcl.dtd. By default, the XML file must be named jpos.xml
+# However, this named can be changed using the property (see below):
+# jpos.config.populator.file.
+# c) jpos.config.simple.xml.Xerces2RegPopulator
+# This populator uses Xerces2 and implements an XML parser according to
+# the jpos/res/jcl.xsd XML schema. The file name is same as above; however,
+# since this parser expects an XML schema, the XML file header is different.
+# See the jpos-schema.xml file.
+#
+# NOTE: Xerces and Xerces2 are XML parsers from the http://www.apache.org
+# Jakarta projects.
+#------------------------------------------------------------------------------
+
+jpos.loader.serviceManagerClass=jpos.loader.simple.SimpleServiceManager
+
+#jpos.config.regPopulatorClass=jpos.config.simple.SimpleRegPopulator
+jpos.config.regPopulatorClass=jpos.config.simple.xml.SimpleXmlRegPopulator
+#jpos.config.regPopulatorClass=jpos.config.simple.xml.Xerces2RegPopulator
+
+#------------------------------------------------------------------------------
+# Use this property to for the JCL to load a specific file (cfg or XML)
+# when not using multiple populators via the jpos.config.populator.class.
+# multi-property
+#------------------------------------------------------------------------------
+
+#jpos.config.populatorFile=jpos1.cfg
+
+#------------------------------------------------------------------------------
+# To define multiple populator then comment the property
+# "jpos.config.regPopulatorClass"
+# and use the following multiproperty properties (defines 2 populators one
+# XML and one serialized)
+#------------------------------------------------------------------------------
+
+#jpos.config.populator.class.0=jpos.config.simple.xml.SimpleXmlRegPopulator
+#jpos.config.populator.class.1=jpos.config.simple.SimpleRegPopulator
+
+#------------------------------------------------------------------------------
+# You can also define populator files for each populator as follows
+#------------------------------------------------------------------------------
+
+#jpos.config.populator.file.0=jpos0.xml
+#jpos.config.populator.file.1=jpos1.cfg
+
+#------------------------------------------------------------------------------
+# Tracing properties
+# ------------------
+# All tracing properties that are boolean attributes can be turned on of
+# off using ON/on/TRUE/true or OFF/false for any other value.
+# The available properties are (see commented properties below):
+# 1) jpos.tracing
+# This is a legacy property and will turn the global tracer on. You should
+# note that it is preferable to use the named tracing property instead
+# 2) jpos.com.team871.util.tracing.TurnOnAllNamedTracers
+# This property when turned on will enable all named tracers. A named tracer
+# will print out a message prepended by [] where is the name of
+# the tracer in question.
+# 3) jpos.com.team871.util.tracing.TurnOnNamedTracers = name1, name2, ...
+# This will turn on the named tracers listed as name1, name2, ... this is
+# useful if when all named tracers are on you want to filter the output
+#------------------------------------------------------------------------------
+
+#jpos.tracing=ON
+#jpos.com.team871.util.tracing.TurnOnNamedTracers=XercesRegPopulator, AbstractRegPopulator, MainFrame
+#jpos.com.team871.util.tracing.TurnOnNamedTracers=JposServiceLoader,SimpleEntryRegistry,SimpleRegPopulator,XercesRegPopulator
+#jpos.com.team871.util.tracing.TurnOnAllNamedTracers=OFF
\ No newline at end of file