initial commit

This commit is contained in:
rdavidek 2021-04-23 13:28:20 +02:00
commit 00f5522167
12 changed files with 758 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
target
bin
.settings
.classpath
.project

61
pom.xml Normal file
View File

@ -0,0 +1,61 @@
<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 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cz.kamma.mining</groupId>
<artifactId>mining-info-web</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>mining-info-web</name>
<url>http://maven.apache.org</url>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.json/json -->
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20171018</version>
</dependency>
</dependencies>
<build>
<finalName>ROOT</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>prime-repo</id>
<name>Prime Repo</name>
<url>http://repository.primefaces.org</url>
</repository>
</repositories>
</project>

View File

@ -0,0 +1,8 @@
package cz.kamma.mining;
public interface Constants {
public static final String APP_VERSION = "v0.4";
public static final String COPYRIGHT = "2021";
public static final int DEFAULT_HTTP_TIMEOUT = 2000;
}

View File

@ -0,0 +1,281 @@
package cz.kamma.mining.bean;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.JSONArray;
import org.json.JSONObject;
import cz.kamma.mining.Constants;
import cz.kamma.mining.helper.HttpHelper;
import cz.kamma.mining.vo.KeyValue;
public class MiningBean {
public static String updateAll(HttpServletRequest request, HttpServletResponse response) throws Exception {
java.lang.System.setProperty("https.protocols", "TLSv1,TLSv1.1,TLSv1.2");
List<KeyValue> prices = new ArrayList<>();
List<KeyValue> workers = new ArrayList<>();
List<KeyValue> pool = new ArrayList<>();
List<KeyValue> network = new ArrayList<>();
String[] cryptoCur = new String[] { "btc", "ltc", "xrp", "eth" };
double[] lastPrices = new double[] { 0, 0, 0, 0 };
String apikey = request.getParameter("apikey");
String ltcWallet = request.getParameter("ltc");
String xrpWallet = request.getParameter("xrp");
String currency = request.getParameter("cur");
if (request.getParameter("apikey") == null) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid API key");
return null;
}
if (currency == null || currency.equals("null") || currency.length() == 0)
currency = "usd";
else
currency = currency.toLowerCase();
String curSym = "$";
if (currency.equals("usd"))
curSym = "$";
else if (currency.equals("eur"))
curSym = "";
workers.clear();
prices.clear();
network.clear();
pool.clear();
String resultStr;
String restRequest;
for (int i = 0; i < cryptoCur.length; i++) {
String ccur = cryptoCur[i];
restRequest = HttpHelper.getStringResponse("https://www.bitstamp.net/api/v2/ticker/".concat(ccur).concat(currency));
if (restRequest != null && restRequest.length() > 0) {
JSONObject tmp = new JSONObject(restRequest);
double res = tmp.getDouble("last");
lastPrices[i] = res;
if (res > 0d)
resultStr = curSym + res;
else
resultStr = "Unknown";
KeyValue wi = new KeyValue();
wi.setKey(ccur.toUpperCase().concat("/").concat(currency.toUpperCase()).concat(" (Bitstamp)"));
wi.setValue(resultStr);
prices.add(wi);
}
}
if (ltcWallet != null && !"null".equals(ltcWallet) && ltcWallet.length() > 0) {
restRequest = HttpHelper.getStringResponse("https://chain.so/api/v2/get_address_balance/LTC/".concat(ltcWallet));
if (restRequest != null && restRequest.length() > 0) {
JSONObject full = new JSONObject(restRequest);
JSONObject data = (JSONObject)full.get("data");
String confirmedBalance = (String) data.get("confirmed_balance");
double res = Double.parseDouble(confirmedBalance);
if (res > 0d) {
resultStr = res + " LTC " + curSym + String.format("%.2f", (res * lastPrices[1]));
} else
resultStr = "Unknown";
KeyValue wi = new KeyValue();
wi.setKey("My Balance LTC");
wi.setValue(resultStr);
prices.add(wi);
}
}
if (xrpWallet != null && !"null".equals(xrpWallet) && xrpWallet.length() > 0) {
restRequest = HttpHelper.getStringResponse("https://data.ripple.com/v2/accounts/".concat(xrpWallet).concat("/balances"));
if (restRequest != null && restRequest.length() > 0) {
JSONObject full = new JSONObject(restRequest);
JSONArray balances = (JSONArray) full.get("balances");
double res = balances.getJSONObject(0).getDouble("value");
if (res > 0d) {
resultStr = res + " XRP " + curSym + String.format("%.2f", (res * lastPrices[2]));
} else
resultStr = "Unknown";
KeyValue wi = new KeyValue();
wi.setKey("My Balance XRP");
wi.setValue(resultStr);
prices.add(wi);
}
}
if (apikey != null && !"null".equals(apikey) && apikey.length() > 0) {
String miningJson = HttpHelper.getStringResponse("https://www.litecoinpool.org/api?api_key=".concat(apikey));
if (miningJson != null && miningJson.length() > 0) {
JSONObject full = new JSONObject(miningJson);
JSONObject user = (JSONObject) full.get("user");
KeyValue wi = new KeyValue();
wi.setKey("HashRate");
if (user.getInt("hash_rate") > 0)
wi.setValue((user.getInt("hash_rate") / 1000) + " MH/s");
else
wi.setValue("Unknown");
workers.add(wi);
JSONObject workersJson = (JSONObject) full.get("workers");
for (Iterator<String> keys = workersJson.keys(); keys.hasNext();) {
String key = keys.next();
JSONObject worker = (JSONObject) workersJson.get(key);
wi = new KeyValue();
wi.setKey("HashRate " + key);
wi.setValue((worker.getInt("hash_rate") / 1000) + " MH/s");
workers.add(wi);
}
wi = new KeyValue();
wi.setKey("Paid");
if (user.getDouble("paid_rewards") > 0)
wi.setValue(user.getDouble("paid_rewards") + " LTC " + curSym + String.format("%.2f", (user.getDouble("paid_rewards") * lastPrices[1])));
else
wi.setValue("Unknown");
workers.add(wi);
wi = new KeyValue();
wi.setKey("Unpaid");
if (user.getDouble("unpaid_rewards") > 0)
wi.setValue(user.getDouble("unpaid_rewards") + " LTC " + curSym + String.format("%.2f", (user.getDouble("unpaid_rewards") * lastPrices[1])));
else
wi.setValue("Unknown");
workers.add(wi);
wi = new KeyValue();
wi.setKey("Total");
if (user.getDouble("total_rewards") > 0)
wi.setValue(user.getDouble("total_rewards") + " LTC " + curSym + String.format("%.2f", (user.getDouble("total_rewards") * lastPrices[1])));
else
wi.setValue("Unknown");
workers.add(wi);
wi = new KeyValue();
wi.setKey("Expected 24h");
if (user.getDouble("expected_24h_rewards") > 0)
wi.setValue(user.getDouble("expected_24h_rewards") + " LTC " + curSym + String.format("%.2f", (user.getDouble("expected_24h_rewards") * lastPrices[1])));
else
wi.setValue("Unknown");
workers.add(wi);
wi = new KeyValue();
wi.setKey("Past 24h");
if (user.getDouble("past_24h_rewards") > 0)
wi.setValue(user.getDouble("past_24h_rewards") + " LTC " + curSym + String.format("%.2f", (user.getDouble("past_24h_rewards") * lastPrices[1])));
else
wi.setValue("Unknown");
workers.add(wi);
JSONObject net = (JSONObject) full.get("network");
wi = new KeyValue();
wi.setKey("Network HashRate");
if (net.getLong("hash_rate") > 0)
wi.setValue((net.getLong("hash_rate") / 1000000) + " GH/s");
else
wi.setValue("Unknown");
network.add(wi);
wi = new KeyValue();
wi.setKey("Difficulty");
if (net.getDouble("difficulty") > 0)
wi.setValue("" + net.getDouble("difficulty"));
else
wi.setValue("Unknown");
network.add(wi);
wi = new KeyValue();
wi.setKey("Next Difficulty");
if (net.getDouble("next_difficulty") > 0)
wi.setValue("" + net.getDouble("next_difficulty"));
else
wi.setValue("Unknown");
network.add(wi);
wi = new KeyValue();
wi.setKey("Retarget time");
if (net.getDouble("retarget_time") > 0)
wi.setValue(splitToComponentTimes(net.getInt("retarget_time")));
else
wi.setValue("Unknown");
network.add(wi);
JSONObject poolJson = (JSONObject) full.get("pool");
wi = new KeyValue();
wi.setKey("Pool HashRate");
if (poolJson.getLong("hash_rate") > 0)
wi.setValue((poolJson.getLong("hash_rate") / 1000000) + " GH/s");
else
wi.setValue("Unknown");
pool.add(wi);
wi = new KeyValue();
wi.setKey("Active users");
if (poolJson.getInt("active_users") > 0)
wi.setValue("" + poolJson.getInt("active_users"));
else
wi.setValue("Unknown");
pool.add(wi);
wi = new KeyValue();
wi.setKey("PPS Ratio");
if (poolJson.getDouble("pps_ratio") > 0)
wi.setValue("" + poolJson.getDouble("pps_ratio"));
else
wi.setValue("Unknown");
pool.add(wi);
}
}
String res = "<response><prices>#PRICES#</prices><workers>#WORKERS#</workers><pool>#POOL#</pool><network>#NETWORK#</network></response>";
String tmp = "";
for (KeyValue kv : prices) {
tmp = tmp.concat("<pair><key>").concat(kv.getKey().concat("</key>").concat("<value>").concat(kv.getValue()).concat("</value></pair>"));
}
res = res.replace("#PRICES#", tmp);
tmp = "";
for (KeyValue kv : workers) {
tmp = tmp.concat("<pair><key>").concat(kv.getKey().concat("</key>").concat("<value>").concat(kv.getValue()).concat("</value></pair>"));
}
res = res.replace("#WORKERS#", tmp);
tmp = "";
for (KeyValue kv : pool) {
tmp = tmp.concat("<pair><key>").concat(kv.getKey().concat("</key>").concat("<value>").concat(kv.getValue()).concat("</value></pair>"));
}
res = res.replace("#POOL#", tmp);
tmp = "";
for (KeyValue kv : network) {
tmp = tmp.concat("<pair><key>").concat(kv.getKey().concat("</key>").concat("<value>").concat(kv.getValue()).concat("</value></pair>"));
}
res = res.replace("#NETWORK#", tmp);
return res;
}
public String getVersion() {
return Constants.APP_VERSION;
}
public static String splitToComponentTimes(int longVal) {
int days = longVal / (24 * 3600);
int remainder = longVal - (days * 24 * 3600);
int hours = remainder / 3600;
remainder = remainder - hours * 3600;
int mins = remainder / 60;
//remainder = remainder - mins * 60;
//int secs = remainder;
return (days>0?days+"d ":"")+(hours>0?hours+"h ":"")+(mins>0?mins+"m ":"");
}
}

