--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>de.laktatnebel.product.tools</groupId>
+ <artifactId>Calculators</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ <packaging>war</packaging>
+
+ <parent>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-parent</artifactId>
+ <version>2.4.3</version>
+ <relativePath /> <!-- lookup parent from repository -->
+ </parent>
+
+ <name>Calculators</name>
+ <description>Calculates Sport Issues</description>
+
+ <properties>
+ <java.version>15</java.version>
+ <jaxb-api.version>2.3.1</jaxb-api.version>
+ <utillib.version>2.1.0</utillib.version>
+ </properties>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>javax.xml.bind</groupId>
+ <artifactId>jaxb-api</artifactId>
+ <version>${jaxb-api.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>de.laktatnebel.libs</groupId>
+ <artifactId>utillib</artifactId>
+ <version>${utillib.version}</version>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-web</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-devtools</artifactId>
+ <scope>runtime</scope>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-tomcat</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-test</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <!-- https://mvnrepository.com/artifact/javax.xml.bind/jaxb-api -->
+ <dependency>
+ <groupId>javax.xml.bind</groupId>
+ <artifactId>jaxb-api</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>de.laktatnebel.libs</groupId>
+ <artifactId>utillib</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-maven-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
--- /dev/null
+package de.laktatnebel.product.tools;
+
+/*
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.UriInfo;
+*/
+
+//@Path("/hello")
+public class Hello {
+// This method is called if TEXT_PLAIN is request
+ //@GET
+ // @Produces(MediaType.TEXT_PLAIN)
+ public String sayPlainTextHello() {
+ return "Hello Jersey";
+ }
+
+// This method is called if XML is request
+ //@GET
+ //@Produces(MediaType.TEXT_XML)
+ public String sayXMLHello() {
+ return "<?xml version=\"1.0\"?>" + "<hello> Hello Jersey" + "</hello>";
+ }
+
+// This method is called if HTML is request
+ //@GET
+ //@Produces(MediaType.TEXT_HTML)
+ public String sayHtmlHello() {
+ return "<html> " + "<title>" + "Hello Jersey" + "</title>"
+ + "<body><h1>" + "Hello Jersey" + "</body></h1>" + "</html> ";
+ }
+}
--- /dev/null
+package de.laktatnebel.product.tools.calculators;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class AbstractCalculator {
+
+ /** Logger logger field */
+ private static Logger logger = LoggerFactory.getLogger(AbstractCalculator.class);
+
+ {
+ logger = null;
+ }
+
+ /**
+ * @param clazz Class
+ * @return Logger
+ */
+ public static Logger getLogger(Class<?> clazz) {
+ if (AbstractCalculator.logger == null) {
+ AbstractCalculator.logger = LoggerFactory.getLogger(clazz);
+ }
+ return AbstractCalculator.logger;
+ }
+ /**
+ *
+ * @param logger Logger
+ * @param string String
+ */
+ public static void log(Logger logger, String string) {
+ if (logger.isTraceEnabled()) {
+ logger.trace(string);
+ } else if (logger.isDebugEnabled()) {
+ logger.debug(string);
+ } else if (logger.isInfoEnabled()) {
+ logger.info(string);
+ } else if (logger.isWarnEnabled()) {
+ logger.warn(string);
+ } else if (logger.isErrorEnabled()) {
+ logger.error(string);
+ }
+ }
+
+}
--- /dev/null
+package de.laktatnebel.product.tools.calculators;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class Calculators {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Calculators.class, args);
+ }
+
+}
--- /dev/null
+package de.laktatnebel.product.tools.calculators;
+
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+
+public class ServletInitializer extends SpringBootServletInitializer {
+
+ @Override
+ protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
+ return application.sources(Calculators.class);
+ }
+
+}
--- /dev/null
+package de.laktatnebel.product.tools.calculators.output;
+
+import java.io.StringWriter;
+import java.util.HashMap;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+public class OutPutter {
+
+ private Document doc = null;
+
+ public OutPutter() {
+
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder builder = null;
+ try {
+ builder = factory.newDocumentBuilder();
+ } catch (ParserConfigurationException e) {
+ e.printStackTrace();
+ throw new RuntimeException("Error converting to String", e);
+ }
+ Document doc = builder.newDocument();
+
+ Element root = doc.createElementNS("laktatnebel.de", "result");
+ doc.appendChild(root);
+
+ this.doc = doc;
+ }
+
+ public void setNodeNameValue(String nodeName, String nodeValue) {
+ NodeList elementsByTagName = this.doc.getElementsByTagName("result");
+
+ Element e = getNodeNameValue(nodeName, nodeValue);
+
+ elementsByTagName.item(0).appendChild(e);
+ }
+
+ public Element getNodeNameValue(String nodeName, String nodeValue) {
+ Element e = this.doc.createElement(nodeName);
+ e.appendChild(this.doc.createTextNode(nodeValue));
+
+ return e;
+ }
+
+ public void setNodeList(String nodeName, HashMap<String, String> nameValueList) {
+ NodeList elementsByTagName = this.doc.getElementsByTagName("result");
+
+ Element mother = this.doc.createElement(nodeName);
+
+ Element newChild = null;
+ for (String keyValue : nameValueList.keySet()) {
+
+ newChild = getNodeNameValue(keyValue, nameValueList.get(keyValue));
+ mother.appendChild(newChild);
+ elementsByTagName.item(0).appendChild(mother);
+ }
+ }
+
+ @Override
+ public String toString() {
+ try {
+ StringWriter sw = new StringWriter();
+
+ TransformerFactory tf = TransformerFactory.newInstance();
+ Transformer transformer = tf.newTransformer();
+ transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
+ transformer.setOutputProperty(OutputKeys.METHOD, "xml");
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+ transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+
+ transformer.transform(new DOMSource(this.doc), new StreamResult(sw));
+ return sw.toString();
+ } catch (Exception ex) {
+ throw new RuntimeException("Error converting to String", ex);
+ }
+ }
+
+}
\ No newline at end of file
--- /dev/null
+package de.laktatnebel.product.tools.calculators.run;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import de.laktatnebel.product.tools.calculators.AbstractCalculator;
+import de.laktatnebel.product.tools.calculators.output.OutPutter;
+import de.laktatnebel.product.tools.calculators.util.Converter;
+import de.laktatnebel.product.tools.calculators.util.Time;
+
+@RestController
+public class RunPace extends AbstractCalculator {
+ @SuppressWarnings("unused")
+
+ /**
+ * Default constructor.
+ */
+ public RunPace() {
+ // TODO Auto-generated constructor stub
+ }
+
+ @RequestMapping(value = "/hello", method = RequestMethod.GET, produces = MediaType.TEXT_PLAIN_VALUE)
+ ResponseEntity<String> helloWorld() {
+ return new ResponseEntity<String>("Hello World!", HttpStatus.OK);
+ }
+
+ @RequestMapping(value = "/pace/{dist}/{hour}/{min}/{sec}", method = RequestMethod.GET, produces = MediaType.TEXT_XML_VALUE)
+ @ResponseBody
+ ResponseEntity<String> getPace(@PathVariable(name = "dist") Double distance,
+ @PathVariable(name = "hour") Integer hours, @PathVariable(name = "min") Integer minutes,
+ @PathVariable(name = "sec") Integer seconds) {
+
+ Time originTime = new Time(hours, minutes, seconds);
+ Double kmPerHours = Converter.getKmPerHours(distance, originTime);
+ String pace = Converter.getPace(originTime, distance);
+
+ OutPutter output = new OutPutter();
+ output.setNodeNameValue("pace", pace);
+ output.setNodeNameValue("speed", Double.toString(kmPerHours));
+
+ return new ResponseEntity<String>(output.toString(), HttpStatus.OK);
+ }
+}
--- /dev/null
+package de.laktatnebel.product.tools.calculators.run;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import de.laktatnebel.product.tools.calculators.AbstractCalculator;
+import de.laktatnebel.product.tools.calculators.output.OutPutter;
+import de.laktatnebel.product.tools.calculators.util.Converter;
+import de.laktatnebel.product.tools.calculators.util.Time;
+
+@RestController
+public class RunPrediction extends AbstractCalculator {
+ private static final double VDOT_PRECISION = 0.000125;
+
+ @SuppressWarnings("unused")
+
+ /**
+ * Default constructor.
+ */
+ public RunPrediction() {
+ // TODO Auto-generated constructor stub
+ }
+
+ @RequestMapping(value = "/predict/{dist}/{hour}/{min}/{sec}/{disttopredict}", method = RequestMethod.GET, produces = MediaType.TEXT_XML_VALUE)
+ @ResponseBody
+ ResponseEntity<String> getPace(@PathVariable(name = "dist") Double distance,
+ @PathVariable(name = "hour") Integer hours, @PathVariable(name = "min") Integer minutes,
+ @PathVariable(name = "sec") Integer seconds, @PathVariable(name = "disttopredict") Double distancetopredict) {
+
+ Time originTime = new Time(hours, minutes, seconds);
+ getLogger(RunPrediction.class).debug("originTime\t" + originTime.toString());
+ getLogger(RunPrediction.class).debug("originTime\t" + originTime.toFormattedString());
+
+ JackDaniels originJD = new JackDaniels (originTime, distance);
+ getLogger(RunPrediction.class).debug("originJD\t" + originJD.toString());
+
+ String originPace = Converter.getPace(originTime, distance);
+
+ Time estimatedTime = new Time();
+ estimatedTime.setTimeMinutes(originTime.getMinutes() * Math.pow(distancetopredict / distance, 1.06));
+ getLogger(RunPrediction.class).debug("estimatedTime\t" + estimatedTime.toString());
+ getLogger(RunPrediction.class).debug("estimatedTime\t" + estimatedTime.toFormattedString());
+
+ JackDaniels estimatedJD = new JackDaniels(estimatedTime, distancetopredict);
+ getLogger(RunPrediction.class).debug("estimatedJD\t" + estimatedJD.toString());
+
+ String estimatedPace = Converter.getPace(estimatedTime, distancetopredict);
+
+ int i=0;
+ Time predictedTime = new Time();
+ predictedTime.setTimeHours(estimatedTime.getHours());
+ JackDaniels predictedJD = new JackDaniels(estimatedTime, distancetopredict);
+ while (Math.abs(predictedJD.getVdot() / originJD.getVdot() - 1) > VDOT_PRECISION) {
+ if (estimatedJD.getVdot() > originJD.getVdot()) {
+ predictedTime.addSeconds(1);
+ } else {
+ predictedTime.addSeconds(-1);
+ }
+
+ getLogger(RunPrediction.class).debug("predictedTime\t" + predictedTime.toString());
+ getLogger(RunPrediction.class).debug("predictedTime\t" + predictedTime.toFormattedString());
+
+ predictedJD = new JackDaniels(predictedTime, distancetopredict);
+ getLogger(RunPrediction.class).debug("predictedJD\t" + predictedJD.toString());
+
+ if (++i >= 100 ) break;
+ }
+
+ String predictedPace = Converter.getPace(predictedTime, distancetopredict);
+
+ Double kmPerHours = Converter.getKmPerHours(distance, originTime);
+ Double meterPerMin = Converter.getMeterPerMin(distance, originTime);
+
+ OutPutter output = new OutPutter();
+ output.setNodeNameValue("pace_min-km", originPace);
+ output.setNodeNameValue("speed_km-h", Double.toString(kmPerHours));
+ output.setNodeNameValue("meter-per-min", Double.toString(meterPerMin));
+ output.setNodeNameValue("vO2", Double.toString(originJD.getVo2()));
+ output.setNodeNameValue("fvO2", Double.toString(originJD.getFvo2()));
+ output.setNodeNameValue("vdot", Double.toString(originJD.vdot));
+ output.setNodeNameValue("distancetopredict", Double.toString(distancetopredict));
+ output.setNodeNameValue("estimatedTime", estimatedTime.toFormattedString());
+ output.setNodeNameValue("estimatedPace_min-km", estimatedPace);
+ output.setNodeNameValue("predictedTime", predictedTime.toFormattedString());
+ output.setNodeNameValue("predictedPace_min-km", predictedPace);
+
+ return new ResponseEntity<String>(output.toString(), HttpStatus.OK);
+ }
+
+ private class JackDaniels {
+ private Double vo2 = 0.0;
+ private Double fvo2 = 0.0;
+ private Double vdot = 0.0;
+
+ public JackDaniels(Time originTime, Double distance) {
+ this.vo2 = 0.000104 * Math.pow(Converter.getMeterPerMin(distance, originTime), 2) + 0.182258 * Converter.getMeterPerMin(distance, originTime) - 4.60;
+ this.fvo2 = 0.80 + 0.298956 * Math.pow(Math.E, (-0.193261*originTime.getMinutes())) + 0.189438 * Math.pow(Math.E, (-0.012778*originTime.getMinutes()));
+ this.vdot = getVo2() / getFvo2();
+ }
+
+ public Double getVo2() {
+ return vo2;
+ }
+
+ public Double getFvo2() {
+ return fvo2;
+ }
+
+ public Double getVdot() {
+ return vdot;
+ }
+
+ @Override
+ public String toString() {
+ return "JackDaniels [vo2=" + vo2 + ", fvo2=" + fvo2 + ", vdot=" + vdot + "]";
+ }
+ }
+}
--- /dev/null
+package de.laktatnebel.product.tools.calculators.run;
+
+import java.util.HashMap;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import de.laktatnebel.product.tools.calculators.AbstractCalculator;
+import de.laktatnebel.product.tools.calculators.output.OutPutter;
+import de.laktatnebel.product.tools.calculators.util.Converter;
+import de.laktatnebel.product.tools.calculators.util.Time;
+
+@RestController
+public class SplitTimes extends AbstractCalculator {
+
+ public SplitTimes() {
+ super();
+ // TODO Auto-generated constructor stub
+ }
+
+ @RequestMapping(value = "/splits/{dist}/{hour}/{min}/{sec}", method = RequestMethod.GET, produces = MediaType.TEXT_XML_VALUE)
+ @ResponseBody
+ ResponseEntity<String> getAllSplits(@PathVariable(name = "dist") Double distance,
+ @PathVariable(name = "hour") Integer hours, @PathVariable(name = "min") Integer minutes,
+ @PathVariable(name = "sec") Integer seconds) {
+
+ Time originTime = new Time(hours, minutes, seconds);
+ Double kmPerHours = Converter.getKmPerHours(distance, originTime);
+ String pace = Converter.getPace(originTime, distance);
+
+ OutPutter output = new OutPutter();
+
+ output.setNodeNameValue("pace", pace);
+ output.setNodeNameValue("speed", Double.toString(kmPerHours));
+ getLogger(RunPrediction.class).debug("speed\t" + kmPerHours);
+
+ Double split = 0.0;
+ while (split < distance) {
+ getLogger(RunPrediction.class).debug("split\t" + split);
+
+ Time splitTime = new Time();
+ splitTime.setTimeHours(split * originTime.getHours() / distance);
+
+ HashMap<String, String> splits = new HashMap<String, String>();
+ splits.put("km", Double.toString(split));
+ splits.put("time", splitTime.toFormattedString());
+
+ output.setNodeList("split", splits);
+ split++;
+ }
+
+ HashMap<String, String> splits = new HashMap<String, String>();
+ splits.put("km", Double.toString(distance));
+ splits.put("time", originTime.toFormattedString());
+
+ output.setNodeList("split", splits);
+
+ return new ResponseEntity<String>(output.toString(), HttpStatus.OK);
+ }
+
+ @RequestMapping(value = "/splits/{dist}/{hour}/{min}/{sec}/{specialsplit}", method = RequestMethod.GET, produces = MediaType.TEXT_XML_VALUE)
+ @ResponseBody
+ ResponseEntity<String> getSpecialSplit(@PathVariable(name = "dist") Double distance,
+ @PathVariable(name = "hour") Integer hours, @PathVariable(name = "min") Integer minutes,
+ @PathVariable(name = "sec") Integer seconds, @PathVariable(name = "specialsplit") Double specialsplit) {
+
+ Time originTime = new Time(hours, minutes, seconds);
+ Double kmPerHours = Converter.getKmPerHours(distance, originTime);
+ String pace = Converter.getPace(originTime, distance);
+
+ OutPutter output = new OutPutter();
+
+ output.setNodeNameValue("pace", pace);
+ output.setNodeNameValue("speed", Double.toString(kmPerHours));
+ getLogger(RunPrediction.class).debug("speed\t" + kmPerHours);
+
+ Time splitTime = new Time();
+ splitTime.setTimeHours(originTime.getHours() * specialsplit / distance);
+
+ HashMap<String, String> splits = new HashMap<String, String>();
+ splits.put("km", Double.toString(specialsplit));
+ splits.put("time", splitTime.toFormattedString());
+
+ output.setNodeList("split", splits);
+
+ return new ResponseEntity<String>(output.toString(), HttpStatus.OK);
+ }
+
+}
--- /dev/null
+package de.laktatnebel.product.tools.calculators.util;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.TimeZone;
+
+public class Converter {
+
+ public static String getPace(Time time, Double distance) {
+ Date dateFromTimeInSeconds = new Date(Math.round(60L * 60L * 1000L * time.getHours() / distance));
+
+ SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss,SS");
+ sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
+
+ return sdf.format(dateFromTimeInSeconds);
+ }
+
+ public static Double getKmPerHours(Double distance, Time time) {
+ return distance / time.getHours();
+ }
+
+ public static Double getMeterPerMin(Double distance, Time time) {
+ return distance * 1000 / time.getMinutes();
+ }
+
+
+}
--- /dev/null
+package de.laktatnebel.product.tools.calculators.util;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.TimeZone;
+
+public class Time {
+
+ private Double seconds = 0.0;
+ private Double minutes = 0.0;
+ private Double hours = 0.0;
+
+ public Time(Integer hours, Integer minutes, Integer seconds) {
+ super();
+ setTime(hours, minutes, seconds);
+ }
+
+ public void addSeconds(int secondsToAdd) {
+ setTimeSeconds(this.seconds + (double) secondsToAdd/10);
+ }
+
+ public String toFormattedString() {
+ Date dateFromTimeInSeconds = new Date(Math.round(1000L * seconds));
+
+ SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss,SS");
+ sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
+
+ return sdf.format(dateFromTimeInSeconds);
+ }
+
+ public Time() {
+ super();
+ }
+
+ public Double getSeconds() {
+ return seconds;
+ }
+
+ public Double getMinutes() {
+ return minutes;
+ }
+
+ public Double getHours() {
+ return hours;
+ }
+
+ public void setTimeSeconds(Double seconds) {
+ this.seconds = seconds;
+ this.minutes = seconds / 60;
+ this.hours = seconds / 3600;
+ }
+
+ public void setTimeMinutes(Double minutes) {
+ this.seconds = minutes * 60;
+ this.minutes = minutes;
+ this.hours = minutes / 60;
+ }
+
+ public void setTimeHours(Double hours) {
+ this.seconds = hours * 3600;
+ this.minutes = hours * 60;
+ this.hours = hours;
+ }
+
+ public void setTime(Integer hours, Integer minutes, Integer seconds) {
+ this.seconds = (double) hours * 3600 + (double) minutes * 60 + (double) seconds;
+ this.minutes = (double) hours * 60 + (double) minutes + (double) seconds / 60;
+ this.hours = (double) hours + (double) minutes / 60 + (double) seconds / 3600;
+ }
+
+ @Override
+ public String toString() {
+ return "Time [seconds=" + seconds + ", minutes=" + minutes + ", hours=" + hours + "]";
+ }
+}
\ No newline at end of file
--- /dev/null
+logging.level.root=TRACE
+logging.level.org.springframework.web=DEBUG
+logging.level.org.hibernate=ERROR
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" ?>\r
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">\r
+\r
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">\r
+\r
+ <appender name="appender" class="org.apache.log4j.ConsoleAppender">\r
+ <layout class="org.apache.log4j.PatternLayout">\r
+ <param name="ConversionPattern" value="%d [%t] %p - %m%n" />\r
+ </layout>\r
+ </appender>\r
+\r
+ <root>\r
+ <priority value="trace" />\r
+ <appender-ref ref="appender" />\r
+ </root>\r
+\r
+</log4j:configuration>\r
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<title>Insert title here</title>
+</head>
+<body>
+something ...
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+package de.laktatnebel.product.tools.calculators;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class CalculatorApplicationTests {
+
+ @Test
+ void contextLoads() {
+ }
+
+}