View File

@ -0,0 +1,39 @@
package cz.kamma.mining.helper;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import cz.kamma.mining.Constants;
public class HttpHelper {
public static String getStringResponse(String urlStr) {
return getStringResponse(urlStr, Constants.DEFAULT_HTTP_TIMEOUT);
}
public static String getStringResponse(String urlStr, int timeout) {
String output = "";
try {
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);
conn.setDoOutput(false);
conn.setConnectTimeout(timeout);
conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.76 Safari/537.36");
conn.connect();
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
output += inputLine;
in.close();
conn.disconnect();
} catch (Exception e) {
System.out.println("Error while getting HTTP response from " + urlStr + ". Ex:" + e);
}
return output;
}
}

View File

@ -0,0 +1,28 @@
package cz.kamma.mining.vo;
import java.io.Serializable;
public class KeyValue implements Serializable {
private static final long serialVersionUID = 1L;
String key;
String value;
public KeyValue() {
}
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;
}
}

View File

@ -0,0 +1,10 @@
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<display-name>Mining Console</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>

View File

@ -0,0 +1,34 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@page contentType="text/html; charset=UTF-8" %>
<%@page import="cz.kamma.mining.Constants"%>
<html lang="en">
<head>
<link rel="icon"
href="https://cdn2.iconfinder.com/data/icons/bitcoin-and-mining/44/trade-24.png">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="format-detection" content="telephone=no">
<meta name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<title>Mining Info</title>
<link rel="stylesheet" type="text/css" href="./css/default-theme.css">
<script type="text/javascript"
src="client.js?ver=<%=Constants.APP_VERSION%>"></script>
</head>
<body class="landscape">
<div class="toolbar">
<h1>Mining Info</h1>
</div>
<ul id="overview">
<li>LOADING...</li>
</ul>
<script language=javascript type='text/javascript'>
function asynchUpdate() {
AX_asynchUpdate("<%=request.getParameter("apikey")%>", "<%=request.getParameter("ltc")%>", "<%=request.getParameter("xrp")%>", "<%=request.getParameter("cur")%>");
setTimeout('asynchUpdate();', 5000);
}
asynchUpdate();
</script>
</body>
</html>

142
src/main/webapp/client.js Normal file
View File

@ -0,0 +1,142 @@
var URLsuffix = '/getupdate.jsp';
//var URLsuffix = '/mining-console/getupdate.jsp';
var ajaxHttp = getAjaxLibrary();
function getAjaxLibrary() {
var activexmodes = [ "Msxml2.XMLHTTP", "Microsoft.XMLHTTP" ] // activeX
// versions
// to check
// for in IE
if (window.ActiveXObject) { // Test for support for ActiveXObject in IE
// first (as XMLHttpRequest in IE7 is broken)
for (var i = 0; i < activexmodes.length; i++) {
try {
return new ActiveXObject(activexmodes[i])
} catch (e) {
// suppress error
}
}
} else if (window.XMLHttpRequest) // if Mozilla, Safari etc
return new XMLHttpRequest()
else
return false
}
/*******************************************************************************
* F U N C T I O N S
******************************************************************************/
function getHost() {
var url = "" + window.location;
var prot = url.split('//')[0];
var urlparts = url.split('//')[1].split('/');
return urlparts[0];
}
function getProt() {
var url = "" + window.location;
return url.split('//')[0];
}
function ajaxSendRequest(data, onReadyStateChange) {
var URL = getProt() + '//' + getHost() + URLsuffix;
// if (ajaxHttp.overrideMimeType)
// ajaxHttp.overrideMimeType('text/xml')
ajaxHttp.open("POST", URL, true);
ajaxHttp.onreadystatechange = onReadyStateChange;
ajaxHttp.setRequestHeader('Content-Type',
'application/x-www-form-urlencoded');
ajaxHttp.send(data);
}
function ajaxResponseReady() {
if (ajaxHttp.readyState == 4) {
/* received */
if (ajaxHttp.status == 200
|| window.location.href.indexOf("http") == -1) {
/* response is ok */
return true;
} else {
return false;
}
}
return false;
}
function ajaxGetXmlResponse() {
if (ajaxHttp.responseXML && ajaxHttp.responseXML.parseError
&& (ajaxHttp.responseXML.parseError.errorCode != 0)) {
ajaxGetXmlError(true);
return null;
} else {
return ajaxHttp.responseXML;
}
}
function AX_asynchUpdate(apikey, ltc, xrp, cur) {
var data = 'ajaxMethod=asynchUpdate&apikey=' + apikey + '&ltc=' + ltc
+ '&xrp=' + xrp+ '&cur=' + cur;
ajaxSendRequest(data, AX_asynchUpdateResponse);
}
function AX_asynchUpdateResponse() {
if (ajaxResponseReady()) {
if (ajaxHttp.responseText.indexOf('invalid') == -1) {
var xmlDocument = ajaxGetXmlResponse();
var prices = xmlDocument.getElementsByTagName("prices")[0]
.getElementsByTagName("pair");
var workers = xmlDocument.getElementsByTagName("workers")[0]
.getElementsByTagName("pair");
var pool = xmlDocument.getElementsByTagName("pool")[0]
.getElementsByTagName("pair");
var network = xmlDocument.getElementsByTagName("network")[0]
.getElementsByTagName("pair");
var resStr = "<li class='group' id='prices'>Prices</li>";
for (var i = 0; i <= (prices.length - 1); i++) {
resStr = resStr
+ "<li>"
+ prices[i].getElementsByTagName("key")[0].firstChild.data
+ " <span class='value' style='transition: text-shadow 0.7s ease-in-out;'>"
+ prices[i].getElementsByTagName("value")[0].firstChild.data
+ "</span></li>";
}
if (workers.length > 0) {
resStr = resStr + "<li class='group' id='workers'>Workers</li>";
for (var i = 0; i <= (workers.length - 1); i++) {
resStr = resStr
+ "<li>"
+ workers[i].getElementsByTagName("key")[0].firstChild.data
+ " <span class='value' style='transition: text-shadow 0.7s ease-in-out;'>"
+ workers[i].getElementsByTagName("value")[0].firstChild.data
+ "</span></li>";
}
}
if (pool.length > 0) {
resStr = resStr + "<li class='group' id='pool'>Pool</li>";
for (var i = 0; i <= (pool.length - 1); i++) {
resStr = resStr
+ "<li>"
+ pool[i].getElementsByTagName("key")[0].firstChild.data
+ " <span class='value' style='transition: text-shadow 0.7s ease-in-out;'>"
+ pool[i].getElementsByTagName("value")[0].firstChild.data
+ "</span></li>";
}
}
if (network.length > 0) {
resStr = resStr + "<li class='group' id='network'>Network</li>";
for (var i = 0; i <= (network.length - 1); i++) {
resStr = resStr
+ "<li>"
+ network[i].getElementsByTagName("key")[0].firstChild.data
+ " <span class='value' style='transition: text-shadow 0.7s ease-in-out;'>"
+ network[i].getElementsByTagName("value")[0].firstChild.data
+ "</span></li>";
}
}
document.getElementById('overview').innerHTML = resStr;
}
}
}

View File

@ -0,0 +1,79 @@
body {
margin: 0;
font-family: Helvetica;
background: #FFFFFF;
color: #000000;
overflow-x: hidden;
}
body > *:not(.toolbar) {
position: absolute;
margin: 0;
padding: 0;
left: 0;
top: 45px;
width: 100%;
height: auto;
min-height: 415px;
}
/************************************************************************************************/
body > .toolbar {
box-sizing: border-box;
border-bottom: 1px solid #2d3642;
border-top: 1px solid #6d84a2;
padding: 0 10px 10px 10px;
height: 45px;
background: #6d84a2 repeat-x;
}
.toolbar > h1 {
position: absolute;
overflow: hidden;
left: 0%;
margin: 1px 0 0 -1px;
padding-top: 10px;
height: 45px;
font-size: 20px;
width: 100%;
font-weight: bold;
text-shadow: rgba(0, 0, 0, 0.4) 0px -1px 0;
text-align: center;
text-overflow: ellipsis;
white-space: nowrap;
color: #FFFFFF;
}
/************************************************************************************************/
body > ul > li {
position: relative;
margin: 0;
border-bottom: 1px solid #E0E0E0;
padding: 8px 0 8px 10px;
font-size: 17px;
font-weight: bold;
list-style: none;
}
.group {
position: relative;
top: -1px;
margin-bottom: -2px;
border-top: 1px solid #7d7d7d;
border-bottom: 1px solid #999999;
padding: 1px 10px;
font-weight: bold;
text-shadow: rgba(0, 0, 0, 0.4) 0 1px 0;
color: #FFFFFF;
opacity:0.7;
background: #c8c8c8 repeat-x;
}
.value {
color: #55AA55;
float: right;
padding: 0 8px;
}

View File

@ -0,0 +1,12 @@
<%@page import="cz.kamma.mining.bean.MiningBean"%>
<%@page import="java.util.Date"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
String res = MiningBean.updateAll(request, response);
response.setContentType("text/xml; charset=UTF-8");
response.setHeader("Cache-Control", "no-cache");
response.getWriter().write(res);
response.getWriter().flush();
%>

58
src/main/webapp/index.jsp Normal file
View File

@ -0,0 +1,58 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@page contentType="text/html; charset=UTF-8" %>
<%@page import="cz.kamma.mining.Constants"%>
<html>
<head>
<link rel="icon"
href="https://cdn2.iconfinder.com/data/icons/bitcoin-and-mining/44/trade-24.png">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Mining Info</title>
<link rel="stylesheet" type="text/css" href="./css/default-theme.css">
</head>
<body>
<div class="toolbar">
<h1>Mining Info</h1>
</div>
<form action="ajaxview.jsp" method="GET">
<table border="0" width="100%">
<tr>
<td class='group'>litecoinpool.org API key (mandatory)</td>
<td align="right" class='group'
style='transition: text-shadow 0.7s ease-in-out;'><input
type="text" name="apikey" size="40" /></td>
</tr>
<tr>
<td class='group'>Litecoin wallet address (optional)</td>
<td align="right" class='group'
style='transition: text-shadow 0.7s ease-in-out;'><input
type="text" name="ltc" size="40" /></td>
</tr>
<tr>
<td class='group'>Ripple wallet address (optional)</td>
<td align="right" class='group'
style='transition: text-shadow 0.7s ease-in-out;'><input
type="text" name="xrp" size="40" /></td>
</tr>
<tr>
<td class='group'>Fiat currency</td>
<td align="right" class='group'
style='transition: text-shadow 0.7s ease-in-out;'><select
name="cur"><option value="usd" selected>USD ($)</option>
<option value="eur">EUR (€)</option></select></td>
</tr>
<tr>
<td class='group' colspan="2"><div align="center">
<input type="submit" value="Show" />
</div></td>
</tr>
<tr>
<td colspan="2"></td>
</tr>
<tr>
<td colspan="2" align="center"><h5>mining-info.eu <%=Constants.APP_VERSION%> ©<%=Constants.COPYRIGHT%><br/>LTC: LgQU1Pf96Bip67bpUrTw6K1goayWjPwfay</h5></td>
</tr>
</table>
</form>
</body>
</html>