Browse Source

Sample configs and other stuff from hushpool.is

pull/3/head
fekt 2 years ago
parent
commit
6669c653af
  1. 20
      coins/hush.json
  2. 9
      coins/wsb.json
  3. 2
      libs/paymentProcessor.js
  4. 38
      pool_configs/solo-wsb.json
  5. 86
      website/default/index.html
  6. 2798
      website/default/key.html
  7. 50
      website/default/pages/admin.html
  8. 11
      website/default/pages/api.html
  9. 325
      website/default/pages/getting_started.html
  10. 132
      website/default/pages/home.html
  11. 105
      website/default/pages/miner_stats.html
  12. 25
      website/default/pages/mining_key.html
  13. 92
      website/default/pages/payments.html
  14. 356
      website/default/pages/stats.html
  15. 64
      website/default/pages/tbs.html
  16. 94
      website/default/pages/workers.html
  17. 100
      website/default/static/admin.js
  18. BIN
      website/default/static/favicon.png
  19. BIN
      website/default/static/hush-logo-horizontal-01.png
  20. BIN
      website/default/static/hushfavicon.ico
  21. 13
      website/default/static/kmdfavicon.svg
  22. BIN
      website/default/static/komodo-logo-horizontal-01.png
  23. 13
      website/default/static/logo.svg
  24. 30
      website/default/static/main.js
  25. 246
      website/default/static/miner_stats.js
  26. 1
      website/default/static/nvd3.css
  27. 6
      website/default/static/nvd3.js
  28. 143
      website/default/static/stats.js
  29. 68
      website/default/static/style.css
  30. 102
      website/piratepool.io/index.html
  31. 2798
      website/piratepool.io/key.html
  32. 50
      website/piratepool.io/pages/admin.html
  33. 11
      website/piratepool.io/pages/api.html
  34. 219
      website/piratepool.io/pages/getting_started.html
  35. 98
      website/piratepool.io/pages/home.html
  36. 34
      website/piratepool.io/pages/miner_stats.html
  37. 25
      website/piratepool.io/pages/mining_key.html
  38. 68
      website/piratepool.io/pages/payments.html
  39. 112
      website/piratepool.io/pages/stats.html
  40. 30
      website/piratepool.io/pages/tbs.html
  41. 56
      website/piratepool.io/pages/workers.html
  42. 100
      website/piratepool.io/static/admin.js
  43. BIN
      website/piratepool.io/static/favicon.png
  44. BIN
      website/piratepool.io/static/favicon/android-icon-144x144.png
  45. BIN
      website/piratepool.io/static/favicon/android-icon-192x192.png
  46. BIN
      website/piratepool.io/static/favicon/android-icon-36x36.png
  47. BIN
      website/piratepool.io/static/favicon/android-icon-48x48.png
  48. BIN
      website/piratepool.io/static/favicon/android-icon-72x72.png
  49. BIN
      website/piratepool.io/static/favicon/android-icon-96x96.png
  50. BIN
      website/piratepool.io/static/favicon/apple-icon-114x114.png
  51. BIN
      website/piratepool.io/static/favicon/apple-icon-120x120.png
  52. BIN
      website/piratepool.io/static/favicon/apple-icon-144x144.png
  53. BIN
      website/piratepool.io/static/favicon/apple-icon-152x152.png
  54. BIN
      website/piratepool.io/static/favicon/apple-icon-180x180.png
  55. BIN
      website/piratepool.io/static/favicon/apple-icon-57x57.png
  56. BIN
      website/piratepool.io/static/favicon/apple-icon-60x60.png
  57. BIN
      website/piratepool.io/static/favicon/apple-icon-72x72.png
  58. BIN
      website/piratepool.io/static/favicon/apple-icon-76x76.png
  59. BIN
      website/piratepool.io/static/favicon/apple-icon-precomposed.png
  60. BIN
      website/piratepool.io/static/favicon/apple-icon.png
  61. 2
      website/piratepool.io/static/favicon/browserconfig.xml
  62. BIN
      website/piratepool.io/static/favicon/favicon-16x16.png
  63. BIN
      website/piratepool.io/static/favicon/favicon-32x32.png
  64. BIN
      website/piratepool.io/static/favicon/favicon-96x96.png
  65. BIN
      website/piratepool.io/static/favicon/favicon.ico
  66. 41
      website/piratepool.io/static/favicon/manifest.json
  67. BIN
      website/piratepool.io/static/favicon/ms-icon-144x144.png
  68. BIN
      website/piratepool.io/static/favicon/ms-icon-150x150.png
  69. BIN
      website/piratepool.io/static/favicon/ms-icon-310x310.png
  70. BIN
      website/piratepool.io/static/favicon/ms-icon-70x70.png
  71. 3
      website/piratepool.io/static/home.js
  72. 13
      website/piratepool.io/static/kmdfavicon.svg
  73. BIN
      website/piratepool.io/static/komodo-logo-horizontal-01.png
  74. 13
      website/piratepool.io/static/logo.svg
  75. 208
      website/piratepool.io/static/main.js
  76. 237
      website/piratepool.io/static/miner_stats.js
  77. 83
      website/piratepool.io/static/payments.js
  78. BIN
      website/piratepool.io/static/pirate128.png
  79. BIN
      website/piratepool.io/static/skull.png
  80. BIN
      website/piratepool.io/static/skull256.png
  81. 149
      website/piratepool.io/static/stats.js
  82. 557
      website/piratepool.io/static/style.css
  83. 79
      website/piratepool.io/static/workers.js
  84. 92
      website/zznomp/index.html
  85. 2798
      website/zznomp/key.html
  86. 50
      website/zznomp/pages/admin.html
  87. 11
      website/zznomp/pages/api.html
  88. 265
      website/zznomp/pages/getting_started.html
  89. 147
      website/zznomp/pages/home.html
  90. 28
      website/zznomp/pages/miner_stats.html
  91. 25
      website/zznomp/pages/mining_key.html
  92. 61
      website/zznomp/pages/payments.html
  93. 261
      website/zznomp/pages/stats.html
  94. 30
      website/zznomp/pages/tbs.html
  95. 60
      website/zznomp/pages/workers.html
  96. 100
      website/zznomp/static/admin.js
  97. BIN
      website/zznomp/static/favicon.png
  98. BIN
      website/zznomp/static/favicon/android-icon-144x144.png
  99. BIN
      website/zznomp/static/favicon/android-icon-192x192.png
  100. BIN
      website/zznomp/static/favicon/android-icon-36x36.png
  101. BIN
      website/zznomp/static/favicon/android-icon-48x48.png
  102. BIN
      website/zznomp/static/favicon/android-icon-72x72.png
  103. BIN
      website/zznomp/static/favicon/android-icon-96x96.png
  104. BIN
      website/zznomp/static/favicon/apple-icon-114x114.png
  105. BIN
      website/zznomp/static/favicon/apple-icon-120x120.png
  106. BIN
      website/zznomp/static/favicon/apple-icon-144x144.png
  107. BIN
      website/zznomp/static/favicon/apple-icon-152x152.png
  108. BIN
      website/zznomp/static/favicon/apple-icon-180x180.png
  109. BIN
      website/zznomp/static/favicon/apple-icon-57x57.png
  110. BIN
      website/zznomp/static/favicon/apple-icon-60x60.png
  111. BIN
      website/zznomp/static/favicon/apple-icon-72x72.png
  112. BIN
      website/zznomp/static/favicon/apple-icon-76x76.png
  113. BIN
      website/zznomp/static/favicon/apple-icon-precomposed.png
  114. BIN
      website/zznomp/static/favicon/apple-icon.png
  115. 2
      website/zznomp/static/favicon/browserconfig.xml
  116. BIN
      website/zznomp/static/favicon/favicon-16x16.png
  117. BIN
      website/zznomp/static/favicon/favicon-32x32.png
  118. BIN
      website/zznomp/static/favicon/favicon-96x96.png
  119. BIN
      website/zznomp/static/favicon/favicon.ico
  120. 41
      website/zznomp/static/favicon/manifest.json
  121. BIN
      website/zznomp/static/favicon/ms-icon-144x144.png
  122. BIN
      website/zznomp/static/favicon/ms-icon-150x150.png
  123. BIN
      website/zznomp/static/favicon/ms-icon-310x310.png
  124. BIN
      website/zznomp/static/favicon/ms-icon-70x70.png
  125. 145
      website/zznomp/static/home.js
  126. 13
      website/zznomp/static/kmdfavicon.svg
  127. BIN
      website/zznomp/static/komodo-logo-horizontal-01.png
  128. 13
      website/zznomp/static/logo.svg
  129. 34
      website/zznomp/static/main.js
  130. 247
      website/zznomp/static/miner_stats.js
  131. 1
      website/zznomp/static/nvd3.css
  132. 6
      website/zznomp/static/nvd3.js
  133. 84
      website/zznomp/static/payments.js
  134. BIN
      website/zznomp/static/pirate128.png
  135. BIN
      website/zznomp/static/skull.png
  136. BIN
      website/zznomp/static/skull256.png
  137. 143
      website/zznomp/static/stats.js
  138. 612
      website/zznomp/static/style.css
  139. 79
      website/zznomp/static/workers.js

20
coins/hush.json

@ -1,12 +1,12 @@
{
"name": "hush",
"symbol": "hush",
"algorithm": "equihash",
"peerMagic": "f9eee48d",
"txfee": 0.0001,
"privateChain": true,
"sapling": true,
"overwintered": true,
"requireShielding": true,
"disablecb": true
"name": "hush",
"symbol": "hush",
"algorithm": "equihash",
"peerMagic": "f9eee48d",
"txfee": 0.0001,
"privateChain": true,
"sapling": true,
"overwintered": true,
"requireShielding": true,
"disablecb": true
}

9
coins/wsb.json

@ -0,0 +1,9 @@
{
"name": "WSB",
"symbol": "WSB",
"algorithm": "equihash",
"txfee": 0.0001,
"peerMagic": "faa04bca",
"sapling": true,
"disablecb": true
}

2
libs/paymentProcessor.js

@ -300,7 +300,7 @@ function SetupForPool(logger, poolOptions, setupFinished) {
callback(true);
}
else {
var opid = result[4];
var opid = result[4];
opidCount++;
opids.push(opid);
logger.special(logSystem, logComponent, 'Shield balance ' + amount + ' ' + opid);

38
pool_configs/solo-wsb.json

@ -0,0 +1,38 @@
{
"enabled": false,
"coin": "wsb.json",
"address": "RWEBo1Yp4uGkeXPi1ZGQARfLPkGmoW1MwY",
"zAddress": "",
"tAddress": "RWEBo1Yp4uGkeXPi1ZGQARfLPkGmoW1MwY",
"walletInterval": 1,
"rewardRecipients": {},
"tlsOptions": { "enabled": false },
"paymentProcessing": { "enabled": false, "daemon": false },
"trackShares": { "disable": true },
"ports": {
"3333": {
"tls":false,
"diff": 0.001,
"varDiff": {
"minDiff": 0.001,
"maxDiff": 10000,
"targetTime": 15,
"retargetTime": 60,
"variancePercent": 30
}
}
},
"daemons": [{
"host": "127.0.0.1",
"port": 52043,
"user": "user",
"password": "pass"
}],
"p2p": {
"enabled": true,
"host": "127.0.0.1",
"port": 52042,
"disableTransactions": true
},
"mposMode": { "enabled": false }
}

86
website/default/index.html

@ -0,0 +1,86 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="shortcut icon" type="image/png" href="/static/hushfavicon.ico"/>
<link href='http://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.0.3/css/font-awesome.min.css">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/normalize/3.0.1/normalize.min.css">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/pure/0.4.2/pure-min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.4.5/d3.min.js"></script>
<script src="/static/nvd3.js"></script>
<link rel="stylesheet" href="/static/nvd3.css">
<script src="/static/main.js"></script>
<link rel="stylesheet" href="/static/style.css">
<title>hnomp</title>
</head>
<body>
<header>
<div class="home-menu pure-menu pure-menu-open pure-menu-horizontal">
<a class="pure-menu-heading hot-swapper" href="/"><i class="fa fa-home"></i>&nbsp;Home</a>
<ul>
<li class="{{? it.selected === 'getting_started' }}pure-menu-selected{{?}}">
<a class="hot-swapper" href="/getting_started">
<i class="fa fa-rocket"></i>&nbsp;
Getting Started
</a>
</li>
<li class="{{? it.selected === 'stats' }}pure-menu-selected{{?}}">
<a class="hot-swapper" href="/stats">
<i class="fa fa-bar-chart-o"></i>&nbsp;
Graph Stats
</a>
</li>
<li class="{{? it.selected === 'tbs' }}pure-menu-selected{{?}}">
<a class="hot-swapper" href="/tbs">
<i class="fa fa-table"></i>&nbsp;
Tab Stats
</a>
</li>
<li class="{{? it.selected === 'workers' }}pure-menu-selected{{?}}">
<a class="hot-swapper" href="/workers">
<i class="fa fa-cogs"></i>&nbsp;
Workers Stats
</a>
</li>
<li class="{{? it.selected === 'payments' }}pure-menu-selected{{?}}">
<a class="hot-swapper" href="/payments">
<i class="fa fa-bitcoin"></i>&nbsp;
Payments
</a>
</li>
<li class="{{? it.selected === 'api' }}pure-menu-selected{{?}}">
<a class="hot-swapper" href="/api">
<i class="fa fa-code"></i>&nbsp;
API
</a>
</li>
</ul>
</div>
</header>
<main>
{{=it.page}}
</main>
<footer>
&lt;3 🐸 &middot; <a href="https://git.hush.is/hush/hnomp" target="_blank">hnomp on our own Gitea</a>
</footer>
</body>
</html>

2798
website/default/key.html

File diff suppressed because it is too large

50
website/default/pages/admin.html

@ -0,0 +1,50 @@
<div>
<style>
#passwordForm, #adminCenter{
display: none;
}
#adminCenter{
display: flex;
flex-flow: row;
}
#leftMenu{
flex: 0 0 200px;
}
#editForm{
flex: 1 1 auto;
}
</style>
<form class="pure-form pure-form-stacked" id="passwordForm">
<fieldset>
<legend>Password</legend>
<input id="password" type="password" placeholder="Password">
<label for="remember" class="pure-checkbox">
<input id="remember" type="checkbox"> Stay Logged In
</label>
<button type="submit" class="pure-button pure-button-primary">Log In</button>
</fieldset>
</form>
<div id="adminCenter">
<div class="pure-menu pure-menu-open" id="leftMenu">
<a class="pure-menu-heading">Administration</a>
<ul>
<li id="addPool"><a href="#">Add Pool</a></li>
<li class="pure-menu-heading" id="poolList">Current Pools</li>
</ul>
</div>
<div id="editForm"></div>
</div>
<script src="/static/admin.js"></script>
</div>

11
website/default/pages/api.html

@ -0,0 +1,11 @@
<div style="margin: 18px;">
API - The API is work in progress and is subject to change during development.
<ul>
<li><a href="/api/stats">/api/stats</a> global pool stats</li>
<li><a href="/api/blocks">/api/blocks</a> global block stats</li>
<li><a href="/api/pool_stats">/api/pool_stats</a> - historical stats</li>
<li><a href="/api/payments">/api/payments</a> - payment history</li>
<li><a href="/api/worker_stats?taddr">/api/worker_stats?taddr</a> - historical time per pool json </li>
<li><a href="/api/live_stats">/api/live_stats</a> - live stats (websocket)</li>
</ul>
</div>

325
website/default/pages/getting_started.html

@ -0,0 +1,325 @@
<style>
#holder{
display: flex;
flex-direction: row;
}
.glow{
box-shadow: inset 0 0 12px 4px #ff6c00;
}
.hidden{
display: none !important;
}
#menu{
background-color: #3d3d3d;
min-width: 170px;
}
#menu > .menuHeader{
color: #e3f7ff;
border-bottom: 1px solid #7f878b;
font-size: 1.2em;
padding: 16px 16px 4px 15px;
}
.menuList{
transition-duration: 200ms;
}
.menuList > a:first-child{
margin-top: 10px;
}
.menuList > a{
display: inline-block;
color: #e3f7ff;
text-decoration: none;
padding: 7px;
padding-left: 25px;
width:40px;
}
.menuList > a:hover{
color: #f69b3a;
}
#main{
flex: 1 1 auto;
display: flex;
flex-direction: column;
margin: 18px;
}
.miningOption{
color: white;
/* display: flex;
flex: 1 1 auto;
flex-direction: row;
flex-wrap: wrap; */
min-height: 215px;
justify-content: center;
align-items: center;
text-decoration: none;
}
a.miningOption:hover{
color: #f69b3a;
}
.miningOption:first-child{
background-color: #0eafc7;
}
.miningOption:last-child{
background-color: #b064e1;
}
.miningOptionNum{
font-size: 6em;
padding-right: 20px;
width: 140px;
text-align: center;
}
.miningOptionInstructions{
flex: 1 1 auto;
padding:10px;
}
.miningOptionInstructions > div:first-child{
font-size: 2.4em;
}
.miningOptionInstructions > div:last-child{
margin-top: 20px;
font-size: 1.3em;
}
#orHolder{
height: 37px;
text-align: center;
}
#orLine{
border-bottom: 1px solid #c2cacf;
height: 19px;
margin-bottom: -13px;
}
#orText{
background-color: #ebf4fa;
color: #5c5c5c;
display: inline-block;
width: 35px;
font-style: italic;
}
#coinInfoBackground{
transition-duration: 400ms;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: black;
opacity: 0.0;
}
#coinInfo{
display: flex;
flex-direction: column;
color: white;
width: 750px;
min-height: 400px;
top: 50px;
left: 50%;
margin-left: -375px;
position: absolute;
background-color: #f06350;
}
#coinInfo .coinInfoName{
text-transform: capitalize;
}
#coinInfo > div:first-of-type{
font-size: 1.8em;
text-align: center;
margin-top: 40px;
margin-bottom: 35px;
}
#coinInfoRows{
display: flex;
flex-direction: row;
justify-content: center;
flex: 1 1 auto;
margin-bottom: 70px;
}
#coinInfoRows > div{
display: flex;
flex-direction: column;
justify-content: center;
}
#coinInfoRows > div > div{
padding: 3px;
}
#coinInfoRowKeys{
font-weight: bold;
padding-right: 30px;
}
#coinInfoRowKeys .coinInfoSubtle{
font-weight: normal;
}
#coinInfoRowValues{
}
#coinInfoClose{
position: absolute;
font-size: 3em;
top: 0;
right: 0;
width: 60px;
height: 60px;
text-align: center;
color: white;
text-decoration: none;
}
#coinInfoClose:hover{
color: #50f0e3;
}
</style>
<div id="holder">
<a href="#" class="miningOption" id="coinGlowTrigger">
<div class="miningOptionInstructions">
<div>Select a coin for connection details</div>
<div>Configurations for each coin are available for advanced miners</div>
</div>
</a>
<div id="menu">
{{? (function(){
if (!it.portalConfig.switching) return false;
for (var p in it.portalConfig.switching){
if (it.portalConfig.switching[p].enabled)
return true;
}
return false;
})()
}}
<div class="menuHeader">Coin-Switching Ports</div>
{{?}}
<div class="menuList">
{{ for (var p in it.portalConfig.switching){
if (!it.portalConfig.switching[p].enabled) continue;
var info = {
algo: p,
ports: {},
host: it.portalConfig.website.stratumHost
};
info.ports[it.portalConfig.switching[p].port] = {diff: it.portalConfig.switching[p].diff};
info = JSON.stringify(info).replace(/"/g, '&quot;');
}}
<a href="#" class="poolOption" data-info="{{=info}}">{{=p}}</a>
{{ } }}
</div>
<div class="menuHeader">Coins</div>
<div class="menuList" id="coinList">
{{ for(var pool in it.poolsConfigs) {
var info = JSON.stringify({
coin: it.poolsConfigs[pool].coin,
algo: it.poolsConfigs[pool].coin.algorithm,
ports: it.poolsConfigs[pool].ports,
host: it.portalConfig.website.stratumHost
}).replace(/"/g, '&quot;');
}}
<a href="#" class="poolOption" data-info="{{=info}}">{{=pool}} {{=Object.keys(it.poolsConfigs[pool].ports)[0]}}</a>
{{ } }}
</div>
</div>
<!-- <div id="main">
<a href="#" class="miningOption" id="nompAppDownload">
<div class="miningOptionNum">1.</div>
<div class="miningOptionInstructions">
<div>Download NOMP App</div>
<div>Our preconfigured app makes mining that easy</div>
</div>
</a>
<div id="orHolder">
<div id="orLine"></div>
<div id="orText">or</div>
</div>
<a href="#" class="miningOption" id="coinGlowTrigger">
<div class="miningOptionNum">2.</div>
<div class="miningOptionInstructions">
<div>Select a coin for connection details</div>
<div>Configurations for each coin are available for advanced miners</div>
</div>
</a>
</div> -->
</div>
<a href="#" id="coinInfoBackground" class="hidden"></a>
<div id="coinInfo" class="hidden">
<a href="#" id="coinInfoClose">×</a>
<div><span class="coinInfoName"></span> Configuration:</div>
<div id="coinInfoRows">
<div id="coinInfoRowKeys">
<div>Username:</div>
<div>Password:</div>
</div>
<div id="coinInfoRowValues">
<div id="coinInfoUsername"></div>
<div>anything</div>
</div>
</div>
</div>
<script>
function showCoinConfig(info){
var htmlKeys = '<div class="coinInfoData">Algorithm:</div>';
var htmlValues = '<div class="coinInfoData">' + info.algo + '</div>';
for (var port in info.ports){
htmlKeys += '<div class="coinInfoData">URL <span class="coinInfoSubtle">(difficulty ' + info.ports[port].diff + ')</span>:</div>';
htmlValues += '<div class="coinInfoData">stratum+tcp://' + info.host + ':' + port + '</div>';
}
if (info.coin)
$('#coinInfoUsername').text('your ' + info.coin.name + ' wallet address');
else
$('#coinInfoUsername').text('your public key');
$('.coinInfoData').remove();
$('#coinInfoRowKeys').append(htmlKeys);
$('#coinInfoRowValues').append(htmlValues);
}
$('#coinGlowTrigger').click(function(event){
event.preventDefault();
$('.menuList').addClass('glow');
setTimeout(function(){
$('.menuList').removeClass('glow');
}, 200);
return false;
});
$('.poolOption').click(function(event){
event.preventDefault();
showCoinConfig($(this).data('info'));
$('#coinInfoBackground,#coinInfo').removeClass('hidden');
$('#coinInfoBackground').css('opacity', 0.7);
return false;
});
$('#coinInfoBackground,#coinInfoClose').click(function(event){
event.preventDefault();
$('#coinInfoBackground,#coinInfo').addClass('hidden');
$('#coinInfoBackground').css('opacity', 0.0);
return false;
});
$('#nompAppDownload').click(function(event){
event.preventDefault();
alert('NOMP App development still in progress...');
return false;
});
</script>

132
website/default/pages/home.html

@ -0,0 +1,132 @@
<style>
#boxWelcome{
background-color: #0eafc7;
color: white;
margin: 18px;
}
#logoImg{
height: 285px;
margin: 55px;
}
#welcomeText{
font-size: 2.7em;
margin: 50px 18px 10px 18px;
}
#welcomeItems{
list-style-type: none;
font-size: 1.3em;
padding: 0 !important;
margin: 0 0 0 18px !important;
}
#welcomeItems > li{
margin: 30px !important;
}
#boxesLower {
margin: 0 9px;
}
#boxesLower > div {
display: flex;
}
#boxesLower > div > div {
flex: 1 1 auto;
margin: 0 9px 18px 9px;
padding: 10px;
display: flex;
flex-direction: column;
}
.boxLowerHeader{
font-size: 1.3em;
margin: 0 0 5px 10px;
}
#boxStatsLeft{
background-color: #b064e1;
}
#boxStatsRight{
background-color: #10bb9c;
}
.boxStats{
color: white;
}
.boxStatsList{
display: flex;
flex-flow: row wrap;
justify-content: space-around;
opacity: 0.77;
margin-bottom: 5px;
flex: 1 1 auto;
/* align-content: center; */
}
.boxStatsList i.fa{
height: 15px;
width: 33px;
text-align: center;
}
.boxStatsList > div{
padding: 5px 20px;
}
.boxStatsList > div > div{
padding: 3px;
}
</style>
<div class="pure-g-r" id="boxWelcome">
<img src="/static/hush-logo-horizontal-01.png" style="margin: 0 auto; height:150px;">
<div class="pure-u-1">
<div style="font-size: 2em; text-align:center; margin-bottom:10px;">HNOMP</div>
<div style="text-align:center; margin-bottom:10px;"">Low 1.5% fee! Min payouts of 1!</div>
</div>
</div>
<div class="pure-g-r" id="boxesLower">
<div class="pure-u-1">
<div class="boxStats" id="boxStatsLeft">
<div class="boxLowerHeader">Global Stats</div>
<div class="boxStatsList">
{{ for(var algo in it.stats.algos) { }}
<div>
<div><i class="fa fa-flask"></i>{{=algo}}</div>
<div><i class="fa fa-users"></i><span id="statsMiners{{=algo}}">{{=it.stats.algos[algo].workers}}</span> Miners</div>
<div><i class="fa fa-tachometer"></i><span id="statsHashrate{{=algo}}">{{=it.stats.algos[algo].hashrateString}}</span></div>
</div>
{{ } }}
</div>
</div>
</div>
<div class="pure-u-1">
<div class="boxStats" id="boxStatsRight">
<div class="boxLowerHeader">Pools / Coins</div>
<div class="boxStatsList">
{{ for(var pool in it.stats.pools) { }}
<div>
<div><i class="fa fa-dot-circle-o"></i>{{=pool}}</div>
<div><i class="fa fa-users"></i><span id="statsMiners{{=pool}}">{{=it.stats.pools[pool].workerCount}}</span> Miners</div>
<div><i class="fa fa-tachometer"></i><span id="statsHashrate{{=pool}}">{{=it.stats.pools[pool].hashrateString}}</span></div>
</div>
{{ } }}
</div>
</div>
</div>
</div>
<script>
$(function() {
statsSource.addEventListener('message', function (e) {
var stats = JSON.parse(e.data);
for (algo in stats.algos) {
$('#statsMiners' + algo).text(stats.algos[algo].workers);
$('#statsHashrate' + algo).text(stats.algos[algo].hashrateString);
}
for (var pool in stats.pools) {
$('#statsMiners' + pool).text(stats.pools[pool].workerCount);
$('#statsHashrate' + pool).text(stats.pools[pool].hashrateString);
}
});
});
</script>

105
website/default/pages/miner_stats.html

@ -0,0 +1,105 @@
<style>
#topCharts{
padding-left: 18px;
padding-right: 18px;
padding-top: 18px;
padding-bottom: 0px;
}
#topCharts > div > div > svg{
display: block;
height: 280px;
}
.chartWrapper{
border: solid 1px #c7c7c7;
border-radius: 5px;
padding: 5px;
margin-bottom: 18px;
}
.chartLabel{
font-size: 1.2em;
text-align: center;
padding: 4px;
}
.chartHolder{
}
#boxesWorkers {
margin: 0 9px;
}
#boxesWorkers > div {
display: flex;
}
#boxesWorkers > div > div {
flex: 1 1 auto;
margin: 0 9px 18px 9px;
padding: 10px;
display: flex;
flex-direction: column;
}
.boxLowerHeader{
font-size: 1.3em;
margin: 0 0 5px 10px;
}
#boxStatsLeft{
color: black;
background-color: #cccccc;
}
#boxStatsRight{
color: black;
background-color: #cccccc;
}
.boxStats{
color: white;
}
.boxStatsList{
display: flex;
flex-flow: row wrap;
justify-content: space-around;
opacity: 0.77;
margin-bottom: 5px;
flex: 1 1 auto;
align-content: center;
}
.boxStatsList i.fa{
height: 15px;
width: 33px;
text-align: center;
}
.boxStatsList > div{
padding: 5px 20px;
}
.boxStatsList > div > div{
padding: 3px;
}
</style>
<div id="topCharts">
<div class="chartWrapper">
<div class="chartLabel">
<!--<div style="float:left; padding-right: 18px;"><i class="fa fa-users"></i><span id="statsWorkers">...</span></div>-->
<div style="float:left; margin-right: 9px;">{{=String(it.stats.address).split(".")[0]}}</div>
<div style="float:right; padding-left: 18px;"><small><i class="fa fa-tachometer"></i> <span id="statsHashrateAvg">...</span> (Avg)</small></div>
<div style="float:right; padding-left: 18px;"><small><i class="fa fa-tachometer"></i> <span id="statsHashrate">...</span> (Now)</small></div>
<div style="float:right; padding-left: 18px;"><small><i class="fa fa-gavel"></i> Luck <span id="statsLuckDays">...</span> Days</small></div>
</div>
<div class="chartHolder"><svg id="workerHashrate" /></div>
<div>
<div style="float:right; padding-top: 9px; padding-right: 18px;"><i class="fa fa-cog"></i> Shares: <span id="statsTotalShares">...</span></div>
<div style="float:left; padding-top: 9px; padding-left: 18px; padding-right: 18px;"><i class="fa fa-money"></i> Immature: <span id="statsTotalImmature">...</span> </div>
<div style="float:left; padding-top: 9px; padding-left: 18px; padding-right: 18px;"><i class="fa fa-money"></i> Bal: <span id="statsTotalBal">...</span> </div>
<div style="padding-top: 9px; padding-left: 18px;"><i class="fa fa-money"></i> Paid: <span id="statsTotalPaid">...</span> </div>
</div>
</div>
</div>
<div id="boxesWorkers"> </div>
<script>
var _miner = "{{=String(it.stats.address).split(".")[0]}}";
var _workerCount = 0;
window.statsSource = new EventSource("/api/live_stats");
document.querySelector('main').appendChild(document.createElement('script')).src = '/static/miner_stats.js';
</script>

25
website/default/pages/mining_key.html

@ -0,0 +1,25 @@
<style>
#miningKeyPage{
margin: 15px;
}
#keyFrame{
padding: 0;
border: 0;
width: 100%;
height: 750px;
display: block;
}
</style>
<div id="miningKeyPage">
<p>
This script run client-side (in your browser). For maximum security <a href="/key.html" download="key.html">download</a> the script and run it locally and
offline in a modern web browser.
</p>
<iframe id="keyFrame" src="/key.html">
</iframe>
</div>

92
website/default/pages/payments.html

@ -0,0 +1,92 @@
<style>
#bottomNotes {
display: block;
padding-left: 18px;
padding-right: 18px;
padding-bottom: 18px;
}
#topPool {
padding-top: 18px;
padding-left: 18px;
padding-right: 18px;
}
#topPool > div > div > svg {
display: block;
height: 280px;
}
.poolWrapper {
border: solid 1px #c7c7c7;
border-radius: 5px;
padding: 5px;
margin-bottom: 18px;
}
.poolLabel {
font-size: 1.2em;
text-align: center;
padding: 4px;
}
.poolMinerTable {
}
table {
width: 100%;
}
table td {
padding: 6px 12px;
}
</style>
<script type="text/javascript">
$(function () {
$(document).tooltip({
content: function () {
return $(this).prop('title');
},
show: null,
close: function (event, ui) {
ui.tooltip.hover(
function () {
$(this).stop(true).fadeTo(400, 1);
},
function () {
$(this).fadeOut("400", function () {
$(this).remove();
})
});
}
});
});
</script>
{{ function readableDate(a){ return new Date(parseInt(a)).toISOString().substring(0, 16).replace('T', ' ') + ' UTC'; } }}
{{ for(var pool in it.stats.pools) { }}
<table class="puretable">
<thead>
<tr>
<th>Blocks</th>
<th>Time</th>
<th>Miners</th>
<th>Shares</th>
<th>Amount</th>
</tr>
</thead>
{{ for(var p in it.stats.pools[pool].payments) { }}
<tr>
<td style="max-width: 475px; word-wrap: break-word;">
{{if (String(it.stats.pools[pool].name) == 'kmd') { }}
<a href="https://kmdexplorer.io/tx/{{=it.stats.pools[pool].payments[p].txid}}" title="View transaction" target="_blank" rel="noopener noreferrer">{{=it.stats.pools[pool].payments[p].blocks}}</a>
{{ } else if (String(it.stats.pools[pool].name) == 'kmdice') { }}
<a href="http://kmdice.explorer.dexstats.info/tx/{{=it.stats.pools[pool].payments[p].txid}}" target="_blank" rel="noopener noreferrer">{{=it.stats.pools[pool].payments[p].blocks}}</a>
{{ } else { }}
{{=it.stats.pools[pool].payments[p].blocks}}
{{ } }}
</td>
<td>{{=readableDate(it.stats.pools[pool].payments[p].time)}}</td>
<td>{{=it.stats.pools[pool].payments[p].miners}}</td>
<td>{{=Math.round(it.stats.pools[pool].payments[p].shares)}}</td>
<td>{{=it.stats.pools[pool].payments[p].paid}} {{=it.stats.pools[pool].symbol}}</td>
</tr>
{{ } }}
</table>
</div>
{{ } }}

356
website/default/pages/stats.html

@ -0,0 +1,356 @@
<style>
#topCharts{
padding: 18px;
}
#topCharts > div > div > svg{
display: block;
height: 280px;
}
.chartWrapper{
border: solid 1px #c7c7c7;
border-radius: 5px;
padding: 5px;
margin-bottom: 18px;
}
.chartLabel{
font-size: 1.2em;
text-align: center;
padding: 4px;
}
#boxesLower {
margin: 0 9px;
}
#boxesLower > div {
display: flex;
}
#boxesLower > div > div {
flex: 1 1 auto;
margin: 0 9px 18px 9px;
padding: 10px;
display: flex;
flex-direction: column;
}
.boxLowerHeader{
font-size: 1.3em;
margin: 0 0 5px 10px;
}
#boxStatsLeft{
color: black;
background-color: #cccccc;
}
#boxStatsRight{
color: black;
background-color: #cccccc;
}
.boxStats{
color: white;
}
.boxStatsList{
display: flex;
flex-flow: row wrap;
justify-content: space-around;
opacity: 0.77;
margin-bottom: 5px;
flex: 1 1 auto;
align-content: center;
}
.boxStatsList i.fa{
height: 15px;
width: 33px;
text-align: center;
}
.boxStatsList > div{
padding: 5px 20px;
}
.boxStatsList > div > div{
padding: 3px;
}
div.tooltip {
position: absolute;
text-align: center;
width: 60px;
height: 28px;
padding: 2px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
#tooltip.hidden {
opacity: 0;
}
</style>
<div id="topCharts">
<div class="chartWrapper">
<div class="chartLabel">Pool Historical Hashrate</div>
<div class="chartHolder"><svg id="poolHashrate"/></div>
</div>
</div>
{{ function capitalizeFirstLetter(t){return t.charAt(0).toUpperCase()+t.slice(1)} }}
{{ function readableDate(a){ return new Date(parseInt(a)).toISOString().substring(0, 16).replace('T', ' ') + ' UTC'; } }}
<div class="pure-g-r" id="boxesLower">
{{ for(var pool in it.stats.pools) { }}
<div class="pure-u-1-2">
<div class="boxStats" id="boxStatsLeft">
<div class="boxLowerHeader">{{=it.stats.pools[pool].name}} Pool Stats</div>
<div class="boxStatsList">
<div>
<div><i class="fa fa-users"></i><span id="statsMiners{{=pool}}">{{=it.stats.pools[pool].minerCount}}</span> Miners</div>
<div><i class="fa fa-rocket"></i><span id="statsWorkers{{=pool}}">{{=it.stats.pools[pool].workerCount}}</span> Workers</div>
<div><i class="fa fa-tachometer"></i><span id="statsHashrate{{=pool}}">{{=it.stats.pools[pool].hashrateString}}</span> (Now)</div>
<div><i class="fa fa-tachometer"></i><span id="statsHashrateAvg{{=pool}}">...</span> (Avg)</div>
<div><i class="fa fa-gavel"></i>Luck <span id="statsLuckDays{{=pool}}">{{=it.stats.pools[pool].luckDays}}</span> Days</div>
</div>
</div>
</div>
</div>
<div class="pure-u-1-2">
<div class="boxStats" id="boxStatsRight">
<div class="boxLowerHeader">{{=it.stats.pools[pool].name}} Network Stats</div>
<div class="boxStatsList">
<div>
<div><i class="fa fa-bars" aria-hidden="true"></i><small>Block Height:</small> <span id="statsNetworkBlocks{{=pool}}">{{=it.stats.pools[pool].poolStats.networkBlocks}}</span></div>
<div><i class="fa fa-tachometer"></i><small>Network Hash/s:</small> <span id="statsNetworkSols{{=pool}}">{{=it.stats.pools[pool].poolStats.networkSolsString}}</span></div>
<div><i class="fa fa-unlock-alt" aria-hidden="true"></i><small>Difficulty:</small> <span id="statsNetworkDiff{{=pool}}">{{=it.stats.pools[pool].poolStats.networkDiff}}</span></div>
<div><i class="fa fa-users"></i><small>Node Connections:</small> <span id="statsNetworkConnections{{=pool}}">{{=it.stats.pools[pool].poolStats.networkConnections}}</span></div>
</div>
</div>
</div>
</div>
{{ } }}
</div>
{{ for(var pool in it.stats.pools) { }}
{{ var blockscomb = new Array; }}
<div class="pure-g-r" id="boxesLower">
<div class="pure-u-1-1">
<div class="boxStats" id="boxStatsRight">
<div class="boxLowerHeader">{{=it.stats.pools[pool].name}} Blocks Found &nbsp;&nbsp;
<span style="float:right;"><small>
<i class="fa fa-bars"></i> <span id="statsValidBlocks{{=pool}}">{{=it.stats.pools[pool].poolStats.validBlocks}}</span> Blocks &nbsp;&nbsp;
<i class="fa fa-money"></i> Paid: <span id="statsTotalPaid{{=pool}}">{{=(parseFloat(it.stats.pools[pool].poolStats.totalPaid)).toFixed(8)}}</span> {{=it.stats.pools[pool].symbol}}</small>&nbsp;&nbsp;</span>
</div>
<div class="boxStatsList" style="margin-top: 9px;">
<!--<div id="{{=it.stats.pools[pool].name}}NewBlocks"></div>-->
{{ for(var b in it.stats.pools[pool].pending.blocks) { }}
{{ var block = it.stats.pools[pool].pending.blocks[b].split(":"); }}
<div style="margin-bottom: 9px; background-color: #eeeeee; min-width:600px;" title="{{if (it.stats.pools[pool].pending.confirms && it.stats.pools[pool].pending.confirms[block[0]]) { }}{{if (it.stats.pools[pool].pending.confirms[block[0]] == 1) { }}Waiting for dPoW notarization{{} else if (it.stats.pools[pool].pending.confirms[block[0]] < it.poolsConfigs[pool].paymentProcessing.minConf*2) { }}Waiting for min confirmations{{ } else { }}Queued for payment{{ } }}{{ } else { }}Waiting for payment processor to review{{ } }}">
<i class="fa fa-bars"></i>
<small>Block:</small>
{{if (String(it.stats.pools[pool].name) == "kmd") { }}
<a href="https://kmdexplorer.io/blocks/{{=block[0]}}" target="_blank">{{=block[2]}}</a>
{{ } else if (String(it.stats.pools[pool].name) == "rkt") { }}
<a href="http://rkt.explorer.dexstats.info/block/{{=block[0]}}" target="_blank">{{=block[2]}}</a>
{{ } else if (String(it.stats.pools[pool].name) == "kmdice") { }}
<a href="http://kmdice.explorer.dexstats.info/block/{{=block[0]}}" target="_blank">{{=block[2]}}</a>
{{ } else { }}
{{=block[2]}}
{{ } }}
{{if (block[4] != null) { }}
<span style="padding-left: 18px;"><small>{{=readableDate(block[4])}}</small></span>
{{ } }}
{{if (it.stats.pools[pool].pending.confirms && it.stats.pools[pool].pending.confirms[block[0]]) { }}
{{if (it.stats.pools[pool].pending.confirms[block[0]] == 1) { }}
<span style="float:right; color: red;"><small>Waiting for Notarization</small></span>
{{ } else { }}
<span style="float:right; color: red;"><small>{{=it.stats.pools[pool].pending.confirms[block[0]]}} of {{=it.poolsConfigs[pool].paymentProcessing.minConf*2}} Confirmations</small></span>
{{ } }}
{{ } else { }}
<span style="float:right; color: red;"><small>*PENDING*</small></span>
{{ } }}
<div><i class="fa fa-gavel"></i><small>Mined By:</small> <a href="/workers/{{=block[3].split('.')[0]}}">{{=block[3].length > 40 ? block[3].substring(0, 20) + '...' + block[3].substring(block[3].length-20, block[3].length): block[3]}}</a></div>
</div>
{{ blockscomb.push(block);}}
{{ } }}
{{ var i=0; for(var b in it.stats.pools[pool].confirmed.blocks) { }}
{{ if (i < 8) { i++; }}
{{ var block = it.stats.pools[pool].confirmed.blocks[b].split(":"); }}
<div style="margin-bottom: 9px; background-color: #eeeeee; min-width:600px;"><i class="fa fa-bars"></i>
<small>Block:</small>
{{if (String(it.stats.pools[pool].name) == "kmd") { }}
<a href="https://kmdexplorer.io/blocks/{{=block[0]}}" target="_blank">{{=block[2]}}</a>
{{ } else if (String(it.stats.pools[pool].name).startsWith("rkt")) { }}
<a href="http://rkt.explorer.dexstats.info/block/{{=block[0]}}" target="_blank">{{=block[2]}}</a>
{{ } else if (String(it.stats.pools[pool].name).startsWith("kmdice")) { }}
<a href="http://kmdice.explorer.dexstats.info/block/{{=block[0]}}" target="_blank">{{=block[2]}}</a>
{{ } else { }}
{{=block[2]}}
{{ } }}
{{if (block[4] != null) { }}
<span style="padding-left: 18px;"><small>{{=readableDate(block[4])}}</small></span>
{{ } }}
<span style="float:right; padding-left: 18px; color: green;"><small>*PAID*</small></span>
<div><i class="fa fa-gavel"></i><small>Mined By:</small> <a href="/workers/{{=block[3].split('.')[0]}}">{{=block[3].length > 40 ? block[3].substring(0, 20) + '...' + block[3].substring(block[3].length-20, block[3].length): block[3]}}</a></div>
</div>
{{blockscomb.push(block);}}
{{ } }}
{{ } }}
{{if (blockscomb.length > 0) { }}
<!--{{=JSON.stringify(blockscomb)}}-->
<script>
var blockscomb = ({{=JSON.stringify(blockscomb)}})
</script>
{{ } }}
</div>
</div>
</div>
</div>
{{if (blockscomb.length > 0) { }}
<center><div id="bottomCharts{{=pool}}" style="text-align:center;" align="center">
<div class="chartWrapper" style="text-align:center;">
<div class="chartLabel">Finders of the last {{=blockscomb.length}} blocks</div>
<div class="hidden" id="tooltip{{=pool}}"><p><span id="value{{=pool}}"></span> blocks found by <span id="finderr{{=pool}}"></span></p></div>
<div class="chartHolder" id="pie{{=pool}}"><svg id="blocksPie{{=pool}}" style="display: block; margin: auto; text-align:center;"/></div>
</div>
</div></center>
<script>
var groupedByFinder = {};
var data = [];
for (var i=0; i < blockscomb.length; i++) {
finder=blockscomb[i][3]; // if other doesn 't already have a property for the current letter
// create it and assign it to a new empty array
if (!(finder in groupedByFinder))
groupedByFinder[finder] = [];
groupedByFinder[finder].push(blockscomb[i]);
}
Object.keys(groupedByFinder).forEach(function(i) {
var obj = {};
obj.label = i
obj.value = groupedByFinder[i].length
data.push(obj)
});
console.log(JSON.stringify(data))
var w = 400;
var h = 400;
var r = h/2;
var legendRectSize = 18;
var legendSpacing = 5;
var color = d3.scale.category20c();
var div = d3.select("#pie{{=pool}}").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var vis = d3.select('#blocksPie{{=pool}}')
.data([data])
.attr("width", 1000)
.attr("height", h)
.attr("style", "display: block; margin: auto;")
.attr("preserveAspectRatio", "xMidYMin")
.append("svg:g")
.attr("transform", "translate(" + r + "," + r + ")");
var pie = d3.layout.pie().value(function(d){return d.value;});
// declare an arc generator function
var arc = d3.svg.arc().outerRadius(r);
// select paths, use arc generator to draw
var arcs = vis.selectAll("g.slice{{=pool}}")
.data(pie)
.enter()
.append("svg:g")
.attr("class", "slice{{=pool}}")
.attr("id", "slice")
.on("mouseover", function(d){
d3.select("#tooltip{{=pool}}")
.style("left", d3.event.pageX + "px")
.style("top", d3.event.pageY + "px")
.style("opacity", 1)
.select("#value{{=pool}}")
.text(d.data.value);
d3.select("#tooltip{{=pool}}")
.select("#finderr{{=pool}}")
.text(d.data.label);
});
arcs.append("svg:path")
.attr("fill", function(d, i){
return color(i);
})
.attr("d", function (d) {
return arc(d);
});
var legend = vis.selectAll('.legend')
.data(color.domain())
.enter()
.append('g')
.attr('class', 'legend')
.attr('id', {{=JSON.stringify(pool)}})
.attr('transform', function(d, i) {
var height = legendRectSize + legendSpacing;
var offset = height * color.domain().length / 2;
var horz = 12 * legendRectSize;
var vert = i * height;
return 'translate(' + horz + ',' + vert + ')';
});
legend.append('rect')
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.style('fill', color)
.style('stroke', color);
legend.append('text')
.attr('x', legendRectSize + legendSpacing)
.attr('y', legendRectSize - legendSpacing)
.text(function(d, i) {
return data[i].label;
});
</script>
{{ } }}
{{ } }}
<script>
document.querySelector('main').appendChild(document.createElement('script')).src = '/static/stats.js';
$(function() {
window.statsSource = new EventSource("/api/live_stats");
statsSource.addEventListener('message', function (e) {
var stats = JSON.parse(e.data);
for (var pool in stats.pools) {
$('#statsMiners' + pool).text(stats.pools[pool].minerCount);
$('#statsWorkers' + pool).text(stats.pools[pool].workerCount);
$('#statsHashrate' + pool).text(stats.pools[pool].hashrateString);
$('#statsHashrateAvg' + pool).text(getReadableHashRateString(calculateAverageHashrate(pool)));
$('#statsLuckDays' + pool).text(stats.pools[pool].luckDays);
$('#statsValidBlocks' + pool).text(stats.pools[pool].poolStats.validBlocks);
$('#statsTotalPaid' + pool).text((parseFloat(stats.pools[pool].poolStats.totalPaid)).toFixed(8));
$('#statsNetworkBlocks' + pool).text(stats.pools[pool].poolStats.networkBlocks);
$('#statsNetworkDiff' + pool).text(stats.pools[pool].poolStats.networkDiff);
$('#statsNetworkSols' + pool).text(getReadableNetworkHashRateString(stats.pools[pool].poolStats.networkSols));
$('#statsNetworkConnections' + pool).text(stats.pools[pool].poolStats.networkConnections);
}
});
});
function getReadableNetworkHashRateString(hashrate){
hashrate = (hashrate * 1000000);
if (hashrate < 1000000)
return '0 Sol';
var byteUnits = [ ' Sol/s', ' KSol/s', ' MSol/s', ' GSol/s', ' TSol/s', ' PSol/s' ];
var i = Math.floor((Math.log(hashrate/1000) / Math.log(1000)) - 1);
hashrate = (hashrate/1000) / Math.pow(1000, i + 1);
return hashrate.toFixed(2) + byteUnits[i];
}
</script>

64
website/default/pages/tbs.html

@ -0,0 +1,64 @@
<style>
#topCharts {
padding: 18px;
}
#topCharts > div > div > svg {
display: block;
height: 280px;
}
.chartWrapper {
border: solid 1px #c7c7c7;
border-radius: 5px;
padding: 5px;
margin-bottom: 18px;
}
.chartLabel {
font-size: 1.2em;
text-align: center;
padding: 4px;
}
.chartHolder {
}
table {
width: 100%;
}
</style>
<table class="pure-table">
<thead>
<tr>
<th>Pool</th>
<th>Algo</th>
<th>Workers</th>
<th>Valid Shares</th>
<th>Invalid Shares</th>
<th>Total Blocks</th>
<th>Pending</th>
<th>Confirmed</th>
<th>Orphaned</th>
<th>Hashrate</th>
</tr>
</thead>
{{ for(var pool in it.stats.pools) { }}
<tr class="pure-table-odd">
<td>{{=it.stats.pools[pool].name}}</td>
<td>{{=it.stats.pools[pool].algorithm}}</td>
<td>{{=Object.keys(it.stats.pools[pool].workers).length}}</td>
<td>{{=it.stats.pools[pool].poolStats.validShares}}</td>
<td>{{=it.stats.pools[pool].poolStats.invalidShares}}</td>
<td>{{=it.stats.pools[pool].poolStats.validBlocks}}</td>
<td>{{=it.stats.pools[pool].blocks.pending}}</td>
<td>{{=it.stats.pools[pool].blocks.confirmed}}</td>
<td>{{=it.stats.pools[pool].blocks.orphaned}}</td>
<td>{{=it.stats.pools[pool].hashrateString}}</td>
</tr>
{{ } }}
</table>

94
website/default/pages/workers.html

@ -0,0 +1,94 @@
<style>
#bottomNotes {
display: block;
padding-left: 18px;
padding-right: 18px;
padding-bottom: 18px;
}
#topPool {
padding-top: 18px;
padding-left: 18px;
padding-right: 18px;
}
#topPool > div > div > svg {
display: block;
height: 280px;
}
.poolWrapper {
border: solid 1px #c7c7c7;
border-radius: 5px;
padding: 5px;
margin-bottom: 18px;
}
.poolLabel {
font-size: 1.2em;
text-align: center;
padding: 4px;
}
.poolMinerTable {
}
table {
width: 100%;
}
</style>
<script type="text/javascript">
function searchKeyPress(e)
{
// look for window.event in case event isn't passed in
e = e || window.event;
if (e.keyCode == 13)
{
document.getElementById('btnSearch').click();
return false;
}
return true;
}
$(document).ready(function(){
$('.btn-lg').click(function(){
window.location = "workers/" + $('.input-lg').val();
});
});
</script>
{{ function capitalizeFirstLetter(t){return t.charAt(0).toUpperCase()+t.slice(1)} }}
{{ var i=0; for(var pool in it.stats.pools) { }}
<div id="topPool">
<div class="poolWrapper">
<div class="poolLabel">
<span style="float:right; margin-bottom: 8px;">
<small>Miner Lookup:
<input type="text" class="form-control input-lg" onkeypress="return searchKeyPress(event);">
<span class="input-group-btn">
<button class="btn btn-default btn-lg" type="button">Lookup</button>
</span>
</small>
</span>
{{=capitalizeFirstLetter(it.stats.pools[pool].name)}} Top Miners &nbsp;&nbsp;
<small><i class="fa fa-users"></i> <span id="statsMiners{{=pool}}">{{=it.stats.pools[pool].minerCount}}</span> Miners &nbsp;&nbsp;
<i class="fa fa-rocket"></i> <span id="statsWorkers{{=pool}}">{{=it.stats.pools[pool].workerCount}}</span> Workers &nbsp;&nbsp;
<i class="fa fa-cog"></i> <span id="statsWorkers{{=pool}}">{{=it.stats.pools[pool].shareCount}}</span> Shares </small>
</div>
<div class="poolMinerTable">
<table class="pure-table">
<thead>
<tr>
<th>Address</th>
<th>Shares</th>
<th>Efficiency</th>
<th>Hashrate</th>
</tr>
</thead>
{{ for(var worker in it.stats.pools[pool].miners) { }}
{{var workerstat = it.stats.pools[pool].miners[worker];}}
<tr class="pure-table-odd">
<td><a href="/workers/{{=worker.split('.')[0]}}">{{=worker.length > 40 ? worker.substring(0, 20) + '...' + worker.substring(worker.length-20, worker.length): worker}}</a></td>
<td>{{=Math.round(workerstat.currRoundShares * 100) / 100}}</td>
<td>{{? workerstat.shares > 0}} {{=Math.floor(10000 * workerstat.shares / (workerstat.shares + workerstat.invalidshares)) / 100}}% {{??}} 0% {{?}}</td>
<td>{{=workerstat.hashrateString}}</td>
</tr>
{{ } }}
</table>
</div>
</div>
</div>
{{ } }}

100
website/default/static/admin.js

@ -0,0 +1,100 @@
var docCookies = {
getItem: function (sKey) {
return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null;
},
setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) {
if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { return false; }
var sExpires = "";
if (vEnd) {
switch (vEnd.constructor) {
case Number:
sExpires = vEnd === Infinity ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; max-age=" + vEnd;
break;
case String:
sExpires = "; expires=" + vEnd;
break;
case Date:
sExpires = "; expires=" + vEnd.toUTCString();
break;
}
}
document.cookie = encodeURIComponent(sKey) + "=" + encodeURIComponent(sValue) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + (bSecure ? "; secure" : "");
return true;
},
removeItem: function (sKey, sPath, sDomain) {
if (!sKey || !this.hasItem(sKey)) { return false; }
document.cookie = encodeURIComponent(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + ( sDomain ? "; domain=" + sDomain : "") + ( sPath ? "; path=" + sPath : "");
return true;
},
hasItem: function (sKey) {
return (new RegExp("(?:^|;\\s*)" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie);
}
};
var password = docCookies.getItem('password');
function showLogin(){
$('#adminCenter').hide();
$('#passwordForm').show();
}
function showAdminCenter(){
$('#passwordForm').hide();
$('#adminCenter').show();
}
function tryLogin(){
apiRequest('pools', {}, function(response){
showAdminCenter();
displayMenu(response.result)
});
}
function displayMenu(pools){
$('#poolList').after(Object.keys(pools).map(function(poolName){
return '<li class="poolMenuItem"><a href="#">' + poolName + '</a></li>';
}).join(''));
}
function apiRequest(func, data, callback){
var httpRequest = new XMLHttpRequest();
httpRequest.onreadystatechange = function(){
if (httpRequest.readyState === 4 && httpRequest.responseText){
if (httpRequest.status === 401){
docCookies.removeItem('password');
$('#password').val('');
showLogin();
alert('Incorrect Password');
}
else{
var response = JSON.parse(httpRequest.responseText);
callback(response);
}
}
};
httpRequest.open('POST', '/api/admin/' + func);
data.password = password;
httpRequest.setRequestHeader('Content-Type', 'application/json');
httpRequest.send(JSON.stringify(data));
}
if (password){
tryLogin();
}
else{
showLogin();
}
$('#passwordForm').submit(function(event){
event.preventDefault();
password = $('#password').val();
if (password){
if ($('#remember').is(':checked'))
docCookies.setItem('password', password, Infinity);
else
docCookies.setItem('password', password);
tryLogin();
}
return false;
});

BIN
website/default/static/favicon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 413 B

BIN
website/default/static/hush-logo-horizontal-01.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

BIN
website/default/static/hushfavicon.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

13
website/default/static/kmdfavicon.svg

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 72 72" style="enable-background:new 0 0 72 72;" xml:space="preserve">
<style type="text/css">
.st0{fill:#316565;}
.st1{fill:#FFFFFF;}
</style>
<rect x="0" y="0" class="st0" width="72" height="72"/>
<path class="st1" d="M35.9,65.4l20.8-8.5l8.7-20.8l-8.5-21L36.1,6.6l-20.8,8.5v0.2L6.6,36.1l8.5,20.8L35.9,65.4z M23,22.9L23,22.9
l13.1-5.5l13.1,5.5l5.5,13.1l-5.5,13.1l-13.1,5.5L23,49.2l-5.5-13.1L23,22.9z"/>
<polygon class="st1" points="36,46.9 43.7,43.7 46.9,35.9 43.7,28.3 36,25.1 28.4,28.3 25.2,35.9 28.2,43.7 "/>
</svg>

After

Width:  |  Height:  |  Size: 797 B

BIN
website/default/static/komodo-logo-horizontal-01.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

13
website/default/static/logo.svg

@ -0,0 +1,13 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" width="350px" height="350px" viewBox="0 0 350 350" enable-background="new 0 0 350 350" xml:space="preserve" xmlns:xml="http://www.w3.org/XML/1998/namespace">
<g>
<path fill="#F48438" d="M138,346H93c0,0-9,0-9-9s0-18,0-18h63c0,0,0,9,0,18S138,346,138,346z"/>
<path fill="#F48438" d="M255,346h-45c0,0-9,0-9-9s0-18,0-18h63c0,0,0,9,0,18S255,346,255,346z"/>
<path fill="#F48438" d="M30,139c0-63,105.099-79.872,143.186-80C210.458,58.875,318,76,318,139c0,0,0,84.71,0,153c0,27-27,27-27,27 H57c0,0-27,0-27-27V139z"/>
<path fill="#FFFFFF" d="M246,264.056c0,4.643-3.428,8.944-9.12,8.944H112.805c-5.691,0-10.805-4.301-10.805-8.944v-65.15 c0-4.643,5.114-7.906,10.805-7.906H236.88c5.691,0,9.12,3.264,9.12,7.906V264.056z"/>
<circle fill="#FFFFFF" cx="94.667" cy="141.667" r="20.333"/>
<circle fill="#FFFFFF" cx="252.667" cy="141.667" r="20.333"/>
<path fill="#F48438" d="M174.24,45.664c24.69-30.635,70.778-25.601,70.778-25.601l6.603,13.863c0,0-48.596-0.658-62.896,24.075 S149.551,76.3,174.24,45.664z"/>
<circle fill="#F48438" cx="259.083" cy="24.083" r="21.083"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

30
website/default/static/main.js

@ -0,0 +1,30 @@
$(function(){
var hotSwap = function(page, pushSate){
if (pushSate) history.pushState(null, null, '/' + page);
$('.pure-menu-selected').removeClass('pure-menu-selected');
$('a[href="/' + page + '"]').parent().addClass('pure-menu-selected');
$.get("/get_page", {id: page}, function(data){
$('main').html(data);
}, 'html')
};
$('.hot-swapper').click(function(event){
if (event.which !== 1) return;
var pageId = $(this).attr('href').slice(1);
hotSwap(pageId, true);
event.preventDefault();
return false;
});
window.addEventListener('load', function() {
setTimeout(function() {
window.addEventListener("popstate", function(e) {
hotSwap(location.pathname.slice(1));
});
}, 0);
});
window.statsSource = new EventSource("/api/live_stats");
});

246
website/default/static/miner_stats.js

@ -0,0 +1,246 @@
var workerHashrateData;
var workerHashrateChart;
var workerHistoryMax = 160;
var statData;
var totalHash;
var totalImmature;
var totalBal;
var totalPaid;
var totalShares;
function getReadableHashRateString(hashrate){
hashrate = (hashrate * 2);
if (hashrate < 1000000) {
return (Math.round(hashrate / 1000) / 1000 ).toFixed(2)+' Sol/s';
}
var byteUnits = [ ' Sol/s', ' KSol/s', ' MSol/s', ' GSol/s', ' TSol/s', ' PSol/s' ];
var i = Math.floor((Math.log(hashrate/1000) / Math.log(1000)) - 1);
hashrate = (hashrate/1000) / Math.pow(1000, i + 1);
return hashrate.toFixed(2) + byteUnits[i];
}
function timeOfDayFormat(timestamp){
var dStr = d3.time.format('%I:%M %p')(new Date(timestamp));
if (dStr.indexOf('0') === 0) dStr = dStr.slice(1);
return dStr;
}
function getWorkerNameFromAddress(w) {
var worker = w;
if (w.split(".").length > 1) {
worker = w.split(".")[1];
if (worker == null || worker.length < 1) {
worker = "noname";
}
} else {
worker = "noname";
}
return worker;
}
function buildChartData(){
var workers = {};
for (var w in statData.history) {
var worker = getWorkerNameFromAddress(w);
var a = workers[worker] = (workers[worker] || {
hashrate: []
});
for (var wh in statData.history[w]) {
a.hashrate.push([statData.history[w][wh].time * 1000, statData.history[w][wh].hashrate]);
}
if (a.hashrate.length > workerHistoryMax) {
workerHistoryMax = a.hashrate.length;
}
}
var i=0;
workerHashrateData = [];
for (var worker in workers){
workerHashrateData.push({
key: worker,
disabled: (i > Math.min((_workerCount-1), 3)),
values: workers[worker].hashrate
});
i++;
}
}
function updateChartData(){
var workers = {};
for (var w in statData.history) {
var worker = getWorkerNameFromAddress(w);
// get a reference to lastest workerhistory
for (var wh in statData.history[w]) { }
//var wh = statData.history[w][statData.history[w].length - 1];
var foundWorker = false;
for (var i = 0; i < workerHashrateData.length; i++) {
if (workerHashrateData[i].key === worker) {
foundWorker = true;
if (workerHashrateData[i].values.length >= workerHistoryMax) {
workerHashrateData[i].values.shift();
}
workerHashrateData[i].values.push([statData.history[w][wh].time * 1000, statData.history[w][wh].hashrate]);
break;
}
}
if (!foundWorker) {
var hashrate = [];
hashrate.push([statData.history[w][wh].time * 1000, statData.history[w][wh].hashrate]);
workerHashrateData.push({
key: worker,
values: hashrate
});
rebuildWorkerDisplay();
return true;
}
}
triggerChartUpdates();
return false;
}
function calculateAverageHashrate(worker) {
var count = 0;
var total = 1;
var avg = 0;
for (var i = 0; i < workerHashrateData.length; i++) {
count = 0;
for (var ii = 0; ii < workerHashrateData[i].values.length; ii++) {
if (worker == null || workerHashrateData[i].key === worker) {
count++;
avg += parseFloat(workerHashrateData[i].values[ii][1]);
}
}
if (count > total)
total = count;
}
avg = avg / total;
return avg;
}
function triggerChartUpdates(){
workerHashrateChart.update();
}
function displayCharts() {
nv.addGraph(function() {
workerHashrateChart = nv.models.lineChart()
.margin({left: 80, right: 30})
.x(function(d){ return d[0] })
.y(function(d){ return d[1] })
.useInteractiveGuideline(true);
workerHashrateChart.xAxis.tickFormat(timeOfDayFormat);
workerHashrateChart.yAxis.tickFormat(function(d){
return getReadableHashRateString(d);
});
d3.select('#workerHashrate').datum(workerHashrateData).call(workerHashrateChart);
return workerHashrateChart;
});
}
function updateStats() {
totalHash = statData.totalHash;
totalPaid = statData.paid;
totalBal = statData.balance;
totalImmature = statData.immature;
totalShares = statData.totalShares;
// do some calculations
var _blocktime = 250;
var _networkHashRate = parseFloat(statData.networkSols) * 1.2;
var _myHashRate = (totalHash / 1000000) * 2;
var luckDays = ((_networkHashRate / _myHashRate * _blocktime) / (24 * 60 * 60)).toFixed(3);
// update miner stats
$("#statsHashrate").text(getReadableHashRateString(totalHash));
$("#statsHashrateAvg").text(getReadableHashRateString(calculateAverageHashrate(null)));
$("#statsLuckDays").text(luckDays);
$("#statsTotalImmature").text(totalImmature);
$("#statsTotalBal").text(totalBal);
$("#statsTotalPaid").text(totalPaid);
$("#statsTotalShares").text(totalShares.toFixed(2));
}
function updateWorkerStats() {
// update worker stats
var i=0;
for (var w in statData.workers) { i++;
var htmlSafeWorkerName = w.split('.').join('_').replace(/[^\w\s]/gi, '');
var saneWorkerName = getWorkerNameFromAddress(w);
$("#statsHashrate"+htmlSafeWorkerName).text(getReadableHashRateString(statData.workers[w].hashrate));
$("#statsHashrateAvg"+htmlSafeWorkerName).text(getReadableHashRateString(calculateAverageHashrate(saneWorkerName)));
$("#statsLuckDays"+htmlSafeWorkerName).text(statData.workers[w].luckDays);
$("#statsPaid"+htmlSafeWorkerName).text(statData.workers[w].paid);
$("#statsBalance"+htmlSafeWorkerName).text(statData.workers[w].balance);
$("#statsShares"+htmlSafeWorkerName).text(Math.round(statData.workers[w].currRoundShares * 100) / 100);
$("#statsDiff"+htmlSafeWorkerName).text(statData.workers[w].diff);
}
}
function addWorkerToDisplay(name, htmlSafeName, workerObj) {
var htmlToAdd = "";
htmlToAdd = '<div class="boxStats" id="boxStatsLeft" style="float:left; margin: 9px; min-width: 260px;"><div class="boxStatsList">';
if (htmlSafeName.indexOf("_") >= 0) {
htmlToAdd+= '<div class="boxLowerHeader">'+htmlSafeName.substr(htmlSafeName.indexOf("_")+1,htmlSafeName.length)+'</div>';
} else {
htmlToAdd+= '<div class="boxLowerHeader">noname</div>';
}
htmlToAdd+='<div><i class="fa fa-tachometer"></i> <span id="statsHashrate'+htmlSafeName+'">'+getReadableHashRateString(workerObj.hashrate)+'</span> (Now)</div>';
htmlToAdd+='<div><i class="fa fa-tachometer"></i> <span id="statsHashrateAvg'+htmlSafeName+'">'+getReadableHashRateString(calculateAverageHashrate(name))+'</span> (Avg)</div>';
htmlToAdd+='<div><i class="fa fa-shield"></i> <small>Diff:</small> <span id="statsDiff'+htmlSafeName+'">'+workerObj.diff+'</span></div>';
htmlToAdd+='<div><i class="fa fa-cog"></i> <small>Shares:</small> <span id="statsShares'+htmlSafeName+'">'+(Math.round(workerObj.currRoundShares * 100) / 100)+'</span></div>';
htmlToAdd+='<div><i class="fa fa-gavel"></i> <small>Luck <span id="statsLuckDays'+htmlSafeName+'">'+workerObj.luckDays+'</span> Days</small></div>';
htmlToAdd+='<div><i class="fa fa-money"></i> <small>Bal: <span id="statsBalance'+htmlSafeName+'">'+workerObj.balance+'</span></small></div>';
htmlToAdd+='<div><i class="fa fa-money"></i> <small>Paid: <span id="statsPaid'+htmlSafeName+'">'+workerObj.paid+'</span></small></div>';
htmlToAdd+='</div></div></div>';
$("#boxesWorkers").html($("#boxesWorkers").html()+htmlToAdd);
}
function rebuildWorkerDisplay() {
$("#boxesWorkers").html("");
var i=0;
for (var w in statData.workers) { i++;
var htmlSafeWorkerName = w.split('.').join('_').replace(/[^\w\s]/gi, '');
var saneWorkerName = getWorkerNameFromAddress(w);
addWorkerToDisplay(saneWorkerName, htmlSafeWorkerName, statData.workers[w]);
}
}
// resize chart on window resize
nv.utils.windowResize(triggerChartUpdates);
// grab initial stats
$.getJSON('/api/worker_stats?'+_miner, function(data){
statData = data;
for (var w in statData.workers) { _workerCount++; }
buildChartData();
displayCharts();
rebuildWorkerDisplay();
updateStats();
});
// live stat updates
statsSource.addEventListener('message', function(e){
// TODO, create miner_live_stats...
// miner_live_stats will return the same josn except without the worker history
// FOR NOW, use this to grab updated stats
$.getJSON('/api/worker_stats?'+_miner, function(data){
statData = data;
// check for missing workers
var wc = 0;
var rebuilt = false;
// update worker stats
for (var w in statData.workers) { wc++; }
// TODO, this isn't 100% fool proof!
if (_workerCount != wc) {
if (_workerCount > wc) {
rebuildWorkerDisplay();
rebuilt = true;
}
_workerCount = wc;
}
rebuilt = (rebuilt || updateChartData());
updateStats();
if (!rebuilt) {
updateWorkerStats();
}
});
});

1
website/default/static/nvd3.css

File diff suppressed because one or more lines are too long

6
website/default/static/nvd3.js

File diff suppressed because one or more lines are too long

143
website/default/static/stats.js

@ -0,0 +1,143 @@
var poolHashrateData;
var poolHashrateChart;
var statData;
var poolKeys;
function buildChartData(){
var pools = {};
poolKeys = [];
for (var i = 0; i < statData.length; i++){
for (var pool in statData[i].pools){
if (poolKeys.indexOf(pool) === -1)
poolKeys.push(pool);
}
}
for (var i = 0; i < statData.length; i++) {
var time = statData[i].time * 1000;
for (var f = 0; f < poolKeys.length; f++){
var pName = poolKeys[f];
var a = pools[pName] = (pools[pName] || {
hashrate: []
});
if (pName in statData[i].pools){
a.hashrate.push([time, statData[i].pools[pName].hashrate]);
}
else{
a.hashrate.push([time, 0]);
}
}
}
poolHashrateData = [];
for (var pool in pools){
poolHashrateData.push({
key: pool,
values: pools[pool].hashrate
});
$('#statsHashrateAvg' + pool).text(getReadableHashRateString(calculateAverageHashrate(pool)));
}
}
function calculateAverageHashrate(pool) {
var count = 0;
var total = 1;
var avg = 0;
for (var i = 0; i < poolHashrateData.length; i++) {
count = 0;
for (var ii = 0; ii < poolHashrateData[i].values.length; ii++) {
if (pool == null || poolHashrateData[i].key === pool) {
count++;
avg += parseFloat(poolHashrateData[i].values[ii][1]);
}
}
if (count > total)
total = count;
}
avg = avg / total;
return avg;
}
function getReadableHashRateString(hashrate){
hashrate = (hashrate * 2);
if (hashrate < 1000000) {
return (Math.round(hashrate / 1000) / 1000 ).toFixed(2)+' Sol/s';
}
var byteUnits = [ ' Sol/s', ' KSol/s', ' MSol/s', ' GSol/s', ' TSol/s', ' PSol/s' ];
var i = Math.floor((Math.log(hashrate/1000) / Math.log(1000)) - 1);
hashrate = (hashrate/1000) / Math.pow(1000, i + 1);
return hashrate.toFixed(2) + byteUnits[i];
}
function timeOfDayFormat(timestamp){
var dStr = d3.time.format('%I:%M %p')(new Date(timestamp));
if (dStr.indexOf('0') === 0) dStr = dStr.slice(1);
return dStr;
}
function displayCharts(){
nv.addGraph(function() {
poolHashrateChart = nv.models.lineChart()
.margin({left: 80, right: 30})
.x(function(d){ return d[0] })
.y(function(d){ return d[1] })
.useInteractiveGuideline(true);
poolHashrateChart.xAxis.tickFormat(timeOfDayFormat);
poolHashrateChart.yAxis.tickFormat(function(d){
return getReadableHashRateString(d);
});
d3.select('#poolHashrate').datum(poolHashrateData).call(poolHashrateChart);
return poolHashrateChart;
});
}
function triggerChartUpdates(){
poolHashrateChart.update();
}
nv.utils.windowResize(triggerChartUpdates);
$.getJSON('/api/pool_stats', function(data){
statData = data;
buildChartData();
displayCharts();
});
statsSource.addEventListener('message', function(e){
var stats = JSON.parse(e.data);
statData.push(stats);
var newPoolAdded = (function(){
for (var p in stats.pools){
if (poolKeys.indexOf(p) === -1)
return true;
}
return false;
})();
if (newPoolAdded || Object.keys(stats.pools).length > poolKeys.length){
buildChartData();
displayCharts();
}
else {
var time = stats.time * 1000;
for (var f = 0; f < poolKeys.length; f++) {
var pool = poolKeys[f];
for (var i = 0; i < poolHashrateData.length; i++) {
if (poolHashrateData[i].key === pool) {
poolHashrateData[i].values.shift();
poolHashrateData[i].values.push([time, pool in stats.pools ? stats.pools[pool].hashrate : 0]);
$('#statsHashrateAvg' + pool).text(getReadableHashRateString(calculateAverageHashrate(pool)));
break;
}
}
}
triggerChartUpdates();
}
});

68
website/default/static/style.css

@ -0,0 +1,68 @@
html, button, input, select, textarea, .pure-g [class *= "pure-u"], .pure-g-r [class *= "pure-u"]{
font-family: 'Open Sans', sans-serif;
}
html{
background: #2d2d2d;
overflow-y: scroll;
}
body{
display: flex;
flex-direction: column;
max-width: 1160px;
margin: 0 auto;
}
header > .home-menu{
background: inherit !important;
height: 54px;
display: flex;
}
header > .home-menu > a.pure-menu-heading, header > .home-menu > ul, header > .home-menu > ul > li{
display: flex !important;
align-items: center;
justify-content: center;
line-height: normal !important;
}
header > .home-menu > a.pure-menu-heading{
color: white;
font-size: 1.5em;
}
header > .home-menu > ul > li > a{
color: #ced4d9;
}
header > .home-menu > ul > li > a:hover, header > .home-menu > ul > li > a:focus{
background: inherit !important;
}
header > .home-menu > ul > li > a:hover, header > .home-menu > ul > li.pure-menu-selected > a{
color: white;
}
main{
background-color: #ebf4fa;
position: relative;
}
footer{
text-align: center;
color: #b3b3b3;
text-decoration: none;
font-size: 0.8em;
padding: 15px;
line-height: 24px;
}
footer a{
color: #fff;
text-decoration: none;
}
footer iframe{
vertical-align: middle;
}

102
website/piratepool.io/index.html

@ -0,0 +1,102 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>piratepool.io - mining pool for PirateChain (ARRR) - the most private and anonymous mineable cryptocurrency - Pirate</title>
<meta name="description" content="The first and largest mining pool for PirateChain (ARRR). Low fees with 66% of proceeds donated to development and marketing efforts. The most private and anonymous cryptocurrency in existence is mineable here on the Equihash algorithm by CPU, GPU, ASIC, NiceHash. - Pirate">
<meta name="keywords" content="PirateChain,Pirate,ARRR,mining,pool,equihash,komodo,dpow,privacy,private,freedom">
<meta name="robots" content="index, follow">
<meta property="og:locale" content="en_EN">
<meta property="og:type" content="website">
<meta property="og:title" content="PiratePool.io - mining pool for PirateChain (ARRR) - the most private mineable cryptocurrency - Pirate">
<meta property="og:site_name" content="PiratePool.io - mining pool for PirateChain (ARRR)">
<meta property="og:description" content="The first and largest mining pool for PirateChain (ARRR). Low fees with 66% of proceeds donated to development and marketing efforts. The most private and anonymous cryptocurrency in existence is mineable here on the Equihash algorithm by CPU, GPU, ASIC, NiceHash. - Pirate">
<meta property="og:url" content="https://piratepool.io">
<meta property="og:image" content="https://piratepool.io/static/pirate128.png">
<meta property="og:image:secure_url" content="https://piratepool.io/static/pirate128.png">
<meta property="og:image:width" content="128">
<meta property="og:image:height" content="128">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:description" content="The first and largest mining pool for PirateChain (ARRR). Low fees with 66% of proceeds donated to development and marketing efforts. The most private and anonymous cryptocurrency in existence is mineable here on the Equihash algorithm by CPU, GPU, ASIC, NiceHash. - Pirate">
<meta name="twitter:title" content="PiratePool.io - mining pool for PirateChain (ARRR) - the most private mineable cryptocurrency - Pirate">
<meta name="twitter:site" content="@webworker01">
<meta name="twitter:image" content="https://piratepool.io/static/pirate128.png">
<meta name="twitter:creator" content="@webworker01">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Bai+Jamjuree|Roboto" />
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.3.1/css/all.css" integrity="sha384-mzrmE5qonljUremFsqc01SB46JvROS7bZs3IO2EmfFsd15uHvIt+Y8vEf7N7fWAU" crossorigin="anonymous" />
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/pure/1.0.0/base-min.css" integrity="sha256-XsW+lsCsaHybdLLnHWsTuwb9A2NuD2hVVlsxtiipTZQ=" crossorigin="anonymous" />
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/pure/1.0.0/pure-min.css" integrity="sha256-Q0zCrUs2IfXWYx0uMKJfG93CvF6oVII21waYsAV4/8Q=" crossorigin="anonymous" />
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/nvd3/1.8.6/nv.d3.min.css" integrity="sha256-bmrwGjHOoD7azP+ZpGcOOitUNUGNRjwzjK1bZeTK6fI=" crossorigin="anonymous" />
<link rel="stylesheet" href="/static/style.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js" integrity="sha256-dsOXGNHAo/syFnazt+KTBsCQeRmlcW1XKL0bCK4Baec=" crossorigin="anonymous"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/nvd3/1.8.6/nv.d3.min.js" integrity="sha256-Eg29ohiE9Hzc/t5whG/QK/B8MGmrO4wkF6WGuSsx0VU=" crossorigin="anonymous"></script>
<script src="/static/main.js"></script>
<link rel="shortcut icon" type="image/png" href="/static/pirate128.png"/>
<link rel="apple-touch-icon" sizes="57x57" href="/static/favicon/apple-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/static/favicon/apple-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/static/favicon/apple-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="/static/favicon/apple-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="/static/favicon/apple-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="/static/favicon/apple-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/static/favicon/apple-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/static/favicon/apple-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/static/favicon/apple-icon-180x180.png">
<link rel="icon" type="image/png" sizes="192x192" href="/static/favicon/android-icon-192x192.png">
<link rel="icon" type="image/png" sizes="32x32" href="/static/favicon/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="96x96" href="/static/favicon/favicon-96x96.png">
<link rel="icon" type="image/png" sizes="16x16" href="/static/favicon/favicon-16x16.png">
<link rel="manifest" href="/static/favicon/manifest.json">
<meta name="msapplication-TileColor" content="#BB9645">
<meta name="msapplication-TileImage" content="/static/favicon/ms-icon-144x144.png">
<meta name="theme-color" content="#BB9645">
<meta name="google-site-verification" content="JxkbxOT-aLGRVzTv8ES0RQ7EaWdSGZvOfZOUVmF1Xm8" />
</head>
<body>
<header>
<div class="home-menu pure-menu pure-menu-horizontal">
<ul class="pure-menu-list">
<li class="pure-menu-item {{? it.selected.length < 1 }}pure-menu-selected{{?}}">
<a class="pure-menu-link hot-swapper" href="/"><i class="fa fa-home"></i>Home</a>
</li>
<li class="pure-menu-item {{? it.selected === 'getting_started' }}pure-menu-selected{{?}}">
<a class="pure-menu-link hot-swapper" href="/getting_started"><i class="fas fa-rocket fa-fw"></i>Getting Started</a>
</li>
<li class="pure-menu-item {{? it.selected === 'stats' }}pure-menu-selected{{?}}">
<a class="pure-menu-link hot-swapper" href="/stats"><i class="fas fa-chart-bar fa-fw"></i>Pool Stats</a>
</li>
<!-- <li class="pure-menu-item {{? it.selected === 'tbs' }}pure-menu-selected{{?}}">
<a class="hot-swapper" href="/tbs"><i class="fas fa-table fa-fw"></i>Tab Stats</a>
</li> -->
<li class="pure-menu-item {{? it.selected === 'workers' }}pure-menu-selected{{?}}">
<a class="pure-menu-link hot-swapper" href="/workers"><i class="fas fa-cogs fa-fw"></i>Workers</a>
</li>
<li class="pure-menu-item {{? it.selected === 'payments' }}pure-menu-selected{{?}}">
<a class="pure-menu-link hot-swapper" href="/payments"><i class="fab fa-btc fa-fw"></i>Payments</a>
</li>
<li class="pure-menu-item {{? it.selected === 'api' }}pure-menu-selected{{?}}">
<a class="pure-menu-link hot-swapper" href="/api"><i class="fas fa-code fa-fw"></i>API</a>
</li>
</ul>
</div>
</header>
<main>
{{=it.page}}
</main>
<footer>
No warranties matey! If ye be 'aving any troubles, invoke yarrr right t' parlay at <!-- <a href="https://discord.gg/rZCXtCC" target="_blank" rel="noopener noreferrer" class="highlight">#pirate</a> --> <a href="https://discord.gg/ASMfX7B" target="_blank" rel="nofollow noreferrer noopener" class="highlight">#piratepool</a>
<br>
&lt;3 <a href="https://webworker.sh" alt="webworker01" target="_blank" rel="noopener noreferrer">🕷️</a> &middot; Built with <a href="https://github.com/webworker01/knomp" target="_blank" rel="noopener noreferrer" class="highlight">knomp</a>
</footer>
</body>
</html>

2798
website/piratepool.io/key.html

File diff suppressed because it is too large

50
website/piratepool.io/pages/admin.html

@ -0,0 +1,50 @@
<div>
<style>
#passwordForm, #adminCenter{
display: none;
}
#adminCenter{
display: flex;
flex-flow: row;
}
#leftMenu{
flex: 0 0 200px;
}
#editForm{
flex: 1 1 auto;
}
</style>
<form class="pure-form pure-form-stacked" id="passwordForm">
<fieldset>
<legend>Password</legend>
<input id="password" type="password" placeholder="Password">
<label for="remember" class="pure-checkbox">
<input id="remember" type="checkbox"> Stay Logged In
</label>
<button type="submit" class="pure-button pure-button-primary">Log In</button>
</fieldset>
</form>
<div id="adminCenter">
<div class="pure-menu pure-menu-open" id="leftMenu">
<a class="pure-menu-heading">Administration</a>
<ul>
<li id="addPool"><a href="#">Add Pool</a></li>
<li class="pure-menu-heading" id="poolList">Current Pools</li>
</ul>
</div>
<div id="editForm"></div>
</div>
<script src="/static/admin.js"></script>
</div>

11
website/piratepool.io/pages/api.html

@ -0,0 +1,11 @@
<div style="padding: 18px;">
API - The API is work in progress and is subject to change during development.
<ul>
<li><a href="/api/stats">/api/stats</a> global pool stats</li>
<li><a href="/api/blocks">/api/blocks</a> global block stats</li>
<li><a href="/api/pool_stats">/api/pool_stats</a> - historical stats</li>
<li><a href="/api/payments">/api/payments</a> - payment history</li>
<li><a href="/api/worker_stats?addr">/api/worker_stats?&lt;replace address here&gt;</a> - historical time per pool json </li>
<li><a href="/api/live_stats">/api/live_stats</a> - live stats (eventsource)</li>
</ul>
</div>

219
website/piratepool.io/pages/getting_started.html

@ -0,0 +1,219 @@
<div class="pure-g gettingStarted">
<div class="pure-u-1-4" style="display:flex; flex:2;">
<div class="pure-menu pure-menu-open gettingStartedMenu">
<h1 class="pure-menu-heading">Getting Started</h1>
<ul class="pure-menu-list">
<li class="pure-menu-item"><a href="#poolDetails" class="pure-menu-link">Pool Details</a></li>
<li class="pure-menu-item"><a href="#payments" class="pure-menu-link">Payout Information</a></li>
<li class="pure-menu-item"><a href="#createWallet" class="pure-menu-link">Create Wallet</a></li>
<li class="pure-menu-item"><a href="#gpuMining" class="pure-menu-link">GPU Mining Software</a></li>
<li class="pure-menu-item"><a href="#cpuMining" class="pure-menu-link">CPU Mining Software</a></li>
</ul>
</div>
</div>
<div class="pure-u-3-4 pure-responsive-disable">
{{? (function(){
if (!it.portalConfig.switching) return false;
for (var p in it.portalConfig.switching){
if (it.portalConfig.switching[p].enabled)
return true;
}
return false;
})()
}}
<div class="menuHeader">Coin-Switching Ports</div>
{{?}}
<div class="menuList">
{{ for (var p in it.portalConfig.switching){
if (!it.portalConfig.switching[p].enabled) continue;
var info = {
algo: p,
ports: {},
host: it.portalConfig.website.stratumHost
};
info.ports[it.portalConfig.switching[p].port] = {diff: it.portalConfig.switching[p].diff};
info = JSON.stringify(info).replace(/"/g, '&quot;');
}}
<a href="#" class="poolOption" data-info="{{=info}}">{{=p}}</a>
{{ } }}
</div>
<h1 class="menuHeader" id="poolDetails">Miner Configuration</h1>
<div class="menuList" id="coinList">
{{ if (it.portalConfig.gettingStartedPopups) { }}
{{ for (var pool in it.poolsConfigs) {
var info = JSON.stringify({
coin: it.poolsConfigs[pool].coin,
algo: it.poolsConfigs[pool].coin.algorithm,
ports: it.poolsConfigs[pool].ports,
host: it.portalConfig.website.stratumHost
}).replace(/"/g, '&quot;');
}}
<a href="#" class="poolOption" data-info="{{=info}}">{{=pool}}</a>
{{ } }}
{{ } else { }}
{{ for (var pool in it.poolsConfigs) { }}
{{if (String(pool) == 'pirate') { continue; } }}
<code>
<h2 class="coinInfoHeader">{{=it.poolsConfigs[pool].coin.name}} Configuration:</h2>
<p class="highlight">&#161;&#161;&#161;Do not mine to an exchange address!!! <a href="#createWallet">Create a wallet to mine to!</a></p>
<table style="margin-top:10px;">
<tr>
<td>Username: </td>
<td>{{ if (it.poolsConfigs[pool].coin && it.poolsConfigs[pool].coin.privateChain) { }}
your {{=it.poolsConfigs[pool].coin.name}} <span class="highlight">zs1</span> sapling address
{{ } else if (it.poolsConfigs[pool].coin) { }}
your {{=it.poolsConfigs[pool].coin.name}} wallet address
{{ } else { }}
your public key
{{ } }}
</td>
</tr>
<tr>
<td>Password: </td>
<td>anything</td>
</tr>
<tr>
<td>Algorithm: </td>
<td>{{=it.poolsConfigs[pool].coin.algorithm}}</td>
</tr>
{{ for (var port in it.poolsConfigs[pool].ports) { }}
<tr>
<td class="coinInfoData">{{= it.poolsConfigs[pool].ports[port].label ? it.poolsConfigs[pool].ports[port].label : 'URL'}} <span class="muted">(diff {{=it.poolsConfigs[pool].ports[port].diff}})</span>: </td>
<td>stratum+tcp://{{=it.portalConfig.website.stratumHost}}:{{=port}}</td>
</tr>
{{ } }}
</table>
</code>
{{ } }}
<div class="gettingStartedContent">
If you have multiple mining rigs you can add a label at the end of your username to see stats broken down by rig on the worker stats page.
</div>
<code>
<h3 class="coinInfoHeader">DSTM</h3>
zm --server {{=it.portalConfig.website.stratumHost}} --port {{= Object.keys(it.poolsConfigs[Object.keys(it.poolsConfigs)[0]].ports)[0] }} --user zs1nrn7h684wq4429pz8a20r49dmmhd3ey07u38f8m2n9du33ashd0xcnls3lfz0spdvn26z3r4jrv<span class="highlight">.myrigname</span> --pass x -dev 0 1 --temp-target=0:70,1:70 --intensity=0:0.5,1:0.5 --color --time
</code>
<code>
<h3 class="coinInfoHeader">EWBF</h3>
miner --server {{=it.portalConfig.website.stratumHost}} --user zs1nrn7h684wq4429pz8a20r49dmmhd3ey07u38f8m2n9du33ashd0xcnls3lfz0spdvn26z3r4jrv<span class="highlight">.myrigname</span> --pass x --port {{= Object.keys(it.poolsConfigs[Object.keys(it.poolsConfigs)[0]].ports)[0] }} --fee 0 --pec --templimit 70 --intensity 50
</code>
<code>
<h3 class="coinInfoHeader">Bminer</h3>
bminer -uri stratum://zs1nrn7h684wq4429pz8a20r49dmmhd3ey07u38f8m2n9du33ashd0xcnls3lfz0spdvn26z3r4jrv<span class="highlight">.myrigname</span>@{{=it.portalConfig.website.stratumHost}}:{{= Object.keys(it.poolsConfigs[Object.keys(it.poolsConfigs)[0]].ports)[0] }} -max-temperature 70 -nofee
</code>
<code>
<h3 class="coinInfoHeader">Claymore's</h3>
ZecMiner64.exe -zpool {{=it.portalConfig.website.stratumHost}}:{{= Object.keys(it.poolsConfigs[Object.keys(it.poolsConfigs)[0]].ports)[0] }} -zwal zs1nrn7h684wq4429pz8a20r49dmmhd3ey07u38f8m2n9du33ashd0xcnls3lfz0spdvn26z3r4jrv<span class="highlight">.myrigname</span> -zpsw x -allpools 1
</code>
<code>
<h3 class="coinInfoHeader">Optiminer</h3>
optiminer-zcash -s {{=it.portalConfig.website.stratumHost}}:{{= Object.keys(it.poolsConfigs[Object.keys(it.poolsConfigs)[0]].ports)[0] }} -u zs1nrn7h684wq4429pz8a20r49dmmhd3ey07u38f8m2n9du33ashd0xcnls3lfz0spdvn26z3r4jrv<span class="highlight">.myrigname</span> -p x
</code>
{{ } }}
</div>
<h1 class="menuHeader" id="payments">Payments</h1>
<div class="gettingStartedContent">
<p>Payouts are currently scheduled once every 4 hours with a minimum payout of 21 ARRR.</p>
<p>There is a limit of ~200 recipients that can be included in a single payout, so the pool payouts are monitored and the min payout adjusted accordingly to ensure a constant flow of payments.</p>
<p>If payments stop going out, do not worry! Funds are safu! Blocks can still be found and will be credited to your worker! Please check <!-- the <a href="https://discord.gg/rZCXtCC">#pools-and-operators channel in discord</a>--><a href="https://discord.gg/ASMfX7B" target="_blank" rel="nofollow noreferrer noopener" class="highlight">#piratepool in discord</a> to see if it's already being worked on.</p>
<p>Pending blocks have not yet been scanned by the payment processor. After being scanned, blocks will need to receive both <a href="https://komodoplatform.com/security-delayed-proof-of-work-dpow/" target="_blank" rel="noopener noreferrer">dPoW notarization</a> and 10 confirmations before being actually paid out.</p>
<p>On your worker stats page, <em class="highlight">pending</em> balance is the remaining estimated amount to be paid for blocks that
were scanned but not yet eligible for payout either because of
<a href="https://komodoplatform.com/new-feature-to-verify-dpow-notarizations/" target="_blank" rel="noopener noreferrer">dPoW</a> or min confirmations.
<em class="highlight">Balance</em> includes blocks that were scanned and already paid out but you have not yet met the min payout.<em class="highlight">*</em></p>
<p><em class="highlight">*Please note these 2 stats will only update when the payment processor runs which is currently every 4 hours.</em></p>
<p>Payments that show up on the payments page initially are in the process of constructing the z transaction. Once the transaction actually broadcasts to the network, the blocks paid out will become hyperlinked to the explorer and then should arrive in your wallet in the next block or two.</p>
</div>
<h1 class="menuHeader" id="createWallet">Generate Wallet and Address</h1>
<div class="gettingStartedContent">
<p><a href="https://medium.com/piratechain/pirateocean-wallet-guide-1cb80f70364c" target="_blank" rel="noopener noreferrer">The PirateOceanQT for PIRATE</a> is available. For wallet support please visit <a href="https://discord.gg/qReShun">#newpirates on Discord</a></p>
<h4>CLI Wallet:</h4>
<ol>
<li><a href="https://docs.komodoplatform.com/komodo/install-Komodo-manually.html" target="_blank">Build Komodo</a></li>
<li>Launch PIRATE chain:
<code>
./komodod -ac_name=PIRATE -ac_supply=0 -ac_reward=25600000000 -ac_halving=77777 -ac_private=1 -addnode=136.243.102.225
</code>
</li>
<li>Generate Z address:
<code>
./komodo-cli -ac_name=PIRATE z_getnewaddress
</code>
</li>
<li>Securely backup your private key:
<code>
./komodo-cli -ac_name=PIRATE z_exportkey "zaddr"
</code>
</li>
<li>Check your balance:
<code>
./komodo-cli -ac_name=PIRATE z_gettotalbalance
</code>
</li>
<li>
For more information visit the <a href="https://pirate.black/" target="_blank">project website</a>
</li>
</ol>
</div>
<h1 class="menuHeader" id="gpuMining">GPU Mining</h1>
<div class="gettingStartedContent">
<p>There are a few decent GPU miners available. You will need to experiment to find which one works best for you. DYOR on this and be sure to virus scan all the things!</p>
<p>Here are a couple well-known GPU miners:</p>
<ul>
<li><a href="https://bitcointalk.org/index.php?topic=2021765.0" target="_blank" rel="noopener noreferrer">dstm's ZCash / Equihash Nvidia Miner</a></li>
<li><a href="https://bitcointalk.org/index.php?topic=1707546.0" target="_blank" rel="noopener noreferrer">EWBF's CUDA Zcash miner 0.3.4b</a></li>
<li><a href="https://www.bminer.me/releases/" target="_blank" rel="noopener noreferrer">Bminer Lite</a></li>
<li><a href="https://bitcointalk.org/index.php?topic=1670733.0" target="_blank" rel="noopener noreferrer">Claymore's ZCash/BTG AMD GPU Miner</a></li>
<li><a href="https://github.com/Optiminer/OptiminerZcash" target="_blank" rel="noopener noreferrer">Optiminer AMD</a></li>
</ul>
</div>
<h1 class="menuHeader" id="cpuMining">CPU Mining</h1>
<div class="gettingStartedContent">
<p>While it is possible to CPU mine with <b>komodod</b> directly like so:</p>
<code>
./komodo-cli -ac_name=PIRATE setgenerate true
</code>
<p>The chances to find a block solo with CPU mining only are already fairly low and most likely the reason you are here at all 🐸</p>
<p>The well-known CPU miner that can be used with the pool is <b>nheqminer</b>. This does <i>not</i> require a Nicehash account and can be used to connect to any equihash stratum.</p>
<h4>Linux</h4>
<p>It is suggested that you attempt to build the CPU miner instead of using the pre-compiled binary so that optimizations for your CPU can be made during the build process</p>
<code>
sudo apt-get install cmake build-essential libboost-all-dev<br />
cd ~<br />
git clone -b Linux https://github.com/nicehash/nheqminer.git<br />
cd ~/nheqminer/cpu_xenoncat/Linux/asm/<br />
sh assemble.sh<br />
cd ~/nheqminer/Linux_cmake/nheqminer_cpu<br />
cmake . &amp;&amp; make<br />
sudo ln -s ~/nheqminer/Linux_cmake/nheqminer_cpu/nheqminer_cpu /usr/local/bin/nheqminer_cpu
</code>
<p>Now you can launch your miner! (replace the values as indicated changing the number of threads (-t) and your address for payouts (-u)</p>
<code>
nheqminer_cpu -t <i>numberofthreads</i> -l <i>stratumhost</i>:<i>stratumport</i> -u <i>youraddress</i>
</code>
<h4>Windows</h4>
<p>Download and install the latest release for windows from <a href="https://github.com/nicehash/nheqminer/releases" target="_blank" rel="noopener noreferrer">the github repo</a></p>
<p>Replace the placeholders below as needed and start mining!</p>
<code>
nheqminer -t <i>numberofthreads</i> -l <i>stratumhost</i>:<i>stratumport</i> -u <i>youraddress</i>
</code>
<h4>Additional Resources</h4>
<ul>
<li><a href="https://github.com/nicehash/nheqminer" target="_blank" rel="noopener noreferrer">nheqminer repo</a></li>
<li><a href="https://steemit.com/mining/@bobinson/zcash-cpu-mining-setup-on-linux" target="_blank" rel="noopener noreferrer">CPU Mining</a></li>
</ul>
</div>
</div>
</div>

98
website/piratepool.io/pages/home.html

@ -0,0 +1,98 @@
{{ function bigNumber(x){ return (x > 1000000000000) ? (x / 1000000000000).toFixed(1) + 'T' : (x > 1000000000) ? (x / 1000000000).toFixed(1) + 'B' : (x > 1000000) ? (x / 1000000).toFixed(1) + 'M' : (x > 1000) ? (x / 1000).toFixed(1) + 'K' : x.toFixed(1); } }}
<div>
<div class="alertbar">
<!-- Stop mining to exchange addresses&#8230; -->
<!-- 300K+ ARRR donated to Onboarding/Dev and Marketing funds, made possible via KMD notary node income.<br>
Thank you for all who voted me into KMD notary node for 2019 in SH! ❤ 🐸-->
<!-- New piratepool.io discord support and discussion channel created! <a href="https://discord.gg/ASMfX7B" target="_blank" rel="nofollow noreferrer noopener" class="highlight">join #piratepool</a> 🐸 -->
<!-- Payout strategy changed to PPLNT with 1 hour payout frequency! Join <a href="https://discord.gg/ASMfX7B" target="_blank" rel="nofollow noreferrer noopener" class="highlight">#piratepool</a> for support and discussion! 🐸 -->
Miner Privacy Enabled! Search for your miner with Miner Lookup. Join <a href="https://discord.gg/ASMfX7B" target="_blank" rel="nofollow noreferrer noopener" class="highlight">#piratepool</a> for support and discussion! 🐸
</div>
<div class="pure-g boxWelcome">
<div class="pure-u-1-3 pure-responsive-disable" style="display:flex; justify-content:center; align-items:center;">
<img src="/static/pirate128.png" style="width:128px; -webkit-filter: drop-shadow(-1px -1px 0 #000); filter: drop-shadow(-1px -1px 0 #000);" alt="piratepool.io - knomp" />
</div>
<div class="pure-u-2-3 pure-responsive-disable">
<h1 style="font-size: 2em; text-align:left; font-weight:900; color:#BB9645; margin:5px 0 10px;" class="textshadow">piratepool.io</h1>
<h2 style="color:#FFF; font-weight:900; font-size:1.5em; margin:0 0 10px;">Mining Pool For PirateChain (ARRR)</h2>
<p>
Donating 66% of the pool fee to the PirateChain project!<br>
<em>33% to PIRATE dev and <a href="https://dexstats.info/onboarding.php" target="_blank" rel="noopener noreferrer">onboarding</a> <a href="https://explorer.pirate.black/address/RAzq6y7dsUKgfuzNjpzyGiuFzvrwuDheQw" target="_blank" rel="noopener noreferrer">fund</a>
<br />
33% to <a href="https://explorer.pirate.black/address/RD5PhyAUhapsvj5ps2cCHozsXZfQSvDdrZ" target="_blank" rel="noopener noreferrer">PIRATE Marketing</a>!</em>
</p>
<table style="width: 100%; margin: 15px auto; text-align: left;">
<tr><td style="width:50%;">Algorithm: </td><td>Equihash</td></tr>
<tr><td>Payout Strategy: </td><td>PPLNT</td></tr>
<tr><td>Payout Frequency: </td><td>{{=it.poolsConfigs['arrr'].paymentProcessing.paymentInterval/60/60}} Hours</td></tr>
<tr><td>Min Payout: </td><td>{{=it.poolsConfigs['arrr'].paymentProcessing.minimumPayment}} ARRR</td></tr>
<tr><td>Pool Fee: </td><td>1%</td></tr>
</table>
<p>Pirate chain, the most private and anonymous cryptocurrency, is mineable here. Learn more:</p>
<div class="pure-g">
<div class="pure-u-1-2 pure-responsive-disable">
<a href="https://pirate.black/" target="_blank" rel="noopener noreferrer"><i class="fa fa-globe fa-fw"></i> Website</a><br />
<a href="https://github.com/PirateNetwork" target="_blank" rel="noopener noreferrer"><i class="fab fa-github fa-fw"></i> Github</a><br />
<a href="https://bitcointalk.org/index.php?topic=4979549" target="_blank" rel="noopener noreferrer"><i class="fab fa-bitcoin fa-fw"></i> Bitcoin Talk</a><br />
<a href="https://miningpoolstats.stream/piratechain" target="_blank" rel="noopener noreferrer"><i class="fas fa-swimmer"></i> Alternative Pools</a>
</div>
<div class="pure-u-1-2 pure-responsive-disable">
<a href="https://explorer.pirate.black" target="_blank" rel="noopener noreferrer"><i class="fas fa-map fa-fw"></i> Explorer</a><br />
<a href="https://discord.gg/qReShun" target="_blank" rel="noopener noreferrer"><i class="fab fa-discord fa-fw"></i> Discord</a><br />
<a href="https://twitter.com/PirateChain" target="_blank" rel="noopener noreferrer"><i class="fab fa-twitter fa-fw"></i> Twitter</a><br />
<a href="https://digitalprice.io/?inviter=4fdaf7" target="_blank" rel="noopener noreferrer"><i class="fas fa-chart-line fa-fw"></i> Trading at DigitalPrice.io</a>
</div>
</div>
</div>
</div>
<div style="max-width:640px; margin:10px auto; padding: 10px 10px 0;">
<p>
<a href="https://medium.com/piratechain/pirateocean-wallet-guide-1cb80f70364c" target="_blank" rel="noopener noreferrer">Download the latest PirateOcean wallet</a> and create a sapling address (<span class="highlight">starts with zs1</span>) and connect to the new stratum ports labeled as <strong><em>arrr</em></strong> on <a href="/getting_started" class="hot-swapper">Getting Started</a>.
</p>
<p>
{{ /* <span style="font-weight:900;">Sprout stratum has been retired! <a href="https://piratepool.io/static/sproutfinal.txt" target="_blank" style=" text-decoration:underline; text-decoration-color:#BB9645">Final Sprout Payouts Report</a></span> */ }}
</p>
<!-- <p>
You need to migrate sprout funds in your own zc wallet address by <span class="highlight">2019-02-01</span>. A quick guide on how to migrate can be <a href="https://github.com/PirateNetwork/docs/wiki/How-to-Migrate-Pirate-(ARRR)-from-sprout-address-to-sapling-address" target="_blank" rel="noopener noreferrer">found here</a>.
You could also try <a href="https://dexstats.info/pirateswap.php" target="_blank" rel="noopener noreferrer">this service to swap your coins</a>.
</p> -->
</div>
<div class="pure-g boxStats">
{{ for(var pool in it.stats.pools) { }}
<div class="pure-u-1-2 pure-responsive-disable">
<div class="l-box">
<h3>{{=it.stats.pools[pool].name}} Pool Stats</h3>
<div class="boxStatsList">
<ul>
<li><i class="fas fa-users fa-fw"></i> <span id="statsMiners{{=pool}}">{{=it.stats.pools[pool].minerCount}}</span> Miners</li>
<li><i class="fas fa-rocket fa-fw"></i> <span id="statsWorkers{{=pool}}">{{=it.stats.pools[pool].workerCount}}</span> Workers</li>
<li><i class="fas fa-tachometer-alt fa-fw"></i> <span id="statsHashrate{{=pool}}">{{=it.stats.pools[pool].hashrateString}}</span> (Now)</li>
<li><i class="fas fa-tachometer-alt fa-fw"></i> <span id="statsHashrateAvg{{=pool}}">...</span> (Avg)</li>
<li><i class="fas fa-dice fa-fw"></i> Luck <span id="statsLuckDays{{=pool}}">{{=it.stats.pools[pool].luckDays}}</span> Days</li>
</ul>
</div>
</div>
</div>
<div class="pure-u-1-2 pure-responsive-disable">
<div class="l-box">
<h3>{{=it.stats.pools[pool].name}} Network Stats</h3>
<div class="boxStatsList">
<ul>
<li><i class="fas fa-link fa-fw" aria-hidden="true"></i> Block Height: <span id="statsNetworkBlocks{{=pool}}">{{=it.stats.pools[pool].poolStats.networkBlocks}}</span></li>
<li><i class="fas fa-tachometer-alt fa-fw"></i> Network Hash/s: <span id="statsNetworkSols{{=pool}}">{{=it.stats.pools[pool].poolStats.networkSolsString}}</span></li>
<li><i class="fas fa-unlock-alt fa-fw" aria-hidden="true"></i> Difficulty: <span id="statsNetworkDiff{{=pool}}">{{=bigNumber(it.stats.pools[pool].poolStats.networkDiff)}}</span></li>
<!-- <li><i class="fas fa-coins fa-fw"></i> Total Supply: <span id="statsNetworkCoins{{=pool}}">{{=(it.stats.pools[pool].poolStats.networkBlocks*256).toLocaleString('en')}}</span></li> -->
<li><i class="fas fa-coins fa-fw"></i> Total Supply: <span id="statsNetworkCoins{{=pool}}">200,000,000</span></li>
<li><i class="fas fa-users fa-fw"></i> Node Connections: <span id="statsNetworkConnections{{=pool}}">{{=it.stats.pools[pool].poolStats.networkConnections}}</span></li>
</ul>
</div>
</div>
</div>
{{ } }}
</div>
<script>
document.querySelector('main').appendChild(document.createElement('script')).src = '/static/home.js';
</script>
</div>

34
website/piratepool.io/pages/miner_stats.html

@ -0,0 +1,34 @@
{{ function middleEllipsis(x) { return x.length > 40 ? x.substring(0, 20) + '...' + x.substring(x.length-20, x.length): x; } }}
{{ function checkCompromised(m) { var compromised = ['zs10jprfefpt2ra88u2ml96nzh3dmlqqqfeha5l7g0x0s0d2awme0eqfyt4w7r7pee0na8tcz6ezzj', 'zs12urwtysy5rkqzy3xgaxeu9g3ezf4fr0wfq44xrnf48uq6ug8qfxp059lms06khekppquvzadxyf', 'zs16sk9n6lyc8ulzkrf5xc72cr07hkyjvvj2emeqjel7xmn90qaf9mj2m8vt34yw45l7syqxlmfe5v', 'zs16xlsu48grwgsr29c9ztcn8jl0s47rtyucv3dw0n2e6y00w0wtt3d4ukqk4sq4sycrdhtxxg7g3k', 'zs19whs7s29a2kn5d4s8mpdad0m4setz86sq64kpv0t2v263mrqvuducp6nlmlwvynltam9zm9mr0p', 'zs1au66ft2gyu8ylgkw70vy4we2ktzum52esl94875w44mu8cmw2dcwfc29kahgmvfwcagwy39ctee', 'zs1c83zjak7ealmn92hejmqmjc7h3ysvglc9n95z79dhajth4fmhmrnv5zxdkufzg6l489y6hwf694', 'zs1d9myt9rpvu6grsl3ntg9wv0dfuj4vhp4rr0m3f940tt6fpxy8adpx4uzs7hgtclqtqe4wq2sjr8', 'zs1df3t2wpdmsjmzd7pwet67grfgr900fg6hjy97hl9vv0tkf7w5eye2zur6xhhzhfxdceu740g04g', 'zs1g342mavfn70xf5pycn8xwu2zsc4vq3fe8zzg99dfkdsdr39rqszvnuzxdp238d3uaqg96mmrclq', 'zs1gp9egrus6zrjqmea23nae7pzpxdy9jt3w65j8netsrcctl3g9e0lrag4tgvctw3r7rhryj4f4ua', 'zs1jttxxfwurarqw3cmkf94ygfs8skh7xxjf83wuh4awq6zjcee9p804p6aurmxv5q02f2uxc3qm93', 'zs1kqaakh9tw8uj039e9hzkh0444rw533uh8r5http8mfjuakmglqyqrjvd2ertnk8j9jlvvnzne9r', 'zs1lpp9qdtj9tkqjfj64wkcprvp2kflpu8cxz8fgclx80uuu4ajsmslkxkx0fh49cpw2yyhxwk0yzg', 'zs1pd047rvjf6es3ypx6vnl7vgnngmt3mkegn4vjtymfy26rxzp97mpjw5y2gkmyljmk99qs2wa4c0', 'zs1qsr5r8fp9scdz4wt08h4uxnlmefl0dmukuzxzs3f8wx6tk6ged399c9taphhx0asagryjkqgya7', 'zs1r4kfr08dm5yx60yg535dzhnpg8m8s4dl8ap42exkwm6699prpw9zu8sgj6xjd5efmrnj6p4u0an', 'zs1sfj20kyt95sfvll20lraw5q22q2aagw2r3pcdgtlaw4epc9sdwymxzdsge8c84f707ytqpjlnx4', 'zs1stzrmj7rfwr8g0hcsgs7aln0vxwcss6h7qfvzkyf9f6vuupeq6eqhrx7kwa0kmm5dawf7f9j8hr', 'zs1u7sy6prj270ucxwcwh9sh7vr33lnlgs6a95nt4hzgwxwvtcesu240px90822mffc0epf2kjlrjq', 'zs1ued52v4gv83yrguw4gpp4j85mtz9euedmwlszqmldl99cgefz8tz4y60ttjgm4avpqegyhnesns', 'zs1uhnyckurr2x4e8ak6ffqes4ggth8n2vxlzyksd8ufv9zltdhggdnxcx4q2jfn8tuea3f7w4yevs', 'zs1v569xvf7klgw8ylgf0dvtd92dtmu669xcqv05qvxud78nt4zwwcjdz046ghq7lvs4r0d227sgrv', 'zs1xl7l6sn0r5nsa6cex87yp3z7j2mj9jgf32dng6qqp7ym66s8wkx9lykmd896uq62e5xlq2mkaqq', 'zs1yxspuhm7fd5ffrjlmxtsyuryaj983paurt794rg87ln98ekdsugexl7kfvjw97ejhv66ytd3454', 'zs1yyeyhf856aag8vxlq4mkhjs8qjrlxfzz67s4jgjazpedrqfj62tr4zkp3tsj6cgc3hggq4t5raf', 'zs1z4aqxzy2krpvu45mfqes74a20yjmeuxlj0s4x89zr932panatzsfh8wf90qulh5683cgg9q0u2v']; return compromised.indexOf(m) > -1; } }}
<div id="pageMiner">
{{ if (checkCompromised(it.stats.address)) { }}
<div class="alertbar">
Your wallet address was possibly comporomised! Please visit <a href="https://discord.gg/ASMfX7B" target="_blank" rel="noopener noreferrer">discord</a> for more details!
</div>
{{ } }}
<div id="topCharts">
<div class="chartWrapper">
<div class="chartLabel">
<div class="workerStatsChartHeaderLeft" title="{{=String(it.stats.address)}}">{{=middleEllipsis(String(it.stats.address).split(".")[0])}}</div>
<div class="workerStatsChartHeaderRight"><i class="fas fa-tachometer-alt fa-fw"></i> <span id="statsHashrateAvg">...</span> (Avg)</div>
<div class="workerStatsChartHeaderRight"><i class="fas fa-tachometer-alt fa-fw"></i> <span id="statsHashrate">...</span> (Now)</div>
<div class="workerStatsChartHeaderRight"><i class="fas fa-dice fa-fw"></i> Luck <span id="statsLuckDays">...</span> Days</div>
</div>
<div class="chartHolder"><svg id="workerHashrate"></svg></div>
<div class="workerStatsChartFooter">
<div title="Lifetime Amount Paid"><i class="fas fa-money-bill-wave fa-fw"></i> Paid: <span id="statsTotalPaid">...</span></div>
<div title="Accrued Balance Waiting for Min-Payout"><i class="fas fa-piggy-bank fa-fw"></i> Balance: <span id="statsTotalBal">...</span></div>
<div title="Estimated Balance Waiting for dPoW/Min Confirmations"><i class="far fa-clock fa-fw"></i> Pending: <span id="statsTotalImmature">...</span></div>
<div title="Current Mining Round Shares"><i class="fas fa-cog fa-fw"></i> Shares: <span id="statsTotalShares">...</span></div>
</div>
</div>
</div>
<div id="boxesWorkers" class="pure-g boxStats"> </div>
<script>
var _miner = "{{=String(it.stats.address).split('.')[0]}}";
var _workerCount = 0;
document.querySelector('main').appendChild(document.createElement('script')).src = '/static/miner_stats.js';
</script>
</div>

25
website/piratepool.io/pages/mining_key.html

@ -0,0 +1,25 @@
<style>
#miningKeyPage{
margin: 15px;
}
#keyFrame{
padding: 0;
border: 0;
width: 100%;
height: 750px;
display: block;
}
</style>
<div id="miningKeyPage">
<p>
This script run client-side (in your browser). For maximum security <a href="/key.html" download="key.html">download</a> the script and run it locally and
offline in a modern web browser.
</p>
<iframe id="keyFrame" src="/key.html">
</iframe>
</div>

68
website/piratepool.io/pages/payments.html

@ -0,0 +1,68 @@
{{
function readableDate(a){
return new Date(parseInt(a)).toISOString().substring(0, 16).replace('T', ' ') + ' UTC';
}
function bigNumber(x){
return (x > 1000000000000) ? (x / 1000000000000).toFixed(1) + 'T' : (x > 1000000000) ? (x / 1000000000).toFixed(1) + 'B' : (x > 1000000) ? (x / 1000000).toFixed(1) + 'M' : (x > 1000) ? (x / 1000).toFixed(1) + 'K' : x.toFixed(1);
}
function timeTil(x){
return (x < 0) ? 'Now' : (x > 86400) ? (x/86400).toFixed(1) + ' Days' : (x > 3600) ? (x/3600).toFixed(1) + ' Hours' : (x > 60) ? (x / 60).toFixed(1) + ' Minutes' : x + ' Seconds';
}
function timeTilNumbers(timestamp) {
return new Date(timestamp * 1000).toISOString().substr(11, 8);
}
}}
<div id="pagePayments">
<div class="alertbar">
<!-- Payout frequency has been changed to 4 hours because miners have been mining to exchange addresses&#8230;-->
<!-- Block Reward Halving occured at block <a href="https://explorer.pirate.black/block/00000000004332fdca73719414e6e595c5f9f909bf39df5ff68f56b008b29790" target="_blank" rel="nofollow noreferrer noopener">388,885</a>!! Join <a href="https://discord.gg/ASMfX7B" target="_blank" rel="nofollow noreferrer noopener" class="highlight">#piratepool</a> for support and discussion! 🐸 -->
Payout strategy changed to PPLNT with 1 hour payout frequency! Join <a href="https://discord.gg/ASMfX7B" target="_blank" rel="nofollow noreferrer noopener" class="highlight">#piratepool</a> for support and discussion! 🐸
</div>
{{ for(var pool in it.stats.pools) { }}
<div class="poolLabel">
{{=it.stats.pools[pool].name}} Payments<span class="responsivehide"> &#160;&#160;</span><br class="responsiveonly" />
<small>
Lifetime<br class="responsiveonly" />
<i class="fas fa-link fa-fw"></i> <span id="statsValidBlocks{{=pool}}">{{=parseInt(it.stats.pools[pool].poolStats.validBlocks).toLocaleString('en')}}</span> Blocks Found<span class="responsivehide"> &#160;&#160;</span><br class="responsiveonly" />
<i class="fas fa-money-bill-wave fa-fw"></i> <span id="statsTotalPaid{{=pool}}">{{=parseInt(it.stats.pools[pool].poolStats.totalPaid).toLocaleString('en')}}</span> {{=it.stats.pools[pool].symbol}} Paid<span class="responsivehide"> &#160;&#160;</span><br class="responsiveonly" />
<i class="far fa-clock fa-fw"></i> Next Payment ETA <span id="statsNextPayment{{=pool}}" class="countdownTimer">{{=timeTil(it.poolsConfigs[pool].paymentProcessing.paymentInterval-parseInt((new Date().getTime() - parseInt(it.stats.pools[pool].payments[0].time))/1000))}}</span>
</small>
</div>
<table class="pure-table" id="paymentTable{{=pool}}">
<thead>
<tr>
<th>Blocks</th>
<th>Time</th>
<th>Miners</th>
<th>Shares</th>
<th>Amount</th>
</tr>
</thead>
<tbody>
{{ for(var p in it.stats.pools[pool].payments) { }}
<tr id="payment{{=pool}}{{=it.stats.pools[pool].payments[p].time}}">
<td class="paymentblocks{{if (it.stats.pools[pool].payments[p].blocks.length > 9) { }} paymentblocksexpand{{ } }}" title="Blocks:{{=it.stats.pools[pool].payments[p].blocks.length}} {{=it.stats.pools[pool].payments[p].opid}}">
<span class="responsiveTableLabel"><i class="fas fa-link fa-fw"></i></span> <span>Blocks: [{{=it.stats.pools[pool].payments[p].blocks.length}}] </span>
{{if (String(it.stats.pools[pool].name) == "KMD") { }}
<a href="https://kmdexplorer.io/tx/{{=it.stats.pools[pool].payments[p].txid}}" target="_blank" rel="noopener noreferrer">{{=it.stats.pools[pool].payments[p].blocks}}</a>
{{ } else if (typeof it.stats.pools[pool].payments[p].txid !== 'undefined' && (String(it.stats.pools[pool].name).startsWith("pirate") || String(it.stats.pools[pool].name).startsWith("arrr")) ) { }}
<a href="https://explorer.pirate.black/tx/{{=it.stats.pools[pool].payments[p].txid}}" target="_blank" rel="noopener noreferrer">{{=it.stats.pools[pool].payments[p].blocks}}</a>
{{ } else { }}
<a>{{=it.stats.pools[pool].payments[p].blocks}}</a>
{{ } }}
<div class="fade">&#9660;</div>
</td>
<td><span class="responsiveTableLabel"><i class="far fa-clock fa-fw"></i> Time: </span>{{=readableDate(it.stats.pools[pool].payments[p].time)}}</td>
<td><span class="responsiveTableLabel"><i class="fas fa-users fa-fw"></i> Miners: </span>{{=it.stats.pools[pool].payments[p].miners}}</td>
<td><span class="responsiveTableLabel"><i class="fas fa-cog fa-fw"></i> Shares: </span>{{=bigNumber(it.stats.pools[pool].payments[p].shares)}}</td>
<td><span class="responsiveTableLabel"><i class="fas fa-money-bill-wave fa-fw"></i> Amount: </span>{{=it.stats.pools[pool].payments[p].paid}} {{=it.stats.pools[pool].symbol}}</td>
</tr>
{{ } }}
</tbody>
</table>
{{ } }}
<script>
document.querySelector('main').appendChild(document.createElement('script')).src = '/static/payments.js';
</script>
</div>

112
website/piratepool.io/pages/stats.html

@ -0,0 +1,112 @@
{{ function capitalizeFirstLetter(t){return t.charAt(0).toUpperCase()+t.slice(1)} }}
{{ function readableDate(a){ return new Date(parseInt(a)).toISOString().substring(0, 16).replace('T', ' ') + ' UTC'; } }}
{{ function bigNumber(x){ return (x > 1000000000000) ? (x / 1000000000000).toFixed(1) + 'T' : (x > 1000000000) ? (x / 1000000000).toFixed(1) + 'B' : (x > 1000000) ? (x / 1000000).toFixed(1) + 'M' : (x > 1000) ? (x / 1000).toFixed(1) + 'K' : x.toFixed(1); } }}
{{ function middleEllipsis(x) { return x.length > 40 ? x.substring(0, 15) + '...' + x.substring(x.length-15, x.length): x; } }}
<div id="pageStats">
<div class="alertbar">
<!-- New piratepool.io discord support and discussion channel created! <a href="https://discord.gg/ASMfX7B" target="_blank" rel="nofollow noreferrer noopener" class="highlight">join #piratepool</a> 🐸 -->
<!-- Payout strategy changed to PPLNT with 1 hour payout frequency! Join <a href="https://discord.gg/ASMfX7B" target="_blank" rel="nofollow noreferrer noopener" class="highlight">#piratepool</a> for support and discussion! 🐸 -->
Miner Privacy Enabled! Search for your miner with Miner Lookup. Join <a href="https://discord.gg/ASMfX7B" target="_blank" rel="nofollow noreferrer noopener" class="highlight">#piratepool</a> for support and discussion! 🐸
</div>
<div id="topCharts">
<div class="chartWrapper">
<h1 class="chartLabel">Pool Hashrate</h1>
<div class="chartHolder"><svg id="poolHashrate"></svg></div>
</div>
</div>
<div class="pure-g boxStats">
{{ for(var pool in it.stats.pools) { }}
<div class="pure-u-1-2 pure-responsive-disable">
<div class="l-box">
<h3>{{=it.stats.pools[pool].name}} Pool Stats</h3>
<div class="boxStatsList">
<ul>
<li><i class="fas fa-users fa-fw"></i> <span id="statsMiners{{=pool}}">{{=it.stats.pools[pool].minerCount}}</span> Miners</li>
<li><i class="fas fa-rocket fa-fw"></i> <span id="statsWorkers{{=pool}}">{{=it.stats.pools[pool].workerCount}}</span> Workers</li>
<li><i class="fas fa-tachometer-alt fa-fw"></i> <span id="statsHashrate{{=pool}}">{{=it.stats.pools[pool].hashrateString}}</span> (Now)</li>
<li><i class="fas fa-tachometer-alt fa-fw"></i> <span id="statsHashrateAvg{{=pool}}">...</span> (Avg)</li>
<li><i class="fas fa-dice fa-fw"></i> Luck <span id="statsLuckDays{{=pool}}">{{=it.stats.pools[pool].luckDays}}</span> Days</li>
</ul>
</div>
</div>
</div>
<div class="pure-u-1-2 pure-responsive-disable">
<div class="l-box">
<h3>{{=it.stats.pools[pool].name}} Network Stats</h3>
<div class="boxStatsList">
<ul>
<li><i class="fas fa-link fa-fw" aria-hidden="true"></i> Block Height: <span id="statsNetworkBlocks{{=pool}}">{{=it.stats.pools[pool].poolStats.networkBlocks}}</span></li>
<li><i class="fas fa-tachometer-alt fa-fw"></i> Network Hash/s: <span id="statsNetworkSols{{=pool}}">{{=it.stats.pools[pool].poolStats.networkSolsString}}</span></li>
<li><i class="fas fa-unlock-alt fa-fw" aria-hidden="true"></i> Difficulty: <span id="statsNetworkDiff{{=pool}}">{{=bigNumber(it.stats.pools[pool].poolStats.networkDiff)}}</span></li>
<!-- <li><i class="fas fa-coins fa-fw"></i> Total Supply: <span id="statsNetworkCoins{{=pool}}">{{=(99554304+(it.stats.pools[pool].poolStats.networkBlocks-388884)*128).toLocaleString('en')}}</span></li> -->
<li><i class="fas fa-coins fa-fw"></i> Total Supply: <span id="statsNetworkCoins{{=pool}}">200,000,000</span></li>
<li><i class="fas fa-users fa-fw"></i> Node Connections: <span id="statsNetworkConnections{{=pool}}">{{=it.stats.pools[pool].poolStats.networkConnections}}</span></li>
</ul>
</div>
</div>
</div>
{{ } }}
</div>
{{ for(var pool in it.stats.pools) { }}
<div class="blocksFound" id="blocksFound{{=it.stats.pools[pool].name}}">
<div class="blocksFoundHeader">
<div>
{{=it.stats.pools[pool].name}} Recent Blocks Found (<span id="blocksFoundHeaderCount{{=it.stats.pools[pool].name}}">{{=it.stats.pools[pool].pending.blocks.length}}</span>)
</div>
<div>
Lifetime<span class="responsivehide"> &#160;&#160;</span><br class="responsiveonly" />
<i class="fas fa-link fa-fw"></i> <span id="statsValidBlocks{{=pool}}">{{=parseInt(it.stats.pools[pool].poolStats.validBlocks).toLocaleString('en')}}</span> Blocks Found<span class="responsivehide"> &#160;&#160;</span><br class="responsiveonly" />
<i class="fas fa-money-bill-wave fa-fw"></i> <span id="statsTotalPaid{{=pool}}">{{=parseInt(it.stats.pools[pool].poolStats.totalPaid).toLocaleString('en')}}</span> {{=it.stats.pools[pool].symbol}} Paid
</div>
</div>
<div class="blocksFoundList">
{{ for (var b in it.stats.pools[pool].pending.blocks) { }}
{{ var block = it.stats.pools[pool].pending.blocks[b].split(":"); }}
<div class="blocksFoundPending" id="blocksFoundPending{{=block[0]}}" title="{{if (it.stats.pools[pool].pending.confirms && it.stats.pools[pool].pending.confirms[block[0]]) { }}{{if (it.stats.pools[pool].pending.confirms[block[0]] == 1) { }}Waiting for dPoW notarization{{} else if (it.stats.pools[pool].pending.confirms[block[0]] < it.poolsConfigs[pool].paymentProcessing.minConf*2) { }}Waiting for min confirmations{{ } else { }}Queued for payment{{ } }}{{ } else { }}Waiting for payment processor to review{{ } }}">
<div>
<i class="fas fa-link fa-fw"></i>
<small>Block:</small>
<a href="https://explorer.pirate.black/block/{{=block[0]}}" target="_blank" rel="noopener noreferrer">{{=block[2]}}</a>
{{if (block[4] != null) { }}
<span><small>{{=readableDate(block[4])}}</small></span>
{{ } }}
{{if (it.stats.pools[pool].pending.confirms && it.stats.pools[pool].pending.confirms[block[0]]) { }}
{{if (it.stats.pools[pool].pending.confirms[block[0]] == 1) { }}
<span class="countLabel">Need dPoW</span>
{{ } else { }}
<span class="countLabel">{{=it.stats.pools[pool].pending.confirms[block[0]]}}/{{=it.poolsConfigs[pool].paymentProcessing.minConf*2}}</span>
{{ } }}
{{ } else { }}
<span class="countLabel">Pending</span>
{{ } }}
</div>
</div>
{{ } }}
{{ for(var i=0; i < 8; i++) { }}
{{ var block = it.stats.pools[pool].confirmed.blocks[i].split(":"); }}
<div class="blocksFoundPaid" id="blocksFoundPaid{{=block[0]}}" title="Payment sent, please check payments page">
<div>
<i class="fas fa-link fa-fw"></i>
<small>Block:</small>
<a href="https://explorer.pirate.black/block/{{=block[0]}}" target="_blank" rel="noopener noreferrer">{{=block[2]}}</a>
{{if (block[4] != null) { }}
<span><small>{{=readableDate(block[4])}}</small></span>
{{ } }}
<span class="countLabel">Paid</span>
</div>
</div>
{{ } }}
</div>
</div>
{{ } }}
<script>
document.querySelector('main').appendChild(document.createElement('script')).src = '/static/stats.js';
</script>
</div>

30
website/piratepool.io/pages/tbs.html

@ -0,0 +1,30 @@
<table class="pure-table">
<thead>
<tr>
<th>Pool</th>
<th>Algo</th>
<th>Workers</th>
<th>Valid Shares</th>
<th>Invalid Shares</th>
<th>Total Blocks</th>
<th>Pending</th>
<th>Confirmed</th>
<th>Orphaned</th>
<th>Hashrate</th>
</tr>
</thead>
{{ for(var pool in it.stats.pools) { }}
<tr>
<td>{{=it.stats.pools[pool].name}}</td>
<td>{{=it.stats.pools[pool].algorithm}}</td>
<td>{{=Object.keys(it.stats.pools[pool].workers).length}}</td>
<td>{{=it.stats.pools[pool].poolStats.validShares}}</td>
<td>{{=it.stats.pools[pool].poolStats.invalidShares}}</td>
<td>{{=it.stats.pools[pool].poolStats.validBlocks}}</td>
<td>{{=it.stats.pools[pool].blocks.pending}}</td>
<td>{{=it.stats.pools[pool].blocks.confirmed}}</td>
<td>{{=it.stats.pools[pool].blocks.orphaned}}</td>
<td>{{=it.stats.pools[pool].hashrateString}}</td>
</tr>
{{ } }}
</table>

56
website/piratepool.io/pages/workers.html

@ -0,0 +1,56 @@
{{ function capitalizeFirstLetter(t){return t.charAt(0).toUpperCase()+t.slice(1)} }}
{{ function bigNumber(x){ return (x > 1000000000000) ? (x / 1000000000000).toFixed(1) + 'T' : (x > 1000000000) ? (x / 1000000000).toFixed(1) + 'B' : (x > 1000000) ? (x / 1000000).toFixed(1) + 'M' : (x > 1000) ? (x / 1000).toFixed(1) + 'K' : x.toFixed(1); } }}
{{ function middleEllipsis(x) { return x.length > 40 ? x.substring(0, 20) + '...' + x.substring(x.length-20, x.length): x; } }}
<div id="pageWorkers">
<div class="alertbar">
Miner Privacy Enabled! Search for your miner with Miner Lookup. Join <a href="https://discord.gg/ASMfX7B" target="_blank" rel="nofollow noreferrer noopener" class="highlight">#piratepool</a> for support and discussion! 🐸
</div>
{{ var i=0; for(var pool in it.stats.pools) { }}
<div id="workers{{=pool}}">
<div class="poolLabel">
<span style="float:right;">
<small>Miner Lookup:
<input type="text" class="form-control input-lg" onkeypress="return searchKeyPress(event);" />
<span class="input-group-btn">
<button class="btn btn-default btn-lg" type="button">Lookup</button>
</span>
</small>
</span>
{{=capitalizeFirstLetter(it.stats.pools[pool].name)}} Top Miners<span class="responsivehide"> &#160;&#160;</span><br class="responsiveonly" />
<small>
<span title="Total number of miners"><i class="fas fa-users fa-fw"></i> <span id="statsMiners{{=pool}}">{{=it.stats.pools[pool].minerCount}}</span> Miners</span><span class="responsivehide"> &#160;&#160;</span>
<span title="Total number of workers"><i class="fas fa-rocket fa-fw"></i> <span id="statsWorkers{{=pool}}">{{=it.stats.pools[pool].workerCount}}</span> Workers</span><span class="responsivehide"> &#160;&#160;</span><br class="responsiveonly" />
<span title="Current Hashrate"><i class="fas fa-tachometer-alt fa-fw"></i> <span id="statsHashrate{{=pool}}">{{=it.stats.pools[pool].hashrateString}}</span></span><span class="responsivehide"> &#160;&#160;</span>
<span title="Current round total shares"><i class="fas fa-cog fa-fw"></i> <span id="statsShares{{=pool}}">{{=bigNumber(it.stats.pools[pool].shareCount)}}</span> Shares</span>
</small>
</div>
<table class="pure-table poolMinerTable">
<thead>
<tr>
<th>Miner</th>
<th>Shares</th>
<th>Efficiency</th>
<th>Hashrate</th>
</tr>
</thead>
<tbody>
{{ var minerindex = 0; }}
{{ for(var worker in it.stats.pools[pool].miners) { }}
{{ minerindex++; }}
{{var workerstat = it.stats.pools[pool].miners[worker];}}
<tr id="miner-{{=minerindex}}" data-hashrate="{{=workerstat.hashrate}}">
<td><span class="responsiveTableLabel"><i class="far fa-address-card fa-fw"></i></span>Miner #{{=minerindex}}</td>
<td><span class="responsiveTableLabel"><i class="fas fa-cog fa-fw"></i> Shares: </span><span>{{=bigNumber(workerstat.currRoundShares)}}</span></td>
<td><span class="responsiveTableLabel"><i class="fas fa-bullseye fa-fw"></i> Efficiency: </span><span>{{? workerstat.shares > 0}} {{=Math.floor(10000 * workerstat.shares / (workerstat.shares + workerstat.invalidshares)) / 100}}% {{??}} 0% {{?}}</span></td>
<td><span class="responsiveTableLabel"><i class="fas fa-tachometer-alt fa-fw"></i> Hashrate: </span><span>{{=workerstat.hashrateString}}</span></td>
</tr>
{{ } }}
</tbody>
</table>
</div>
{{ } }}
<script>
document.querySelector('main').appendChild(document.createElement('script')).src = '/static/workers.js';
</script>
</div>

100
website/piratepool.io/static/admin.js

@ -0,0 +1,100 @@
var docCookies = {
getItem: function (sKey) {
return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null;
},
setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) {
if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { return false; }
var sExpires = "";
if (vEnd) {
switch (vEnd.constructor) {
case Number:
sExpires = vEnd === Infinity ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; max-age=" + vEnd;
break;
case String:
sExpires = "; expires=" + vEnd;
break;
case Date:
sExpires = "; expires=" + vEnd.toUTCString();
break;
}
}
document.cookie = encodeURIComponent(sKey) + "=" + encodeURIComponent(sValue) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + (bSecure ? "; secure" : "");
return true;
},
removeItem: function (sKey, sPath, sDomain) {
if (!sKey || !this.hasItem(sKey)) { return false; }
document.cookie = encodeURIComponent(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + ( sDomain ? "; domain=" + sDomain : "") + ( sPath ? "; path=" + sPath : "");
return true;
},
hasItem: function (sKey) {
return (new RegExp("(?:^|;\\s*)" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie);
}
};
var password = docCookies.getItem('password');
function showLogin(){
$('#adminCenter').hide();
$('#passwordForm').show();
}
function showAdminCenter(){
$('#passwordForm').hide();
$('#adminCenter').show();
}
function tryLogin(){
apiRequest('pools', {}, function(response){
showAdminCenter();
displayMenu(response.result)
});
}
function displayMenu(pools){
$('#poolList').after(Object.keys(pools).map(function(poolName){
return '<li class="poolMenuItem"><a href="#">' + poolName + '</a></li>';
}).join(''));
}
function apiRequest(func, data, callback){
var httpRequest = new XMLHttpRequest();
httpRequest.onreadystatechange = function(){
if (httpRequest.readyState === 4 && httpRequest.responseText){
if (httpRequest.status === 401){
docCookies.removeItem('password');
$('#password').val('');
showLogin();
alert('Incorrect Password');
}
else{
var response = JSON.parse(httpRequest.responseText);
callback(response);
}
}
};
httpRequest.open('POST', '/api/admin/' + func);
data.password = password;
httpRequest.setRequestHeader('Content-Type', 'application/json');
httpRequest.send(JSON.stringify(data));
}
if (password){
tryLogin();
}
else{
showLogin();
}
$('#passwordForm').submit(function(event){
event.preventDefault();
password = $('#password').val();
if (password){
if ($('#remember').is(':checked'))
docCookies.setItem('password', password, Infinity);
else
docCookies.setItem('password', password);
tryLogin();
}
return false;
});

BIN
website/piratepool.io/static/favicon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 413 B

BIN
website/piratepool.io/static/favicon/android-icon-144x144.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
website/piratepool.io/static/favicon/android-icon-192x192.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

BIN
website/piratepool.io/static/favicon/android-icon-36x36.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
website/piratepool.io/static/favicon/android-icon-48x48.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
website/piratepool.io/static/favicon/android-icon-72x72.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
website/piratepool.io/static/favicon/android-icon-96x96.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
website/piratepool.io/static/favicon/apple-icon-114x114.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
website/piratepool.io/static/favicon/apple-icon-120x120.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

BIN
website/piratepool.io/static/favicon/apple-icon-144x144.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
website/piratepool.io/static/favicon/apple-icon-152x152.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
website/piratepool.io/static/favicon/apple-icon-180x180.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
website/piratepool.io/static/favicon/apple-icon-57x57.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
website/piratepool.io/static/favicon/apple-icon-60x60.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
website/piratepool.io/static/favicon/apple-icon-72x72.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
website/piratepool.io/static/favicon/apple-icon-76x76.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
website/piratepool.io/static/favicon/apple-icon-precomposed.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

BIN
website/piratepool.io/static/favicon/apple-icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

2
website/piratepool.io/static/favicon/browserconfig.xml

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig><msapplication><tile><square70x70logo src="/static/favicon/ms-icon-70x70.png"/><square150x150logo src="/static/favicon/ms-icon-150x150.png"/><square310x310logo src="/static/favicon/ms-icon-310x310.png"/><TileColor>#BB9645</TileColor></tile></msapplication></browserconfig>

BIN
website/piratepool.io/static/favicon/favicon-16x16.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 641 B

BIN
website/piratepool.io/static/favicon/favicon-32x32.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
website/piratepool.io/static/favicon/favicon-96x96.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
website/piratepool.io/static/favicon/favicon.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

41
website/piratepool.io/static/favicon/manifest.json

@ -0,0 +1,41 @@
{
"name": "App",
"icons": [
{
"src": "\/static\/favicon\/android-icon-36x36.png",
"sizes": "36x36",
"type": "image\/png",
"density": "0.75"
},
{
"src": "\/static\/favicon\/android-icon-48x48.png",
"sizes": "48x48",
"type": "image\/png",
"density": "1.0"
},
{
"src": "\/static\/favicon\/android-icon-72x72.png",
"sizes": "72x72",
"type": "image\/png",
"density": "1.5"
},
{
"src": "\/static\/favicon\/android-icon-96x96.png",
"sizes": "96x96",
"type": "image\/png",
"density": "2.0"
},
{
"src": "\/static\/favicon\/android-icon-144x144.png",
"sizes": "144x144",
"type": "image\/png",
"density": "3.0"
},
{
"src": "\/static\/favicon\/android-icon-192x192.png",
"sizes": "192x192",
"type": "image\/png",
"density": "4.0"
}
]
}

BIN
website/piratepool.io/static/favicon/ms-icon-144x144.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
website/piratepool.io/static/favicon/ms-icon-150x150.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
website/piratepool.io/static/favicon/ms-icon-310x310.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

BIN
website/piratepool.io/static/favicon/ms-icon-70x70.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

3
website/piratepool.io/static/home.js

@ -0,0 +1,3 @@
$(function() {
initStatData();
});

13
website/piratepool.io/static/kmdfavicon.svg

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 72 72" style="enable-background:new 0 0 72 72;" xml:space="preserve">
<style type="text/css">
.st0{fill:#316565;}
.st1{fill:#FFFFFF;}
</style>
<rect x="0" y="0" class="st0" width="72" height="72"/>
<path class="st1" d="M35.9,65.4l20.8-8.5l8.7-20.8l-8.5-21L36.1,6.6l-20.8,8.5v0.2L6.6,36.1l8.5,20.8L35.9,65.4z M23,22.9L23,22.9
l13.1-5.5l13.1,5.5l5.5,13.1l-5.5,13.1l-13.1,5.5L23,49.2l-5.5-13.1L23,22.9z"/>
<polygon class="st1" points="36,46.9 43.7,43.7 46.9,35.9 43.7,28.3 36,25.1 28.4,28.3 25.2,35.9 28.2,43.7 "/>
</svg>

After

Width:  |  Height:  |  Size: 797 B

BIN
website/piratepool.io/static/komodo-logo-horizontal-01.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

13
website/piratepool.io/static/logo.svg

@ -0,0 +1,13 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" width="350px" height="350px" viewBox="0 0 350 350" enable-background="new 0 0 350 350" xml:space="preserve" xmlns:xml="http://www.w3.org/XML/1998/namespace">
<g>
<path fill="#F48438" d="M138,346H93c0,0-9,0-9-9s0-18,0-18h63c0,0,0,9,0,18S138,346,138,346z"/>
<path fill="#F48438" d="M255,346h-45c0,0-9,0-9-9s0-18,0-18h63c0,0,0,9,0,18S255,346,255,346z"/>
<path fill="#F48438" d="M30,139c0-63,105.099-79.872,143.186-80C210.458,58.875,318,76,318,139c0,0,0,84.71,0,153c0,27-27,27-27,27 H57c0,0-27,0-27-27V139z"/>
<path fill="#FFFFFF" d="M246,264.056c0,4.643-3.428,8.944-9.12,8.944H112.805c-5.691,0-10.805-4.301-10.805-8.944v-65.15 c0-4.643,5.114-7.906,10.805-7.906H236.88c5.691,0,9.12,3.264,9.12,7.906V264.056z"/>
<circle fill="#FFFFFF" cx="94.667" cy="141.667" r="20.333"/>
<circle fill="#FFFFFF" cx="252.667" cy="141.667" r="20.333"/>
<path fill="#F48438" d="M174.24,45.664c24.69-30.635,70.778-25.601,70.778-25.601l6.603,13.863c0,0-48.596-0.658-62.896,24.075 S149.551,76.3,174.24,45.664z"/>
<circle fill="#F48438" cx="259.083" cy="24.083" r="21.083"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

208
website/piratepool.io/static/main.js

@ -0,0 +1,208 @@
//Set this to match config for payment countdown
var explorerURL = 'https://explorer.pirate.black/';
var minConfirmations = 10;
var paymentInterval = 14400;
var nextPaymentTimer;
var paymentTimerOn = false;
var poolHashrateData;
var poolHashrateChart;
var lastHashrateUpdate = {};
var statData;
var poolKeys;
$(function(){
initStatData();
var hotSwap = function(page, pushSate){
if (pushSate) history.pushState(null, null, '/' + page);
$('.pure-menu-selected').removeClass('pure-menu-selected');
$('a[href="/' + page + '"]').parent().addClass('pure-menu-selected');
$.get("/get_page", {id: page}, function(data){
$('main').html(data);
}, 'html')
};
$('body').on('click', '.hot-swapper', function(event) {
if (event.which !== 1) return;
var pageId = $(this).attr('href').slice(1);
hotSwap(pageId, true);
event.preventDefault();
return false;
});
window.addEventListener('load', function() {
setTimeout(function() {
window.addEventListener("popstate", function(e) {
if (location.hash.length == 0) {
hotSwap(location.pathname.slice(1));
}
});
}, 0);
});
window.statsSource = new EventSource("/api/live_stats");
statsSource.addEventListener('message', function (e) {
var stats = JSON.parse(e.data);
var statpush = {};
//Slim down the data we save to statData
for (var pool in stats.pools) {
statpush[pool] = {hashrate: stats.pools[pool].hashrate, workerCount: stats.pools[pool].workerCount, blocks: stats.pools[pool].blocks};
}
statData.push({time:stats.time, pools: statpush});
statData.shift(); // remove old unused record
for (var pool in stats.pools) {
$('#statsMiners' + pool).text(stats.pools[pool].minerCount);
$('#statsWorkers' + pool).text(stats.pools[pool].workerCount);
$('#statsHashrate' + pool).text(stats.pools[pool].hashrateString);
$('#statsHashrateAvg' + pool).text(getReadableHashRateString(calculateAverageHashrate(pool)));
$('#statsLuckDays' + pool).text(stats.pools[pool].luckDays);
$('#statsValidBlocks' + pool).text(parseInt(stats.pools[pool].poolStats.validBlocks).toLocaleString('en'));
$('#statsTotalPaid' + pool).text(parseInt(stats.pools[pool].poolStats.totalPaid).toLocaleString('en'));
$('#statsNetworkBlocks' + pool).text(stats.pools[pool].poolStats.networkBlocks);
$('#statsNetworkDiff' + pool).text(bigNumber(stats.pools[pool].poolStats.networkDiff));
$('#statsNetworkSols' + pool).text(getReadableNetworkHashRateString(stats.pools[pool].poolStats.networkSols));
$('#statsNetworkConnections' + pool).text(stats.pools[pool].poolStats.networkConnections);
}
for (algo in stats.algos) {
$('#statsMiners' + algo).text(stats.algos[algo].workers);
$('#statsHashrate' + algo).text(stats.algos[algo].hashrateString);
}
});
});
function initStatData(callback) {
clearInterval(nextPaymentTimer);
paymentTimerOn = false;
document.querySelectorAll('.nvtooltip').forEach(function(element) {
element.remove();
});
if ( statData === undefined || statData.length == 0 ) {
$.getJSON('/api/pool_stats', function(data){
statData = data;
buildChartData();
if (typeof callback === "function") {
callback();
}
});
} else {
buildChartData();
if (typeof callback === "function") {
callback();
}
}
}
function bigNumber(x) {
return (x > 1000000000000) ? (x / 1000000000000).toFixed(1) + 'T' : (x > 1000000000) ? (x / 1000000000).toFixed(1) + 'B' : (x > 1000000) ? (x / 1000000).toFixed(1) + 'M' : (x > 1000) ? (x / 1000).toFixed(1) + 'K' : x.toFixed(1);
}
function buildChartData() {
var pools = {};
poolKeys = [];
for (var i = 0; i < statData.length; i++){
for (var pool in statData[i].pools){
if (poolKeys.indexOf(pool) === -1) {
poolKeys.push(pool);
lastHashrateUpdate[pool] = 0;
}
}
}
for (var i = 0; i < statData.length; i++) {
var time = statData[i].time * 1000;
for (var f = 0; f < poolKeys.length; f++){
var pName = poolKeys[f];
var a = pools[pName] = (pools[pName] || {
hashrate: []
});
if (pName in statData[i].pools){
a.hashrate.push([time, statData[i].pools[pName].hashrate]);
} else {
a.hashrate.push([time, 0]);
}
}
}
poolHashrateData = [];
for (var pool in pools){
poolHashrateData.push({
key: pool,
values: pools[pool].hashrate
});
$('#statsHashrateAvg' + pool).text(getReadableHashRateString(calculateAverageHashrate(pool)));
}
}
function calculateAverageHashrate(pool) {
var count = 0;
var total = 1;
var avg = 0;
for (var i = 0; i < poolHashrateData.length; i++) {
count = 0;
for (var ii = 0; ii < poolHashrateData[i].values.length; ii++) {
if (pool == null || poolHashrateData[i].key === pool) {
count++;
avg += parseFloat(poolHashrateData[i].values[ii][1]);
}
}
if (count > total)
total = count;
}
avg = avg / total;
return avg;
}
function getReadableHashRateString(hashrate){
hashrate = (hashrate * 2);
if (hashrate < 1000000) {
return (Math.round(hashrate / 1000) / 1000 ).toFixed(2)+' Sol/s';
}
var byteUnits = [ ' Sol/s', ' KSol/s', ' MSol/s', ' GSol/s', ' TSol/s', ' PSol/s' ];
var i = Math.floor((Math.log(hashrate/1000) / Math.log(1000)) - 1);
hashrate = (hashrate/1000) / Math.pow(1000, i + 1);
return hashrate.toFixed(2) + byteUnits[i];
}
function getReadableNetworkHashRateString(hashrate){
hashrate = (hashrate * 1000000);
if (hashrate < 1000000)
return '0 Sol';
var byteUnits = [ ' Sol/s', ' KSol/s', ' MSol/s', ' GSol/s', ' TSol/s', ' PSol/s' ];
var i = Math.floor((Math.log(hashrate/1000) / Math.log(1000)) - 1);
hashrate = (hashrate/1000) / Math.pow(1000, i + 1);
return hashrate.toFixed(2) + byteUnits[i];
}
function middleEllipsis(x, cutlength) {
if (typeof cutlength == 'undefined') {
var cutlength=15;
}
return x.length > 40 ? x.substring(0, cutlength) + '...' + x.substring(x.length-cutlength, x.length): x;
}
function readableDate(a){
return new Date(parseInt(a)).toISOString().substring(0, 16).replace('T', ' ') + ' UTC';
}
function timeOfDayFormat(timestamp){
return new Date(parseInt(timestamp)).toISOString().substring(11, 16);
}
function timeTil(timestamp) {
return (timestamp > 86400) ? (timestamp/86400).toFixed(1) + ' Days' : (timestamp > 3600) ? (timestamp/3600).toFixed(1) + ' Hours' : (timestamp > 60) ? (timestamp / 60).toFixed(1) + ' Minutes' : timestamp + ' Seconds';
}
function timeTilNumbers(timestamp) {
return new Date(timestamp * 1000).toISOString().substr(11, 8);
}
function zeroOrGreater(value) {
return (value < 0) ? 0 : value;
}

237
website/piratepool.io/static/miner_stats.js

@ -0,0 +1,237 @@
var workerHashrateData;
var workerHashrateChart;
var workerHistoryMax = 160;
var minerStatData;
var totalHash;
var totalImmature;
var totalBal;
var totalPaid;
var totalShares;
$(function() {
// resize chart on window resize
nv.utils.windowResize(triggerMinerChartUpdates);
// grab initial stats
$.getJSON('/api/worker_stats?'+_miner, function(data){
minerStatData = data;
for (var w in minerStatData.workers) { _workerCount++; }
buildMinerChartData();
displayMinerCharts();
rebuildWorkerDisplay();
updateMinerStats();
});
// live stat updates
statsSource.addEventListener('message', function(e){
if (document.querySelector('#pageMiner') !== null) {
// TODO, create miner_live_stats...
// miner_live_stats will return the same josn except without the worker history
// FOR NOW, use this to grab updated stats
$.getJSON('/api/worker_stats?'+_miner, function(data){
minerStatData = data;
// check for missing workers
var wc = 0;
var rebuilt = false;
// update worker stats
for (var w in minerStatData.workers) { wc++; }
// TODO, this isn't 100% fool proof!
if (_workerCount != wc) {
if (_workerCount > wc) {
rebuildWorkerDisplay();
rebuilt = true;
}
_workerCount = wc;
}
rebuilt = (rebuilt || updateMinerChartData());
updateMinerStats();
if (!rebuilt) {
updateWorkerStats();
}
});
var stats = JSON.parse(e.data);
}
});
});
function getWorkerNameFromAddress(w) {
var worker = w;
if (w.split(".").length > 1) {
worker = w.split(".")[1];
if (worker == null || worker.length < 1) {
worker = "noname";
}
} else {
worker = "noname";
}
return worker;
}
function buildMinerChartData(){
var workers = {};
for (var w in minerStatData.history) {
var worker = getWorkerNameFromAddress(w);
var a = workers[worker] = (workers[worker] || {
hashrate: []
});
for (var wh in minerStatData.history[w]) {
a.hashrate.push([minerStatData.history[w][wh].time * 1000, minerStatData.history[w][wh].hashrate]);
}
if (a.hashrate.length > workerHistoryMax) {
workerHistoryMax = a.hashrate.length;
}
}
var i=0;
workerHashrateData = [];
for (var worker in workers){
workerHashrateData.push({
key: worker,
//disabled: (i > Math.min((_workerCount-1), 3)),
disabled: false,
values: workers[worker].hashrate
});
i++;
}
}
function updateMinerChartData(){
var workers = {};
for (var w in minerStatData.history) {
var worker = getWorkerNameFromAddress(w);
// get a reference to lastest workerhistory
for (var wh in minerStatData.history[w]) { }
//var wh = minerStatData.history[w][minerStatData.history[w].length - 1];
var foundWorker = false;
for (var i = 0; i < workerHashrateData.length; i++) {
if (workerHashrateData[i].key === worker) {
foundWorker = true;
if (workerHashrateData[i].values.length >= workerHistoryMax) {
workerHashrateData[i].values.shift();
}
workerHashrateData[i].values.push([minerStatData.history[w][wh].time * 1000, minerStatData.history[w][wh].hashrate]);
break;
}
}
if (!foundWorker) {
var hashrate = [];
hashrate.push([minerStatData.history[w][wh].time * 1000, minerStatData.history[w][wh].hashrate]);
workerHashrateData.push({
key: worker,
values: hashrate
});
rebuildWorkerDisplay();
return true;
}
}
triggerMinerChartUpdates();
return false;
}
function calculateAverageMinerHashrate(worker) {
var count = 0;
var total = 1;
var avg = 0;
for (var i = 0; i < workerHashrateData.length; i++) {
count = 0;
for (var ii = 0; ii < workerHashrateData[i].values.length; ii++) {
if (worker == null || workerHashrateData[i].key === worker) {
count++;
avg += parseFloat(workerHashrateData[i].values[ii][1]);
}
}
if (count > total)
total = count;
}
avg = avg / total;
return avg;
}
function triggerMinerChartUpdates(){
workerHashrateChart.update();
}
function displayMinerCharts() {
nv.addGraph(function() {
workerHashrateChart = nv.models.lineChart()
.margin({left: 80, right: 30})
.x(function(d){ return d[0] })
.y(function(d){ return d[1] })
.useInteractiveGuideline(true);
workerHashrateChart.xAxis.tickFormat(timeOfDayFormat);
workerHashrateChart.yAxis.tickFormat(function(d){
return getReadableHashRateString(d);
});
d3.select('#workerHashrate').datum(workerHashrateData).call(workerHashrateChart);
return workerHashrateChart;
});
}
function updateMinerStats() {
totalHash = minerStatData.totalHash;
totalPaid = minerStatData.paid;
totalBal = minerStatData.balance;
totalImmature = minerStatData.immature;
totalShares = minerStatData.totalShares;
// do some calculations
var _blocktime = 250;
var _networkHashRate = parseFloat(minerStatData.networkSols) * 1.2;
var _myHashRate = (totalHash / 1000000) * 2;
var luckDays = ((_networkHashRate / _myHashRate * _blocktime) / (24 * 60 * 60)).toFixed(3);
// update miner stats
$("#statsHashrate").text(getReadableHashRateString(totalHash));
$("#statsHashrateAvg").text(getReadableHashRateString(calculateAverageMinerHashrate(null)));
$("#statsLuckDays").text(luckDays);
$("#statsTotalImmature").text(totalImmature);
$("#statsTotalBal").text(totalBal);
$("#statsTotalPaid").text(totalPaid);
$("#statsTotalShares").text(bigNumber(totalShares));
}
function updateWorkerStats() {
// update worker stats
var i=0;
for (var w in minerStatData.workers) { i++;
var htmlSafeWorkerName = w.split('.').join('_').replace(/[^\w\s]/gi, '');
var saneWorkerName = getWorkerNameFromAddress(w);
$("#statsHashrate"+htmlSafeWorkerName).text(getReadableHashRateString(minerStatData.workers[w].hashrate));
$("#statsHashrateAvg"+htmlSafeWorkerName).text(getReadableHashRateString(calculateAverageMinerHashrate(saneWorkerName)));
$("#statsLuckDays"+htmlSafeWorkerName).text(minerStatData.workers[w].luckDays);
$("#statsPaid"+htmlSafeWorkerName).text(minerStatData.workers[w].paid);
$("#statsBalance"+htmlSafeWorkerName).text(minerStatData.workers[w].balance);
$("#statsShares"+htmlSafeWorkerName).text(bigNumber(minerStatData.workers[w].currRoundShares));
$("#statsDiff"+htmlSafeWorkerName).text(bigNumber(zeroOrGreater(minerStatData.workers[w].diff)));
}
}
function addWorkerToDisplay(name, htmlSafeName, workerObj) {
var htmlToAdd = "";
htmlToAdd ='<div class="pure-u-1-4 pure-responsive-disable"><div class="l-box">';
htmlToAdd+='<h3 class="boxLowerHeader">';
htmlToAdd+=(htmlSafeName.indexOf("_") >= 0) ? htmlSafeName.substr(htmlSafeName.indexOf("_")+1,htmlSafeName.length) : 'noname';
htmlToAdd+='</h3>';
htmlToAdd+='<div class="boxStatsList"><ul>';
htmlToAdd+='<li><i class="fas fa-tachometer-alt fa-fw"></i> <span id="statsHashrate'+htmlSafeName+'">'+getReadableHashRateString(workerObj.hashrate)+'</span> (Now)</li>';
htmlToAdd+='<li><i class="fas fa-tachometer-alt fa-fw"></i> <span id="statsHashrateAvg'+htmlSafeName+'">'+getReadableHashRateString(calculateAverageMinerHashrate(name))+'</span> (Avg)</li>';
htmlToAdd+='<li><i class="fas fa-unlock-alt fa-fw"></i> Diff: <span id="statsDiff'+htmlSafeName+'">'+bigNumber(zeroOrGreater(workerObj.diff))+'</span></li>';
htmlToAdd+='<li><i class="fas fa-cog fa-fw"></i> Shares: <span id="statsShares'+htmlSafeName+'">'+bigNumber(workerObj.currRoundShares)+'</span></li>';
htmlToAdd+='<li><i class="fas fa-dice fa-fw"></i> Luck <span id="statsLuckDays'+htmlSafeName+'">'+workerObj.luckDays+'</span> Days</li>';
htmlToAdd+='<li><i class="fas fa-piggy-bank fa-fw"></i> Bal: <span id="statsBalance'+htmlSafeName+'">'+workerObj.balance+'</span></li>';
htmlToAdd+='<li><i class="fas fa-money-bill-wave fa-fw"></i> Paid: <span id="statsPaid'+htmlSafeName+'">'+workerObj.paid+'</span></li>';
htmlToAdd+='</ul></div></div></div>';
$("#boxesWorkers").html($("#boxesWorkers").html()+htmlToAdd);
}
function rebuildWorkerDisplay() {
$("#boxesWorkers").html("");
var i=0;
for (var w in minerStatData.workers) { i++;
var htmlSafeWorkerName = w.split('.').join('_').replace(/[^\w\s]/gi, '');
var saneWorkerName = getWorkerNameFromAddress(w);
addWorkerToDisplay(saneWorkerName, htmlSafeWorkerName, minerStatData.workers[w]);
}
}

83
website/piratepool.io/static/payments.js

@ -0,0 +1,83 @@
$(function() {
initStatData();
statsSource.addEventListener('message', function (e) {
if (document.querySelector('#pagePayments') !== null) {
var stats = JSON.parse(e.data);
for (var f = 0; f < poolKeys.length; f++) {
var pool = poolKeys[f];
for (var i = 0; i < stats.pools[pool].payments.length; i++) {
var paymentstat = stats.pools[pool].payments[i];
var existingRow = document.querySelector('#payment' + pool + paymentstat.time);
if (existingRow == null) {
clearInterval(nextPaymentTimer);
paymentTimerOn = false;
//Add new
var insertPaymentTr = document.createElement('tr');
insertPaymentTr.id = 'payment' + pool + paymentstat.time;
insertPaymentTr.setAttribute('class', 'dynamicallyInserted');
insertPaymentTr.style.opacity = 0;
insertPaymentTr.style.transition = 'opacity 1s ease-in';
if (typeof paymentstat.txid !== 'undefined') {
var explorerlink = '<a href="' + explorerURL + 'tx/' + paymentstat.txid + '" target="_blank" rel="noopener noreferrer">' + paymentstat.blocks + '</a>';
} else {
var explorerlink = '<a>' + paymentstat.blocks + '</a>';
}
insertPaymentTr.innerHTML = '<td class="paymentblocks" title="Blocks:' + paymentstat.blocks.length + ' ' + paymentstat.opid + '">'
+ '<span class="responsiveTableLabel"><i class="fas fa-link fa-fw"></i></span> <span>Blocks: [' + paymentstat.blocks.length + '] </span>'
+ explorerlink + '<div class="fade">&#9660;</div></td>';
insertPaymentTr.innerHTML += '<td><span class="responsiveTableLabel"><i class="far fa-clock fa-fw"></i> Time: </span>' + readableDate(paymentstat.time) + '</td>';
insertPaymentTr.innerHTML += '<td><span class="responsiveTableLabel"><i class="fas fa-users fa-fw"></i> Miners: </span>' + paymentstat.miners + '</td>';
insertPaymentTr.innerHTML += '<td><span class="responsiveTableLabel"><i class="fas fa-cog fa-fw"></i> Shares: </span>' + bigNumber(paymentstat.shares) + '</td>';
insertPaymentTr.innerHTML += '<td><span class="responsiveTableLabel"><i class="fas fa-money-bill-wave fa-fw"></i> Amount: </span>' + paymentstat.paid + ' ' + stats.pools[pool].symbol + '</td>';
var paymentTable = document.querySelector('#paymentTable' + pool + ' tbody');
if (paymentTable != null) {
paymentTable.insertBefore(insertPaymentTr, paymentTable.firstChild);
setTimeout(() => {
document.querySelectorAll('.dynamicallyInserted').forEach(function(newPayment) {
newPayment.style.opacity = 1;
});
}, 25);
console.log('Added new payment!');
}
} else {
//Update existing (txid) for private chains
if (typeof paymentstat.txid !== 'undefined' && (String(stats.pools[pool].name).startsWith("pirate") || String(stats.pools[pool].name).startsWith("arrr")) ) {
var paymentblock = document.querySelector('#payment' + pool + paymentstat.time + ' .paymentblocks a');
paymentblock.setAttribute('href', explorerURL + 'tx/' + paymentstat.txid);
paymentblock.setAttribute('target', '_blank');
paymentblock.setAttribute('rel', 'noopener noreferrer');
}
}
}
//Global var from main.js - cleared on initStatData(), this needs to be started after the loop in case a new payment was added and old timer needs to be reset
if (!paymentTimerOn) {
nextPaymentTimer = setInterval(function() {
var timeElement = document.querySelector('#statsNextPayment' + pool);
if (timeElement !== null) {
var timeleft=(paymentInterval-parseInt((new Date().getTime() - parseInt(stats.pools[pool].payments[0].time))/1000));
if (timeleft > 0) {
timeElement.innerHTML = timeTil(timeleft);
timeElement.setAttribute('title', timeTilNumbers(timeleft));
} else {
timeElement.innerHTML = 'Now';
timeElement.setAttribute('title', '00:00:00');
}
}
}, 1000);
paymentTimerOn = true;
}
}
}
});
});

BIN
website/piratepool.io/static/pirate128.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
website/piratepool.io/static/skull.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
website/piratepool.io/static/skull256.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

149
website/piratepool.io/static/stats.js

@ -0,0 +1,149 @@
$(function() {
initStatData(displayCharts);
nv.utils.windowResize(triggerChartUpdates);
statsSource.addEventListener('message', function (e) {
if (document.querySelector('#pageStats') !== null) {
var stats = JSON.parse(e.data);
var newPoolAdded = (function(){
for (var p in stats.pools){
if (poolKeys.indexOf(p) === -1)
return true;
}
return false;
})();
if (newPoolAdded || Object.keys(stats.pools).length > poolKeys.length) {
buildChartData();
displayCharts();
} else {
var time = stats.time * 1000;
for (var f = 0; f < poolKeys.length; f++) {
var pool = poolKeys[f];
for (var i = 0; i < poolHashrateData.length; i++) {
if (poolHashrateData[i].key === pool) {
if (time > lastHashrateUpdate[pool]) {
poolHashrateData[i].values.push([time, pool in stats.pools ? stats.pools[pool].hashrate : 0]);
poolHashrateData[i].values.shift();
$('#statsHashrateAvg' + pool).text(getReadableHashRateString(calculateAverageHashrate(pool)));
lastHashrateUpdate[pool] = time;
}
break;
}
}
/* Handle new found blocks */
var poolFoundList = document.querySelector('#blocksFound' + pool + ' .blocksFoundList');
if (poolFoundList != null) {
var pendingblocks = stats.pools[pool].pending.blocks;
var confirmedblocks = stats.pools[pool].confirmed.blocks;
var legitpending = [];
var legitconfirmed = [];
var prevHeight = 0;
document.querySelector('#blocksFoundHeaderCount' + pool).innerHTML = pendingblocks.length;
//Add new pending blocks
//@todo list starts from the heighest to lowest, if multiple blocks found in the same tick it inserts them backwards
for ( var block in pendingblocks ) {
var checkblock = pendingblocks[block].split(':');
legitpending.push(checkblock[0]);
var pendingBlockElement = document.querySelector('#blocksFoundPending' + checkblock[0]);
if (pendingBlockElement == null) {
var insertPendingBlock = document.createElement('div');
insertPendingBlock.id = 'blocksFoundPending' + checkblock[0];
insertPendingBlock.setAttribute('class', 'blocksFoundPending dynamicallyInserted');
insertPendingBlock.setAttribute('title', 'Waiting for payment processor to review');
insertPendingBlock.style.opacity = 0;
insertPendingBlock.style.transition = 'opacity 1s ease-in';
insertPendingBlock.innerHTML = '<div><i class="fas fa-link fa-fw"></i> <small>Block:</small> <a href="' + explorerURL + 'block/' + checkblock[0] + '" target="_blank" rel="noopener noreferrer">' + checkblock[2] + '</a><span style="padding-left: 10px;"><small>' + readableDate(checkblock[4]) + '</small></span><span class="countLabel">Pending</span></div>';
if (parseInt(checkblock[2]) > prevHeight) {
poolFoundList.insertBefore(insertPendingBlock, poolFoundList.firstChild);
} else {
poolFoundList.insertBefore(insertPendingBlock, poolFoundList.firstChild.nextSibling);
}
prevHeight = parseInt(checkblock[2]);
setTimeout(() => {
document.querySelectorAll('.dynamicallyInserted').forEach(function(newBlock) {
newBlock.style.opacity = 1;
});
}, 25);
}
}
//Add new confirmed blocks
//@todo simplify duplicate logic
for ( var i = 7; i >= 0; i-- ) {
var checkblock = confirmedblocks[i].split(':');
legitconfirmed.push(checkblock[0]);
var confirmedBlockElement = document.querySelector('#blocksFoundPaid' + checkblock[0]);
if (confirmedBlockElement == null) {
var insertPendingBlock = document.createElement('div');
insertPendingBlock.id = 'blocksFoundPaid' + checkblock[0];
insertPendingBlock.setAttribute('class', 'blocksFoundPaid');
insertPendingBlock.setAttribute('title', 'Payment sent, please check payments page');
insertPendingBlock.innerHTML = '<div><i class="fas fa-link fa-fw"></i> <small>Block:</small> <a href="' + explorerURL + 'block/' + checkblock[0] + '" target="_blank" rel="noopener noreferrer">' + checkblock[2] + '</a><span style="padding-left: 10px;"><small>' + readableDate(checkblock[4]) + '</small></span><span class="countLabel">Pending</span></div>';
poolFoundList.insertBefore(insertPendingBlock, document.querySelectorAll('.blocksFoundList .blocksFoundPaid')[0]);
}
}
//Update confirms
var confirmblocks = stats.pools[pool].pending.confirms;
for ( var confirm in confirmblocks ) {
var labelElement = document.querySelector('#blocksFoundPending' + confirm + ' .countLabel');
labelElement.innerHTML = (confirmblocks[confirm] == "1") ? 'Need dPoW' : confirmblocks[confirm] + "/" + minConfirmations;
}
//Remove blocks no longer in pending/confirmed list
//Reselect found list because of possible inserts above
//Loop in reverse so there's no "confusion"
var poolFoundListChildren = document.querySelectorAll('#blocksFound' + pool + ' .blocksFoundList > div');
for ( var i = poolFoundListChildren.length-1; i >= 0; i--) {
var blockDivID = poolFoundListChildren[i].id
var blockDivCheckPending = blockDivID.replace('blocksFoundPending', '');
var blockDivCheckPaid = blockDivID.replace('blocksFoundPaid', '');
var blockDivElement = document.getElementById(blockDivID);
if (blockDivElement.classList.contains("blocksFoundPending") && legitpending.indexOf(blockDivCheckPending) < 0) {
document.getElementById(blockDivID).parentNode.removeChild(document.getElementById(blockDivID));
}
if (blockDivElement.classList.contains("blocksFoundPaid") && ( legitconfirmed.indexOf(blockDivCheckPaid) < 0 || legitconfirmed.indexOf(blockDivCheckPaid) > 7 ) ) {
document.getElementById(blockDivID).parentNode.removeChild(document.getElementById(blockDivID));
}
}
}
}
triggerChartUpdates();
}
}
});
});
function displayCharts(){
nv.addGraph(function() {
poolHashrateChart = nv.models.lineChart()
.margin({top:0, right: 30, bottom:15, left: 80})
.x(function(d){ return d[0] })
.y(function(d){ return d[1] })
.useInteractiveGuideline(true);
poolHashrateChart.xAxis.tickFormat(timeOfDayFormat);
poolHashrateChart.yAxis.tickFormat(function(d){
return getReadableHashRateString(d);
});
d3.select('#poolHashrate').datum(poolHashrateData).call(poolHashrateChart);
return poolHashrateChart;
});
}
function triggerChartUpdates(){
poolHashrateChart.update();
}

557
website/piratepool.io/static/style.css

@ -0,0 +1,557 @@
:root {
--gold: #BB9645;
--blue: #082DB2;
--grey: #2f2f2f;
--dark-blue: #071642;
--dark-grey: #141414;
--light-grey: #6d6d6d;
--blood: #690015;
}
* {
box-sizing: border-box;
}
html, body, button, input, select, textarea,
.pure-g [class *= "pure-u"] {
font-family: 'Roboto', sans-serif;
line-height: 1.4em;
}
footer,
h1, h2, h3, h4, h5, h6, h7,
.home-menu,
.chartLabel,
.blocksFoundHeader,
.poolLabel,
.coinInfoHeader,
.workerStatsChartFooter,
.nv-axis text,
.countLabel {
font-family: 'Bai Jamjuree', sans-serif;
line-height:1em;
}
body {
background-color:#000;
display: flex;
flex-direction: column;
max-width: 1160px;
margin: 0 auto;
}
header {
margin-top:5px;
}
main {
background-color: var(--dark-grey);
color:#FFF;
position: relative;
}
a, a:link, a:visited {
color:#FFF;
}
a:hover {
color:var(--gold);
}
code {
font-family: monospace, serif;
display:block;
margin:15px;
padding:20px;
background-color: var(--dark-blue);
word-break:break-all;
box-shadow: -1px -1px 0 #000;
}
input {
color:#000;
}
button {
color:#FFF;
background-color: var(--gold);
border:none;
border-radius: 2px;
padding: 3px 10px;
}
table {
width: 100%;
}
footer{
text-align: center;
color: #FFF;
text-decoration: none;
font-size: 0.8em;
padding: 15px;
line-height: 24px;
}
footer a {
color: #fff;
text-decoration: none;
}
.highlight {
color:var(--gold);
font-weight:900;
}
.muted {
font-size:0.8em;
color:var(--light-grey);
}
.textshadow {
text-shadow: -3px -3px 0px #000;
}
br.responsiveonly {
display:none;
}
.alertbar {
color:var(--gold);
font-weight:900;
text-shadow: -3px -3px 0px #000;
text-align:center;
padding:10px 0;
background-color:var(--dark-blue);
}
/* Menus */
header .home-menu,
header .pure-menu {
background:transparent;
padding: 0;
margin: 5px 0;
}
header .home-menu,
header .home-menu .pure-menu-list,
header .home-menu .pure-menu-list li {
display: flex;
align-items: center;
justify-content: center;
line-height: normal !important;
flex-wrap:wrap;
}
header .home-menu a {
color: var(--gold);
font-weight:900;
font-size:1.2em;
outline: none;
transition:background-color 0.33s ease-out, color 0.33s ease-out;
}
header .home-menu a:hover,
header .home-menu .pure-menu-selected a {
color: #FFF!important;
background-color: var(--gold);
border-radius: 2px;
}
header .home-menu li a i {
margin-right:5px;
}
.pure-menu.pure-menu-open,
.pure-menu.pure-menu-horizontal li .pure-menu-children {
border:none;
}
.pure-menu .pure-menu-heading {
color: #FFF;
font-size: 1.2em;
border-bottom: 1px solid var(--grey);
margin:0;
padding: 16px 16px 12px 15px;
}
.pure-menu li a:hover {
background-color:var(--dark-blue);
color:#FFF;
}
/* PURE TABLE */
.pure-table {
border: none;
}
.pure-table thead {
background-color:var(--gold);
}
.pure-table td {
vertical-align:top;
}
.pure-table-odd td,
.pure-table-even td {
background-color: transparent;
}
.responsiveTableLabel {
display:none;
visibility:hidden;
}
/* HOME */
.boxWelcome{
background-color: var(--dark-blue);
color: white;
max-width:640px;
margin:15px auto 10px auto;
padding:5px 10px 10px;
box-shadow: -1px -1px 0 #000;
}
/* Stats Boxes */
.boxStats .l-box {
background-color: var(--dark-blue);
margin:10px;
padding:10px;
box-shadow: -1px -1px 0 #000;
}
.boxStats h3 {
margin:0;
color: var(--gold);
text-shadow: -2px -2px 0px #000;
}
.boxStatsList {
text-align:center;
}
.boxStatsList ul {
display:inline-block;
margin: 0 auto;
padding:0;
text-align: left;
}
.boxStatsList li {
list-style-type: none;
margin: 5px 0;
}
/* Stats Page */
.blocksFoundList {
clear:both;
display:flex;
flex-wrap:wrap;
justify-content: space-around;
}
.blocksFoundList > div {
margin: 5px;
padding: 5px;
text-overflow: ellipsis;
box-shadow: -1px -1px 0 #000;
flex: 1;
min-width: 150px;
max-width: 150px;
}
.blocksFoundPending {
color: #FFF;
background-color: var(--grey);
}
.blocksFoundList .countLabel {
float:right;
font-size:0.8em;
line-height:1em;
}
.blocksFoundPending .countLabel {
background-color: var(--blood);
border-radius:1px;
padding:1px;
}
.blocksFoundPaid {
background-color: var(--dark-blue);
}
.blocksFoundPaid .countLabel {
color: var(--gold);
font-weight:900;
}
.blocksFoundHeader {
font-size: 1.3em;
margin: 10px 10px 20px 10px;
display: flex;
flex-wrap: wrap;
align-items: center;
}
.blocksFoundHeader > div {
flex: 1;
}
.blocksFoundHeader > div:nth-child(2) {
font-size:0.8em;
text-align:right;
}
.minerAddress {
font-family: monospace;
}
/* GETTING STARTED */
.gettingStartedMenu,
.gettingStartedMenu.pure-menu-open {
width:100%;
display: inline-block;
background-color: var(--gold);
background: linear-gradient(to right, var(--gold) 0%,var(--dark-grey) 100%);
}
.gettingStarted .menuHeader {
color: #FFF;
font-weight:900;
border-bottom: 1px solid var(--grey);
font-size: 1.2em;
padding: 16px 16px 12px 15px;
margin:0;
text-transform:uppercase;
}
.gettingStartedMenu ul {
position: -webkit-sticky;
position:sticky;
top: 10px;
}
.gettingStartedContent {
margin: 15px;
}
.coinInfoHeader {
color: var(--gold);
margin:0;
text-shadow: -2px -2px 0px #000;
}
/* PAYMENTS */
.paymentblocks {
max-width:500px;
word-wrap:break-word;
position:relative;
}
.paymentblocks .fade {
display:none;
}
.paymentblocksexpand .fade {
display:block;
z-index: 10;
background-image: linear-gradient(to bottom, rgba(20, 20, 20, 0), rgba(20, 20, 20, 1) 90%);
width: 95%;
height: 10px;
position: absolute;
bottom: 7px;
pointer-events: none;
text-align: center;
font-size: 14px;
color: var(--gold);
transition: opacity 0.2s ease 0.33s;
}
.paymentblocks a {
display: block;
max-height: 36px;
overflow: hidden;
text-overflow: ellipsis;
transition: max-height 0.2s ease-out 0.33s;
}
.paymentblocksexpand a:hover {
max-height: 1000px;
}
.paymentblocksexpand a:hover + .fade {
opacity:0;
}
/* WORKER STATS */
.workerStatsChartHeaderLeft {
float:left;
max-width:100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.workerStatsChartHeaderRight {
float:right;
padding-left: 18px;
font-size: .8em;
}
.workerStatsChartFooter {
display:flex;
}
.workerStatsChartFooter > div {
flex:1;
text-align:center;
}
.poolLabel {
font-size: 1.2em;
line-height: 1.5em;
text-align: center;
padding: 5px;
}
/* CHARTS */
#topCharts > div > div > svg {
display: block;
height: 280px;
}
.chartWrapper{
padding: 5px;
margin-bottom: 18px;
}
.chartLabel {
font-size: 1.2em;
line-height: 1.2em;
text-align: center;
padding: 4px;
margin:0;
}
.nvd3 .nv-axis path,
.nvd3 .nv-axis line {
fill: none;
stroke: #333333;
shape-rendering: crispEdges;
}
.nv-axis text,
.nv-legend text {
font-size: 11px;
fill: #FFFFFF;
stroke: none;
}
.nv-group.nv-series-0,
.nv-series:first-of-type .nv-legend-symbol {
stroke-opacity: 1;
fill-opacity: 0.5;
fill: var(--gold)!important;
stroke: var(--gold)!important;
}
.nvtooltip {
color:#000;
}
.nvtooltip .legend-color-guide div:first-of-type {
background-color: var(--gold)!important;
}
@media only screen and (max-width: 760px), (min-device-width: 768px) and (max-device-width: 1024px) {
.home-menu li {
margin: 0 5px;
}
.home-menu li a {
padding: 5px;
font-size: 1em;
line-height: 1em;
}
.home-menu li a i {
margin-right:0;
}
.pure-table {
border-top: 1px solid var(--grey);
}
table, thead, tbody, th, td, tr {
display: block;
}
thead tr {
display:none;
visiblity:hidden;
}
tr {
border-bottom: 1px solid var(--grey);
}
td {
border: none;
position: relative;
}
.pure-table td {
border-left:none;
padding: 5px;
max-width:100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
br.responsiveonly {
display:initial;
}
.responsivehide {
display:none;
}
.boxWelcome h1,
.boxWelcome h2 {
text-align:center!important;
}
.blocksFoundHeader {
display:block;
}
.blocksFoundHeader > div {
text-align:center!important;
}
.blocksFoundList > div {
flex: 1;
}
.responsiveTableLabel {
display:inline-block;
visibility:visible;
}
.pure-responsive-disable,
.flex-responsive-disable {
width: 100%;
}
.paymentblocks a {
display:inline;
}
.paymentblocks .fade {
display:none;
}
}

79
website/piratepool.io/static/workers.js

@ -0,0 +1,79 @@
$(function() {
initStatData();
$('.btn-lg').click(function(){
window.location = "workers/" + $('.input-lg').val();
});
statsSource.addEventListener('message', function (e) {
if (document.querySelector('#pageWorkers') !== null) {
var stats = JSON.parse(e.data);
for (var f = 0; f < poolKeys.length; f++) {
var pool = poolKeys[f];
var sharesTotal = 0;
var minerIndex = 0;
for (var addr in stats.pools[pool].miners) {
minerIndex++;
var workerstat = stats.pools[pool].miners[addr];
sharesTotal += parseFloat(workerstat.shares);
var existingRow = document.querySelector('#workers' + pool + ' #miner-' + minerIndex);
var minerEfficiency = ( workerstat.shares > 0 ) ? Math.floor(10000 * workerstat.shares / (workerstat.shares + workerstat.invalidshares)) / 100 : 0;
if (existingRow == null) {
//Add new
var insertMinerTr = document.createElement('tr');
insertMinerTr.id = 'miner-' + minerIndex;
insertMinerTr.setAttribute('data-hashrate', workerstat.hashrate);
insertMinerTr.innerHTML = '<td><span class="responsiveTableLabel"><i class="far fa-address-card fa-fw"></i></span>Miner #'+ minerIndex +'</td>';
insertMinerTr.innerHTML += '<td><span class="responsiveTableLabel"><i class="fas fa-cog fa-fw"></i> Shares: </span><span>' + bigNumber(workerstat.shares) + '</span></td>';
insertMinerTr.innerHTML += '<td><span class="responsiveTableLabel"><i class="fas fa-bullseye fa-fw"></i> Efficiency: </span><span> ' + minerEfficiency + '%</span></td>';
insertMinerTr.innerHTML += '<td><span class="responsiveTableLabel"><i class="fas fa-tachometer-alt fa-fw"></i> Hashrate: </span><span>' + workerstat.hashrateString + '</span></td>';
document.querySelector('#workers' + pool + ' .poolMinerTable tbody').appendChild(insertMinerTr);
console.log('Added new miner! [' + minerIndex + ']');
} else {
//Update existing
document.querySelector('#workers' + pool + ' #miner-' + minerIndex + ' td:nth-child(2) span:nth-child(2)').innerHTML = bigNumber(workerstat.shares);
document.querySelector('#workers' + pool + ' #miner-' + minerIndex + ' td:nth-child(3) span:nth-child(2)').innerHTML = minerEfficiency + '%';
document.querySelector('#workers' + pool + ' #miner-' + minerIndex + ' td:nth-child(4) span:nth-child(2)').innerHTML = workerstat.hashrateString;
document.querySelector('#workers' + pool + ' #miner-' + minerIndex).setAttribute('data-hashrate', workerstat.hashrate);
}
}
document.querySelector('#statsShares' + pool).innerHTML = bigNumber(sharesTotal);
//Remove inactive
var workerList = document.querySelectorAll('#workers' + pool + ' .poolMinerTable tbody tr');
for ( var i = workerList.length-1; i >= 0; i--) {
if( typeof stats.pools[pool].miners[workerList[i].id] == 'undefined') {
console.log('Removing miner :( [' + workerTrID + ']');
workerList[i].parentNode.removeChild(workerList[i]);
}
}
//Resort table
var table = document.querySelector('#workers' + pool + ' table.poolMinerTable tbody');
var rows = document.querySelectorAll('#workers' + pool + ' table.poolMinerTable tbody tr');
var rowsArr = [].slice.call(rows).sort(function (a, b) {
return (parseFloat(a.dataset.hashrate) == parseFloat(b.dataset.hashrate)) ? 0 : ((parseFloat(a.dataset.hashrate) < parseFloat(b.dataset.hashrate)) ? 1 : -1);
});
for (var i = 0; i < rowsArr.length; i++){ table.append(rowsArr[i]); }
}
}
});
});
function searchKeyPress(e)
{
// look for window.event in case event isn't passed in
e = e || window.event;
if (e.keyCode == 13)
{
document.getElementById('btnSearch').click();
return false;
}
return true;
}

92
website/zznomp/index.html

@ -0,0 +1,92 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="shortcut icon" type="image/png" href="/static/skull.png"/>
<!--<meta name="viewport" content="width=device-width, initial-scale=1">-->
<link href='//fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
<!-- <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.0.3/css/font-awesome.min.css"> -->
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.3.1/css/all.css" integrity="sha384-mzrmE5qonljUremFsqc01SB46JvROS7bZs3IO2EmfFsd15uHvIt+Y8vEf7N7fWAU" crossorigin="anonymous">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/normalize/3.0.1/normalize.min.css">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/pure/0.4.2/pure-min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.4.5/d3.min.js"></script>
<script src="/static/nvd3.js"></script>
<link rel="stylesheet" href="/static/nvd3.css">
<script src="/static/main.js"></script>
<link rel="stylesheet" href="/static/style.css">
<title>zz nomp - mining pool for pirate chain</title>
<meta name="google-site-verification" content="JxkbxOT-aLGRVzTv8ES0RQ7EaWdSGZvOfZOUVmF1Xm8" />
</head>
<body>
<header>
<div style="text-align: center;"><span style="font-size:1.5em; color:red; font-weight:900;text-shadow: 1px 1px 1px #fff;">SAPLING on piratepool.io enabled! Immediate action required! See notice on <a href="/#sapling">homepage</a>!</span></div>
<div class="home-menu pure-menu pure-menu-open pure-menu-horizontal">
<a class="pure-menu-heading {{? it.selected.length < 1 }}pure-menu-selected{{?}} hot-swapper" href="/"><i class="fa fa-home"></i>&nbsp;Home</a>
<ul>
<li class="{{? it.selected === 'getting_started' }}pure-menu-selected{{?}}">
<a class="hot-swapper" href="/getting_started">
<i class="fas fa-rocket fa-fw"></i>&nbsp;
Getting Started
</a>
</li>
<li class="{{? it.selected === 'stats' }}pure-menu-selected{{?}}">
<a class="hot-swapper" href="/stats">
<i class="fas fa-chart-bar fa-fw"></i>&nbsp;
Graph Stats
</a>
</li>
<li class="{{? it.selected === 'tbs' }}pure-menu-selected{{?}}">
<a class="hot-swapper" href="/tbs">
<i class="fas fa-table fa-fw"></i>&nbsp;
Tab Stats
</a>
</li>
<li class="{{? it.selected === 'workers' }}pure-menu-selected{{?}}">
<a class="hot-swapper" href="/workers">
<i class="fas fa-cogs fa-fw"></i>&nbsp;
Workers Stats
</a>
</li>
<li class="{{? it.selected === 'payments' }}pure-menu-selected{{?}}">
<a class="hot-swapper" href="/payments">
<i class="fab fa-btc fa-fw"></i>&nbsp;
Payments
</a>
</li>
<li class="{{? it.selected === 'api' }}pure-menu-selected{{?}}">
<a class="hot-swapper" href="/api">
<i class="fas fa-code fa-fw"></i>&nbsp;
API
</a>
</li>
</ul>
</div>
</header>
<main>
{{=it.page}}
</main>
<footer>
No warranties matey! If ye be 'aving any troubles, invoke yer right to parlay at <a href="https://discord.gg/5f7p3vx" target="_blank" rel="noopener noreferrer">#pirate</a>
<br>
&lt;3 <a href="https://webworker.sh" alt="webworker01" target="_blank" rel="noopener noreferrer">🐸</a> &middot; Built with <a href="https://github.com/webworker01/knomp" target="_blank" rel="noopener noreferrer">knomp</a>
</footer>
</body>
</html>

2798
website/zznomp/key.html

File diff suppressed because it is too large

50
website/zznomp/pages/admin.html

@ -0,0 +1,50 @@
<div>
<style>
#passwordForm, #adminCenter{
display: none;
}
#adminCenter{
display: flex;
flex-flow: row;
}
#leftMenu{
flex: 0 0 200px;
}
#editForm{
flex: 1 1 auto;
}
</style>
<form class="pure-form pure-form-stacked" id="passwordForm">
<fieldset>
<legend>Password</legend>
<input id="password" type="password" placeholder="Password">
<label for="remember" class="pure-checkbox">
<input id="remember" type="checkbox"> Stay Logged In
</label>
<button type="submit" class="pure-button pure-button-primary">Log In</button>
</fieldset>
</form>
<div id="adminCenter">
<div class="pure-menu pure-menu-open" id="leftMenu">
<a class="pure-menu-heading">Administration</a>
<ul>
<li id="addPool"><a href="#">Add Pool</a></li>
<li class="pure-menu-heading" id="poolList">Current Pools</li>
</ul>
</div>
<div id="editForm"></div>
</div>
<script src="/static/admin.js"></script>
</div>

11
website/zznomp/pages/api.html

@ -0,0 +1,11 @@
<div style="margin: 18px;">
API - The API is work in progress and is subject to change during development.
<ul>
<li><a href="/api/stats">/api/stats</a> global pool stats</li>
<li><a href="/api/blocks">/api/blocks</a> global block stats</li>
<li><a href="/api/pool_stats">/api/pool_stats</a> - historical stats</li>
<li><a href="/api/payments">/api/payments</a> - payment history</li>
<li><a href="/api/worker_stats?addr">/api/worker_stats?&lt;replace address here&gt;</a> - historical time per pool json </li>
<li><a href="/api/live_stats">/api/live_stats</a> - live stats (websocket)</li>
</ul>
</div>

265
website/zznomp/pages/getting_started.html

@ -0,0 +1,265 @@
<div id="holder">
<div class="pure-menu pure-menu-open gettingStartedMenu">
<span class="pure-menu-heading">Getting Started</span>
<ul class="pure-menu-list">
<li class="pure-menu-item"><a href="#poolDetails" class="pure-menu-link">Pool Details</a></li>
<li class="pure-menu-item"><a href="#payments" class="pure-menu-link">Payout Information</a></li>
<li class="pure-menu-item"><a href="#createWallet" class="pure-menu-link">Create Wallet</a></li>
<li class="pure-menu-item"><a href="#gpuMining" class="pure-menu-link">GPU Mining Software</a></li>
<li class="pure-menu-item"><a href="#cpuMining" class="pure-menu-link">CPU Mining Software</a></li>
</ul>
</div>
<div id="menu">
{{? (function(){
if (!it.portalConfig.switching) return false;
for (var p in it.portalConfig.switching){
if (it.portalConfig.switching[p].enabled)
return true;
}
return false;
})()
}}
<div class="menuHeader">Coin-Switching Ports</div>
{{?}}
<div class="menuList">
{{ for (var p in it.portalConfig.switching){
if (!it.portalConfig.switching[p].enabled) continue;
var info = {
algo: p,
ports: {},
host: it.portalConfig.website.stratumHost
};
info.ports[it.portalConfig.switching[p].port] = {diff: it.portalConfig.switching[p].diff};
info = JSON.stringify(info).replace(/"/g, '&quot;');
}}
<a href="#" class="poolOption" data-info="{{=info}}">{{=p}}</a>
{{ } }}
</div>
<div class="menuHeader" id="poolDetails">Miner Configuration</div>
<div class="menuList" id="coinList">
{{ if (it.portalConfig.gettingStartedPopups) { }}
{{ for (var pool in it.poolsConfigs) {
var info = JSON.stringify({
coin: it.poolsConfigs[pool].coin,
algo: it.poolsConfigs[pool].coin.algorithm,
ports: it.poolsConfigs[pool].ports,
host: it.portalConfig.website.stratumHost
}).replace(/"/g, '&quot;');
}}
<a href="#" class="poolOption" data-info="{{=info}}">{{=pool}}</a>
{{ } }}
{{ } else { }}
{{ for (var pool in it.poolsConfigs) { }}
{{if (String(pool) == 'pirate') { continue; } }}
<code>
<div class="coinInfoHeader"><span class="coinInfoName">{{=it.poolsConfigs[pool].coin.name}}</span> Configuration:</div>
<div class="coinInfoRows">
<div class="coinInfoRowKeys">
<div>Username:</div>
<div>Password:</div>
<div>Algorithm:</div>
{{ for (var port in it.poolsConfigs[pool].ports) { }}
<div class="coinInfoData">{{= it.poolsConfigs[pool].ports[port].label ? it.poolsConfigs[pool].ports[port].label : 'URL'}} <span class="coinInfoSubtle">(diff {{=it.poolsConfigs[pool].ports[port].diff}})</span></div>
{{ } }}
</div>
<div class="coinInfoRowValues">
<div class="coinInfoUsername">
{{ if (it.poolsConfigs[pool].coin && it.poolsConfigs[pool].coin.privateChain) { }}
your {{=it.poolsConfigs[pool].coin.name}} <b style="color:#C99631;">zs1</b> sapling address<br>
{{ } else if (it.poolsConfigs[pool].coin) { }}
your {{=it.poolsConfigs[pool].coin.name}} wallet address
{{ } else { }}
your public key
{{ } }}
</div>
<div>anything</div>
<div>{{=it.poolsConfigs[pool].coin.algorithm}}</div>
{{ for (var port in it.poolsConfigs[pool].ports) { }}
<div class="coinInfoData">stratum+tcp://{{=it.portalConfig.website.stratumHost}}:{{=port}}</div>
{{ } }}
</div>
</div>
</code>
{{ } }}
<div class="content">
If you have multiple mining rigs you can add a label at the end of your username to see stats broken down by rig on the worker stats page.
</div>
<code style="word-break:break-all;">
<b><em>DSTM</em></b><br>
zm --server {{=it.portalConfig.website.stratumHost}} --port {{= Object.keys(it.poolsConfigs[Object.keys(it.poolsConfigs)[0]].ports)[0] }} --user zs1gfnu0j84arzuv4dauryyvys07m0p5vwd8grl4whz08y769jmzj7zar84hewngtgskce4vex4udc.<span style="text-decoration:underline; font-weight:900;">myrigname</span> --pass x -dev 0 1 --temp-target=0:70,1:70 --intensity=0:0.5,1:0.5 --color --time
</code>
<code style="word-break:break-all;">
<b><em>EWBF</em></b><br>
miner --server {{=it.portalConfig.website.stratumHost}} --user zs1gfnu0j84arzuv4dauryyvys07m0p5vwd8grl4whz08y769jmzj7zar84hewngtgskce4vex4udc.<span style="text-decoration:underline; font-weight:900;">myrigname</span> --pass x --port {{= Object.keys(it.poolsConfigs[Object.keys(it.poolsConfigs)[0]].ports)[0] }} --fee 0 --pec --templimit 70 --intensity 50
</code>
<code style="word-break:break-all;">
<b><em>BMINER</em></b><br>
bminer -uri stratum://zs1gfnu0j84arzuv4dauryyvys07m0p5vwd8grl4whz08y769jmzj7zar84hewngtgskce4vex4udc.<span style="text-decoration:underline; font-weight:900;">myrigname</span>@{{=it.portalConfig.website.stratumHost}}:{{= Object.keys(it.poolsConfigs[Object.keys(it.poolsConfigs)[0]].ports)[0] }} -max-temperature 70 -nofee
</code>
{{ } }}
</div>
<div class="menuHeader" id="payments">Payments</div>
<div class="content">
On the sapling pool, payouts should take anywhere from 10 to 30 minutes.<br><br>
There is a limit of 200 receipients that can be included in a payout, hence the high min payout set on the pool. If payments stop going out, do not worry! Funds are safu! Blocks can still be found and will be credited to your username!<br><br>
Most likely the min payout of the pool needs to be adjusted upwards. Please check the <a href="https://discord.gg/5f7p3vx">#pools-and-operators channel in discord</a> to see if it's already being worked on. <br><br>
The longer it takes to make a payout, the more people meet the min payout making the following payout take longer. If you scroll down the payments page compare the number of miners paid versus the time between payments and you will see the correlation.<br><br>
Pending is supposed to be time to maturity before a block gets paid which I have set to 10 to try to coincide with dPoW, but I have doubts this is working right and believe it's just a visual change (need to verify this in the code)<br><br>
Immature and balance on your worker stats page are the unpaid balances accrued from previous payout rounds, it does not count blocks that have not yet been attempted to be paid by the pool<br><br>
Payments that show up on the payments page initially are in the process of constructing the z transaction, once it actually broadcasts the transaction it will switch to being hyperlinked and then should arrive in miners' wallets in the next block or two.
</div>
<div class="menuHeader" id="createWallet">Generate Wallet and Address</div>
<div class="content">
<a href="https://pirate.black/wallets/" target="_blank" rel="noopener noreferrer">GUI Wallet for PIRATE</a> is available. For Agama support please visit <a href="https://discord.gg/5f7p3vx">#newpirates and #agama-wallet on Discord</a><br><br>
CLI Wallet:
<ol>
<li><a href="https://docs.komodoplatform.com/komodo/install-Komodo-manually.html" target="_blank">Build Komodo</a></li>
<li>Launch PIRATE chain:
<code>
./komodod -ac_name=PIRATE -ac_supply=0 -ac_reward=25600000000 -ac_halving=77777 -ac_private=1 -addnode=136.243.102.225
</code>
</li>
<li>Generate Z address:
<code>
./komodo-cli -ac_name=PIRATE z_getnewaddress
</code>
</li>
<li>Securely backup your private key:
<code>
./komodo-cli -ac_name=PIRATE z_exportkey "zaddr"
</code>
</li>
<li>Check your balance:
<code>
./komodo-cli -ac_name=PIRATE z_gettotalbalance
</code>
<li>
For more information visit the <a href="https://pirate.black/" target="_blank">project website</a>
</li>
</ol>
</div>
<div class="menuHeader" id="gpuMining">GPU Mining</div>
<div class="content">
<p>
There are a few decent GPU miners available. You will need to experiment to find which one works best for you. DYOR on this and be sure to virus scan all the things!
</p>
<p>
Here are a couple well-known GPU miners:
</p>
<ul>
<li><a href="https://bitcointalk.org/index.php?topic=2021765.0" target="_blank" rel="noopener noreferrer">dstm's ZCash / Equihash Nvidia Miner</a></li>
<li><a href="https://bitcointalk.org/index.php?topic=1707546.0" target="_blank" rel="noopener noreferrer">EWBF's CUDA Zcash miner 0.3.4b</a></li>
<li><a href="https://www.bminer.me/releases/" target="_blank" rel="noopener noreferrer">Bminer Lite</a></li>
<li><a href="https://bitcointalk.org/index.php?topic=1670733.0" target="_blank" rel="noopener noreferrer">Claymore's ZCash/BTG AMD GPU Miner</a></li>
</ul>
</div>
<div class="menuHeader" id="cpuMining">CPU Mining</div>
<div class="content">
<p>While it is possible to CPU mine with <b>komodod</b> directly like so:</p>
<code>
./komodo-cli -ac_name=PIRATE setgenerate true
</code>
<p>The chances to find a block solo with CPU mining only are already fairly low and most likely the reason you are here at all 🐸</p>
<p>The well-known CPU miner that can be used with the pool is <b>nheqminer</b>. This does <i>not</i> require a Nicehash account and can be used to connect to any equihash stratum.</p>
<h4>Linux</h4>
<p>It is suggested that you attempt to build the CPU miner instead of using the pre-compiled binary so that optimizations for your CPU can be made during the build process</p>
<code>
sudo apt-get install cmake build-essential libboost-all-dev<br>
cd ~<br>
git clone -b Linux https://github.com/nicehash/nheqminer.git<br>
cd ~/nheqminer/cpu_xenoncat/Linux/asm/<br>
sh assemble.sh<br>
cd /home/zcash/nheqminer/Linux_cmake/nheqminer_cpu<br>
cmake . && make<br>
ln -s /home/zcash/nheqminer/Linux_cmake/nheqminer_cpu/nheqminer_cpu /usr/local/bin/nheqminer_cpu
</code>
<p>Now you can launch your miner! (replace the values as indicated changing the number of threads (-t) and your address for payouts (-u)</p>
<code>
nheqminer_cpu -t <i>numberofthreads</i> -l <i>stratumhost</i>:<i>stratumport</i> -u <i>youraddress</i>
</code>
<h4>Windows</h4>
<p>Download and install the latest release for windows from <a href="https://github.com/nicehash/nheqminer/releases" target="_blank" rel="noopener noreferrer">the github repo</a></p>
<p>Replace the placeholders below as needed and start mining!</p>
<code>
nheqminer -t <i>numberofthreads</i> -l <i>stratumhost</i>:<i>stratumport</i> -u <i>youraddress</i>
</code>
<h4>Additional Resources</h4>
<ul>
<li><a href="https://github.com/nicehash/nheqminer" target="_blank" rel="noopener noreferrer">nheqminer repo</a></li>
<li><a href="https://steemit.com/mining/@bobinson/zcash-cpu-mining-setup-on-linux" target="_blank" rel="noopener noreferrer">CPU Mining</a></li>
</ul>
</div>
</div>
</div>
{{ if (it.portalConfig.gettingStartedPopups) { }}
<a href="#" id="coinInfoBackground" class="hidden"></a>
<div id="coinInfo" class="hidden">
<a href="#" id="coinInfoClose">×</a>
<div><span class="coinInfoName"></span> Configuration:</div>
<div id="coinInfoRows">
<div id="coinInfoRowKeys">
<div>Username:</div>
<div>Password:</div>
</div>
<div id="coinInfoRowValues">
<div id="coinInfoUsername"></div>
<div>anything</div>
</div>
</div>
</div>
<script>
function showCoinConfig(info){
var htmlKeys = '<div class="coinInfoData">Algorithm:</div>';
var htmlValues = '<div class="coinInfoData">' + info.algo + '</div>';
for (var port in info.ports){
htmlKeys += '<div class="coinInfoData">URL <span class="coinInfoSubtle">(difficulty ' + info.ports[port].diff + ')</span>:</div>';
htmlValues += '<div class="coinInfoData">stratum+tcp://' + info.host + ':' + port + '</div>';
}
if (info.coin && info.coin.privateChain) {
$('#coinInfoUsername').html('your ' + info.coin.name + ' <b style="color:#C99631;">Z</b> wallet address');
} else if (info.coin) {
$('#coinInfoUsername').text('your ' + info.coin.name + ' wallet address');
} else {
$('#coinInfoUsername').text('your public key');
}
$('.coinInfoData').remove();
$('#coinInfoRowKeys').append(htmlKeys);
$('#coinInfoRowValues').append(htmlValues);
}
$('.poolOption').click(function(event){
event.preventDefault();
showCoinConfig($(this).data('info'));
$('#coinInfoBackground,#coinInfo').removeClass('hidden');
$('#coinInfoBackground').css('opacity', 0.7);
return false;
});
$('#coinInfoBackground,#coinInfoClose').click(function(event){
event.preventDefault();
$('#coinInfoBackground,#coinInfo').addClass('hidden');
$('#coinInfoBackground').css('opacity', 0.0);
return false;
});
</script>
{{ } }}

147
website/zznomp/pages/home.html

@ -0,0 +1,147 @@
<div class="pure-g-r" id="boxWelcome">
<div class="pure-u-1" style="text-align:center; padding:10px 0;">
<div class="pure-u-1-2">
<img src="/static/skull256.png" style="float:left; width:128px;" alt="zz nomp">
<div>
<div style="font-size: 2em; text-align:center; margin-bottom:10px; font-weight:900; color:#1F152A;">zz nomp</div>
<div style="text-align:center;" class="pure-g-r">
<div class="pure-u-1-2" style="text-align:right;">
For Pirate Chain »&nbsp;&nbsp;&nbsp;
</div>
<div class="pure-u-1-2" style="text-align:left;">
<div class="pure-g-r">
<div class="pure-u-1-2" style="text-align:left;">
<a href="https://pirate.black/" target="_blank" rel="noopener noreferrer"><i class="fa fa-globe fa-fw"></i> Website</a><br>
<a href="https://github.com/PirateNetwork" target="_blank" rel="noopener noreferrer"><i class="fab fa-github fa-fw"></i> Github</a><br>
<a href="https://bitcointalk.org/index.php?topic=4979549" target="_blank" rel="noopener noreferrer"><i class="fab fa-bitcoin fa-fw"></i> BTT</a>
</div>
<div class="pure-u-1-2" style="text-align:left;">
<a href="http://pirate.explorer.dexstats.info/" target="_blank" rel="noopener noreferrer"><i class="fas fa-map fa-fw"></i> Explorer</a><br>
<a href="https://discord.gg/5f7p3vx" target="_blank" rel="noopener noreferrer"><i class="fab fa-discord fa-fw"></i> Discord</a><br>
<a href="https://twitter.com/PirateChain" target="_blank" rel="noopener noreferrer"><i class="fab fa-twitter fa-fw"></i> Twitter</a>
</div>
<div class="pure-u-1">
<a href="https://digitalprice.io/?inviter=4fdaf7" target="_blank" rel="noopener noreferrer"><i class="fas fa-chart-line fa-fw"></i> Trading at DigitalPrice.io</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="pure-u-1" style="text-align:center; padding:10px 0;">
<table style="width: auto;margin: 0 auto;text-align: left;">
<tr><td>Payout Frequency:</td><td>~20 Minutes</td></tr>
<tr><td>Min Payout:</td><td>10 ARRR (256 for SPROUT pool)</td></tr>
<tr><td>Pool Fee:</td><td>1%</td></tr>
<tr><td colspan="2">
<br>
<em>1/3rd of the pool fee is donated to the PIRATE <a href="https://dexstats.info/onboarding.php" target="_blank" rel="noopener noreferrer">onboarding</a> <a href="http://pirate.explorer.dexstats.info/address/RAzq6y7dsUKgfuzNjpzyGiuFzvrwuDheQw" target="_blank" rel="noopener noreferrer">fund</a>
<br> and 1/3rd is donated to <a href="http://pirate.explorer.dexstats.info/address/RD5PhyAUhapsvj5ps2cCHozsXZfQSvDdrZ" target="_blank" rel="noopener noreferrer">PIRATE Marketing</a>!</em>
<br><br>
<a name="sapling"></a>
<span style="font-size:1.5em; color:#800000; font-weight:900;text-shadow: 4px 4px 2px #624c4c;">SAPLING Pool has been activated!</span>
<br><br>
Please create a sapling address (<span style="color:#800000; font-weight:900;text-shadow: 4px 4px 2px #624c4c;">starts with zs1</span>) and connect to the<br>
stratum ports labeled as <strong><em>arrr</em></strong> on <a href="/getting_started" class="hot-swapper">Getting Started</a>.
<br><br>
Target for shut down of sprout stratum is <span style="color:#800000; font-weight:900;text-shadow: 4px 4px 2px #624c4c;">2018-12-20!</span>
<br><br>
<span style="color:#800000; font-weight:900;text-shadow: 4px 4px 2px #624c4c;">Why should I switch?</span><br>
Min payout has been significantly reduced for the sapling pool only<br>
(original pool still at 256) and may be reduced further in the future,<br>
but we need more data to determine the proper min payout.
<br><br>
Also sapling payments significantly reduce the load on the server, so<br>
the stratum and website will respond faster!
<br><br>
There is only a 2 month window for the transition to sapling, so we<br>
need all the funds moved to your own wallets so you can migrate them<br>
to sapling with plenty of time.
<br><br>
So please switch as soon as possible to get your ARRR delivered faster!
<br><br>
<span style="color:#800000; font-weight:900;text-shadow: 4px 4px 2px #624c4c;">What about balances in my old address?</span><br>
Once all (most?) miners have switched over, final payout of the sprout<br>
pool will be made with no minimum balance.
<br><br>
Alternative pools:
<a href="https://piratechain.org/" target="_blank" rel="noopener noreferrer">PirateChain.org</a>
<a href="https://polly.chainstrike.io" target="_blank" rel="noopener noreferrer">Polly</a>
<a href="http://minethepiratechain.black" target="_blank" rel="noopener noreferrer">MTPC</a>
<a href="http://pirate.bcmonster.com/" target="_blank" rel="noopener noreferrer">BCMonster</a>
<a href="http://pirate.coolmine.top/" target="_blank" rel="noopener noreferrer">CoolMine</a>
</td></tr>
</table>
</div>
</div>
<div class="pure-g-r" id="boxesLower">
<div class="pure-u-1-2">
<div class="boxStats" id="boxStatsLeft">
<div class="boxLowerHeader">Network Stats</div>
<div class="boxStatsList">
{{ for(var pool in it.stats.pools) { }}
<div>
<div><i class="fas fa-coins fa-fw"></i> {{=pool}}</div>
<div><i class="fas fa-link fa-fw" aria-hidden="true"></i> Block Height: <span id="statsNetworkBlocks{{=pool}}">{{=it.stats.pools[pool].poolStats.networkBlocks}}</span></div>
<div><i class="fas fa-tachometer-alt fa-fw"></i> Network Hash/s: <span id="statsNetworkSols{{=pool}}">{{=it.stats.pools[pool].poolStats.networkSolsString}}</span></div>
<div><i class="fas fa-unlock-alt fa-fw" aria-hidden="true"></i> Difficulty: <span id="statsNetworkDiff{{=pool}}">{{=it.stats.pools[pool].poolStats.networkDiff}}</span></div>
<div><i class="fas fa-users fa-fw"></i> Node Connections: <span id="statsNetworkConnections{{=pool}}">{{=it.stats.pools[pool].poolStats.networkConnections}}</span></div>
</div>
{{ } }}
</div>
</div>
</div>
<div class="pure-u-1-2">
<div class="boxStats" id="boxStatsRight">
<div class="boxLowerHeader">Pools / Coins</div>
<div class="boxStatsList">
{{ for(var pool in it.stats.pools) { }}
<div>
<div><i class="fas fa-coins fa-fw"></i> {{=pool}}</div>
<div><i class="fas fa-users fa-fw"></i> <span id="statsMiners{{=pool}}">{{=it.stats.pools[pool].minerCount}}</span> Miners</div>
<div><i class="fas fa-rocket fa-fw"></i> <span id="statsWorkers{{=pool}}">{{=it.stats.pools[pool].workerCount}}</span> Workers</div>
<div><i class="fas fa-tachometer-alt fa-fw"></i> <span id="statsHashrate{{=pool}}">{{=it.stats.pools[pool].hashrateString}}</span> (Now)</div>
<div><i class="fas fa-tachometer-alt fa-fw"></i> <span id="statsHashrateAvg{{=pool}}">...</span> (Avg)</div>
<div><i class="fas fa-dice fa-fw"></i> Luck <span id="statsLuckDays{{=pool}}">{{=it.stats.pools[pool].luckDays}}</span> Days</div>
</div>
{{ } }}
</div>
</div>
</div>
</div>
<script type="text/javascript" src="/static/home.js" />
<script>
//document.querySelector('main').appendChild(document.createElement('script')).src = '/static/stats.js';
$(function() {
window.statsSource = new EventSource("/api/live_stats");
statsSource.addEventListener('message', function (e) {
var stats = JSON.parse(e.data);
for (var pool in stats.pools) {
$('#statsMiners' + pool).text(stats.pools[pool].minerCount);
$('#statsWorkers' + pool).text(stats.pools[pool].workerCount);
$('#statsHashrate' + pool).text(stats.pools[pool].hashrateString);
$('#statsHashrateAvg' + pool).text(getReadableHashRateString(calculateAverageHashrate(pool)));
$('#statsLuckDays' + pool).text(stats.pools[pool].luckDays);
$('#statsValidBlocks' + pool).text(stats.pools[pool].poolStats.validBlocks);
$('#statsTotalPaid' + pool).text((parseFloat(stats.pools[pool].poolStats.totalPaid)).toFixed(8));
$('#statsNetworkBlocks' + pool).text(stats.pools[pool].poolStats.networkBlocks);
$('#statsNetworkDiff' + pool).text(stats.pools[pool].poolStats.networkDiff);
$('#statsNetworkSols' + pool).text(getReadableNetworkHashRateString(stats.pools[pool].poolStats.networkSols));
$('#statsNetworkConnections' + pool).text(stats.pools[pool].poolStats.networkConnections);
}
for (algo in stats.algos) {
$('#statsMiners' + algo).text(stats.algos[algo].workers);
$('#statsHashrate' + algo).text(stats.algos[algo].hashrateString);
}
});
});
</script>

28
website/zznomp/pages/miner_stats.html

@ -0,0 +1,28 @@
<div id="topCharts">
<div class="chartWrapper">
<div class="chartLabel">
<!--<div style="float:left; padding-right: 18px;"><i class="fa fa-users"></i><span id="statsWorkers">...</span></div>-->
<div style="float:left; margin-right: 9px;">{{=String(it.stats.address).split(".")[0].length > 40 ? String(it.stats.address).split(".")[0].substring(0, 20) + '...' + String(it.stats.address).split(".")[0].substring(String(it.stats.address).split(".")[0].length-20, String(it.stats.address).split(".")[0].length): String(it.stats.address).split(".")[0]}}</div>
<div style="float:right; padding-left: 18px;"><small><i class="fas fa-tachometer-alt fa-fw"></i> <span id="statsHashrateAvg">...</span> (Avg)</small></div>
<div style="float:right; padding-left: 18px;"><small><i class="fas fa-tachometer-alt fa-fw"></i> <span id="statsHashrate">...</span> (Now)</small></div>
<div style="float:right; padding-left: 18px;"><small><i class="fas fa-dice fa-fw"></i> Luck <span id="statsLuckDays">...</span> Days</small></div>
</div>
<div class="chartHolder"><svg id="workerHashrate"></svg></div>
<div>
<div style="float:right; padding-top: 9px; padding-right: 18px;"><i class="fas fa-cog fa-fw"></i> Shares: <span id="statsTotalShares">...</span></div>
<div style="float:left; padding-top: 9px; padding-left: 18px; padding-right: 18px;"><i class="fas fa-money-bill-wave fa-fw"></i> Immature: <span id="statsTotalImmature">...</span> </div>
<div style="float:left; padding-top: 9px; padding-left: 18px; padding-right: 18px;"><i class="fas fa-money-bill-wave fa-fw"></i> Bal: <span id="statsTotalBal">...</span> </div>
<div style="padding-top: 9px; padding-left: 18px;"><i class="fas fa-money-bill-wave fa-fw"></i> Paid: <span id="statsTotalPaid">...</span> </div>
</div>
</div>
</div>
<div id="boxesWorkers"> </div>
<script>
var _miner = "{{=String(it.stats.address).split(".")[0]}}";
var _workerCount = 0;
window.statsSource = new EventSource("/api/live_stats");
document.querySelector('main').appendChild(document.createElement('script')).src = '/static/miner_stats.js';
</script>

25
website/zznomp/pages/mining_key.html

@ -0,0 +1,25 @@
<style>
#miningKeyPage{
margin: 15px;
}
#keyFrame{
padding: 0;
border: 0;
width: 100%;
height: 750px;
display: block;
}
</style>
<div id="miningKeyPage">
<p>
This script run client-side (in your browser). For maximum security <a href="/key.html" download="key.html">download</a> the script and run it locally and
offline in a modern web browser.
</p>
<iframe id="keyFrame" src="/key.html">
</iframe>
</div>

61
website/zznomp/pages/payments.html

@ -0,0 +1,61 @@
<script type="text/javascript">
$(function () {
$(document).tooltip({
content: function () {
return $(this).prop('title');
},
show: null,
close: function (event, ui) {
ui.tooltip.hover(
function () {
$(this).stop(true).fadeTo(400, 1);
},
function () {
$(this).fadeOut("400", function () {
$(this).remove();
})
});
}
});
});
</script>
{{ function readableDate(a){ return new Date(parseInt(a)).toISOString().substring(0, 16).replace('T', ' ') + ' UTC'; } }}
{{ for(var pool in it.stats.pools) { }}
<table class="pure-table">
<thead>
<tr>
<th>Blocks</th>
<th>Time</th>
<th>Miners</th>
<th>Shares</th>
<th>Amount</th>
</tr>
</thead>
{{ for(var p in it.stats.pools[pool].payments) { }}
<tr>
<td class="paymentblocks" title="{{=it.stats.pools[pool].payments[p].opid}}">
{{if (String(it.stats.pools[pool].name).startsWith("zcash")) { }}
<a href="https://explorer.zcha.in/tx/{{=it.stats.pools[pool].payments[p].txid}}" title="View transaction" target="_blank">{{=it.stats.pools[pool].payments[p].blocks}}</a>
{{ } else if (String(it.stats.pools[pool].name).startsWith("zclassic")) { }}
<a href="https://classic.zcha.in/tx/{{=it.stats.pools[pool].payments[p].txid}}" title="View transaction" target="_blank">{{=it.stats.pools[pool].payments[p].blocks}}</a>
{{ } else if (String(it.stats.pools[pool].name).startsWith("hush")) { }}
<a href="https://explorer.myhush.org/tx/{{=it.stats.pools[pool].payments[p].txid}}" title="View transaction" target="_blank">{{=it.stats.pools[pool].payments[p].blocks}}</a>
{{ } else if (String(it.stats.pools[pool].name).startsWith("zen")) { }}
<a href="http://node1.zenchain.info:8886/tx/{{=it.stats.pools[pool].payments[p].txid}}" title="View transaction" target="_blank">{{=it.stats.pools[pool].payments[p].blocks}}</a>
{{ } else if (typeof it.stats.pools[pool].payments[p].txid !== 'undefined' && (String(it.stats.pools[pool].name).startsWith("pirate") || String(it.stats.pools[pool].name).startsWith("arrr")) ) { }}
<a href="https://explorer.pirate.black/tx/{{=it.stats.pools[pool].payments[p].txid}}" title="View transaction" target="_blank">{{=it.stats.pools[pool].payments[p].blocks}}</a>
{{ } else { }}
{{=it.stats.pools[pool].payments[p].blocks}}
{{ } }}
</td>
<td>{{=readableDate(it.stats.pools[pool].payments[p].time)}}</td>
<td>{{=it.stats.pools[pool].payments[p].miners}}</td>
<td>{{=Math.round(it.stats.pools[pool].payments[p].shares)}}</td>
<td>{{=it.stats.pools[pool].payments[p].paid}} {{=it.stats.pools[pool].symbol}}</td>
</tr>
{{ } }}
</table>
</div>
{{ } }}

261
website/zznomp/pages/stats.html

@ -0,0 +1,261 @@
<div id="topCharts">
<div class="chartWrapper">
<div class="chartLabel">Pool Historical Hashrate</div>
<div class="chartHolder"><svg id="poolHashrate"></svg></div>
</div>
</div>
{{ function capitalizeFirstLetter(t){return t.charAt(0).toUpperCase()+t.slice(1)} }}
{{ function readableDate(a){ return new Date(parseInt(a)).toISOString().substring(0, 16).replace('T', ' ') + ' UTC'; } }}
<div class="pure-g-r" id="boxesLower">
{{ for(var pool in it.stats.pools) { }}
<div class="pure-u-1-2">
<div class="boxStats" id="boxStatsLeft">
<div class="boxLowerHeader">{{=it.stats.pools[pool].name}} Pool Stats</div>
<div class="boxStatsList">
<div>
<div><i class="fas fa-users fa-fw"></i> <span id="statsMiners{{=pool}}">{{=it.stats.pools[pool].minerCount}}</span> Miners</div>
<div><i class="fas fa-rocket fa-fw"></i> <span id="statsWorkers{{=pool}}">{{=it.stats.pools[pool].workerCount}}</span> Workers</div>
<div><i class="fas fa-tachometer-alt fa-fw"></i> <span id="statsHashrate{{=pool}}">{{=it.stats.pools[pool].hashrateString}}</span> (Now)</div>
<div><i class="fas fa-tachometer-alt fa-fw"></i> <span id="statsHashrateAvg{{=pool}}">...</span> (Avg)</div>
<div><i class="fas fa-dice fa-fw"></i> Luck <span id="statsLuckDays{{=pool}}">{{=it.stats.pools[pool].luckDays}}</span> Days</div>
</div>
</div>
</div>
</div>
<div class="pure-u-1-2">
<div class="boxStats" id="boxStatsRight">
<div class="boxLowerHeader">{{=it.stats.pools[pool].name}} Network Stats</div>
<div class="boxStatsList">
<div>
<div><i class="fas fa-link fa-fw" aria-hidden="true"></i> Block Height: <span id="statsNetworkBlocks{{=pool}}">{{=it.stats.pools[pool].poolStats.networkBlocks}}</span></div>
<div><i class="fas fa-tachometer-alt fa-fw"></i> Network Hash/s: <span id="statsNetworkSols{{=pool}}">{{=it.stats.pools[pool].poolStats.networkSolsString}}</span></div>
<div><i class="fas fa-unlock-alt fa-fw" aria-hidden="true"></i> Difficulty: <span id="statsNetworkDiff{{=pool}}">{{=it.stats.pools[pool].poolStats.networkDiff}}</span></div>
<div><i class="fas fa-users fa-fw"></i> Node Connections: <span id="statsNetworkConnections{{=pool}}">{{=it.stats.pools[pool].poolStats.networkConnections}}</span></div>
</div>
</div>
</div>
</div>
{{ } }}
</div>
{{ for(var pool in it.stats.pools) { }}
{{ var blockscomb = new Array; }}
<div class="pure-g-r" id="boxesLower">
<div class="pure-u-1-1">
<div class="boxStats" id="boxStatsRight">
<div class="boxLowerHeader">{{=it.stats.pools[pool].name}} Blocks Found &nbsp;&nbsp;
<span style="float:right;"><small>
<i class="fas fa-link fa-fw"></i> <span id="statsValidBlocks{{=pool}}">{{=it.stats.pools[pool].poolStats.validBlocks}}</span> Blocks &nbsp;&nbsp;
<i class="fas fa-money-bill-wave fa-fw"></i> Paid: <span id="statsTotalPaid{{=pool}}">{{=(parseFloat(it.stats.pools[pool].poolStats.totalPaid)).toFixed(8)}}</span> {{=it.stats.pools[pool].symbol}}</small>&nbsp;&nbsp;</span>
</div>
<div class="boxStatsList" style="margin-top: 9px;">
<!--<div id="{{=it.stats.pools[pool].name}}NewBlocks"></div>-->
{{ for(var b in it.stats.pools[pool].pending.blocks) { }}
{{ var block = it.stats.pools[pool].pending.blocks[b].split(":"); }}
<div style="margin-bottom: 9px; background-color: #773938; min-width:600px;" title="{{if (it.stats.pools[pool].pending.confirms && it.stats.pools[pool].pending.confirms[block[0]]) { }}{{if (it.stats.pools[pool].pending.confirms[block[0]] == 1) { }}Waiting for dPoW notarization{{} else if (it.stats.pools[pool].pending.confirms[block[0]] < it.poolsConfigs[pool].paymentProcessing.minConf*2) { }}Waiting for min confirmations{{ } else { }}Queued for payment{{ } }}{{ } else { }}Waiting for payment processor to review{{ } }}">
<div>
<i class="fas fa-link fa-fw"></i>
<small>Block:</small>
<a href="https://explorer.pirate.black/block/{{=block[0]}}" target="_blank" rel="noopener noreferrer">{{=block[2]}}</a>
{{if (block[4] != null) { }}
<span style="padding-left: 18px;"><small>{{=readableDate(block[4])}}</small></span>
{{ } }}
{{if (it.stats.pools[pool].pending.confirms && it.stats.pools[pool].pending.confirms[block[0]]) { }}
{{if (it.stats.pools[pool].pending.confirms[block[0]] == 1) { }}
<span style="float:right; color: red;"><small>Waiting for Notarization</small></span>
{{ } else { }}
<span style="float:right; color: red;"><small>{{=it.stats.pools[pool].pending.confirms[block[0]]}} of {{=it.poolsConfigs[pool].paymentProcessing.minConf*2}} Confirmations</small></span>
{{ } }}
{{ } else { }}
<span style="float:right; color: red;"><small>*PENDING*</small></span>
{{ } }}
</div>
<div><i class="fas fa-crown fa-fw"></i> <small>Mined By:</small> <a href="/workers/{{=block[3].split('.')[0]}}">{{=block[3].length > 40 ? block[3].substring(0, 20) + '...' + block[3].substring(block[3].length-20, block[3].length): block[3]}}</a></div>
</div>
{{ blockscomb.push(block);}}
{{ } }}
{{ var i=0; for(var b in it.stats.pools[pool].confirmed.blocks) { }}
{{ if (i < 8) { i++; }}
{{ var block = it.stats.pools[pool].confirmed.blocks[b].split(":"); }}
<div style="margin-bottom: 9px; background-color: #C99631; min-width:600px;" title="Payment sent, please check payments page">
<div>
<i class="fas fa-link fa-fw"></i>
<small>Block:</small>
<a href="https://explorer.pirate.black/block/{{=block[0]}}" target="_blank" rel="noopener noreferrer">{{=block[2]}}</a>
{{if (block[4] != null) { }}
<span style="padding-left: 18px;"><small>{{=readableDate(block[4])}}</small></span>
{{ } }}
<span style="float:right; padding-left: 18px; color: green;"><small>*PAID*</small></span>
</div>
<div><i class="fas fa-crown fa-fw"></i> <small>Mined By:</small> <a href="/workers/{{=block[3].split('.')[0]}}">{{=block[3].length > 40 ? block[3].substring(0, 20) + '...' + block[3].substring(block[3].length-20, block[3].length): block[3]}}</a></div>
</div>
{{blockscomb.push(block);}}
{{ } }}
{{ } }}
</div>
</div>
</div>
</div>
{{if (blockscomb.length > 0) { }}
<div id="bottomCharts{{=pool}}" style="text-align:center;" align="center">
<div class="chartWrapper" style="text-align:center;">
<div class="chartLabel">Finders of the last {{=blockscomb.length}} blocks</div>
<div class="chartHolder" id="pie{{=pool}}"><svg id="blocksPie{{=pool}}" style="display: block; margin: auto; text-align:center;"/></div>
<div class="hidden tooltip" id="tooltip{{=pool}}"><p><span id="value{{=pool}}"></span> blocks found by <span id="finderr{{=pool}}"></span></p></div>
</div>
</div>
<script>
var blockscomb = ({{=JSON.stringify(blockscomb)}})
var groupedByFinder = {};
var data = [];
for (var i=0; i < blockscomb.length; i++) {
finder=blockscomb[i][3]; // if other doesn 't already have a property for the current letter
// create it and assign it to a new empty array
if (!(finder in groupedByFinder))
groupedByFinder[finder] = [];
groupedByFinder[finder].push(blockscomb[i]);
}
Object.keys(groupedByFinder).forEach(function(i) {
var obj = {};
obj.label = i
obj.value = groupedByFinder[i].length
data.push(obj)
});
//console.log(JSON.stringify(data))
var w = 1000;
var h = 500;
var r = h/2.5;
var legendRectSize = 18;
var legendSpacing = 5;
var color = d3.scale.category20c();
/*var div = d3.select("#pie{{=pool}}").append("div")
.attr("class", "tooltip")
.style("opacity", 0);*/
var vis = d3.select('#blocksPie{{=pool}}')
.data([data])
.attr("width", w)
.attr("height", h)
.attr("style", "display: block; margin: auto; width:800px; height: auto; display:inline-block")
.attr("preserveAspectRatio", "xMidYMin")
.append("svg:g")
.attr("transform", "translate(" + r + "," + r + ")");
var pie = d3.layout.pie().value(function(d){return d.value;});
// declare an arc generator function
var arc = d3.svg.arc().outerRadius(r);
// select paths, use arc generator to draw
var arcs = vis.selectAll("g.slice{{=pool}}")
.data(pie)
.enter()
.append("svg:g")
.attr("class", "slice{{=pool}}")
.attr("id", "slice")
.on("mouseover", function(d){
d3.select("#tooltip{{=pool}}")
.attr("style", "left:" + (d3.event.layerX) + "px; top:" + (d3.event.layerY) + "px; opacity:1; display:block!important;position:absolute")
.select("#value{{=pool}}")
.text(d.data.value);
d3.select("#tooltip{{=pool}}")
.select("#finderr{{=pool}}")
.text(d.data.label.length > 40 ? d.data.label.substring(0, 20) + '...' + d.data.label.substring(d.data.label.length-20, d.data.label.length): d.data.label);
})
.on("mouseout", function(d) {
d3.select("#tooltip{{=pool}}")
.attr("style", "");
})
.on('mousemove', function(d) {
d3.select("#tooltip{{=pool}}")
.style('top', (d3.event.layerY) + 'px')
.style('left', (d3.event.layerX) + 'px');
});
arcs.append("svg:path")
.attr("fill", function(d, i){
return color(i);
})
.attr("d", function (d) {
return arc(d);
});
var legend = vis.selectAll('.legend')
.data(color.domain())
.enter()
.append('g')
.attr('class', 'legend')
.attr('id', {{=JSON.stringify(pool)}})
.attr('transform', function(d, i) {
var height = legendRectSize + legendSpacing;
var offset = height * color.domain().length / 2;
var horz = 13 * legendRectSize;
var vert = (i * height) - r + height;
return 'translate(' + horz + ',' + vert + ')';
});
legend.append('rect')
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.style('fill', color)
.style('stroke', color);
legend.append('text')
.attr('x', legendRectSize + legendSpacing)
.attr('y', legendRectSize - legendSpacing)
.text(function(d, i) {
return data[i].label.length > 40 ? data[i].label.substring(0, 20) + '...' + data[i].label.substring(data[i].label.length-20, data[i].label.length): data[i].label;
});
</script>
{{ } }}
{{ } }}
<script>
document.querySelector('main').appendChild(document.createElement('script')).src = '/static/stats.js';
$(function() {
window.statsSource = new EventSource("/api/live_stats");
statsSource.addEventListener('message', function (e) {
var stats = JSON.parse(e.data);
for (var pool in stats.pools) {
$('#statsMiners' + pool).text(stats.pools[pool].minerCount);
$('#statsWorkers' + pool).text(stats.pools[pool].workerCount);
$('#statsHashrate' + pool).text(stats.pools[pool].hashrateString);
$('#statsHashrateAvg' + pool).text(getReadableHashRateString(calculateAverageHashrate(pool)));
$('#statsLuckDays' + pool).text(stats.pools[pool].luckDays);
$('#statsValidBlocks' + pool).text(stats.pools[pool].poolStats.validBlocks);
$('#statsTotalPaid' + pool).text((parseFloat(stats.pools[pool].poolStats.totalPaid)).toFixed(8));
$('#statsNetworkBlocks' + pool).text(stats.pools[pool].poolStats.networkBlocks);
$('#statsNetworkDiff' + pool).text(stats.pools[pool].poolStats.networkDiff);
$('#statsNetworkSols' + pool).text(getReadableNetworkHashRateString(stats.pools[pool].poolStats.networkSols));
$('#statsNetworkConnections' + pool).text(stats.pools[pool].poolStats.networkConnections);
}
});
});
function getReadableNetworkHashRateString(hashrate){
hashrate = (hashrate * 1000000);
if (hashrate < 1000000)
return '0 Sol';
var byteUnits = [ ' Sol/s', ' KSol/s', ' MSol/s', ' GSol/s', ' TSol/s', ' PSol/s' ];
var i = Math.floor((Math.log(hashrate/1000) / Math.log(1000)) - 1);
hashrate = (hashrate/1000) / Math.pow(1000, i + 1);
return hashrate.toFixed(2) + byteUnits[i];
}
</script>

30
website/zznomp/pages/tbs.html

@ -0,0 +1,30 @@
<table class="pure-table">
<thead>
<tr>
<th>Pool</th>
<th>Algo</th>
<th>Workers</th>
<th>Valid Shares</th>
<th>Invalid Shares</th>
<th>Total Blocks</th>
<th>Pending</th>
<th>Confirmed</th>
<th>Orphaned</th>
<th>Hashrate</th>
</tr>
</thead>
{{ for(var pool in it.stats.pools) { }}
<tr>
<td>{{=it.stats.pools[pool].name}}</td>
<td>{{=it.stats.pools[pool].algorithm}}</td>
<td>{{=Object.keys(it.stats.pools[pool].workers).length}}</td>
<td>{{=it.stats.pools[pool].poolStats.validShares}}</td>
<td>{{=it.stats.pools[pool].poolStats.invalidShares}}</td>
<td>{{=it.stats.pools[pool].poolStats.validBlocks}}</td>
<td>{{=it.stats.pools[pool].blocks.pending}}</td>
<td>{{=it.stats.pools[pool].blocks.confirmed}}</td>
<td>{{=it.stats.pools[pool].blocks.orphaned}}</td>
<td>{{=it.stats.pools[pool].hashrateString}}</td>
</tr>
{{ } }}
</table>

60
website/zznomp/pages/workers.html

@ -0,0 +1,60 @@
<script type="text/javascript">
function searchKeyPress(e)
{
// look for window.event in case event isn't passed in
e = e || window.event;
if (e.keyCode == 13)
{
document.getElementById('btnSearch').click();
return false;
}
return true;
}
$(document).ready(function(){
$('.btn-lg').click(function(){
window.location = "workers/" + $('.input-lg').val();
});
});
</script>
{{ function capitalizeFirstLetter(t){return t.charAt(0).toUpperCase()+t.slice(1)} }}
{{ var i=0; for(var pool in it.stats.pools) { }}
<div id="topPool">
<div class="poolWrapper">
<div class="poolLabel">
<span style="float:right; margin-bottom: 8px;">
<small>Miner Lookup:
<input type="text" class="form-control input-lg" onkeypress="return searchKeyPress(event);">
<span class="input-group-btn">
<button class="btn btn-default btn-lg" type="button">Lookup</button>
</span>
</small>
</span>
{{=capitalizeFirstLetter(it.stats.pools[pool].name)}} Top Miners &nbsp;&nbsp;
<small><i class="fas fa-users fa-fw"></i> <span id="statsMiners{{=pool}}">{{=it.stats.pools[pool].minerCount}}</span> Miners &nbsp;&nbsp;
<i class="fas fa-rocket fa-fw"></i> <span id="statsWorkers{{=pool}}">{{=it.stats.pools[pool].workerCount}}</span> Workers &nbsp;&nbsp;
<i class="fas fa-cog fa-fw"></i> <span id="statsWorkers{{=pool}}">{{=it.stats.pools[pool].shareCount}}</span> Shares </small>
</div>
<div class="poolMinerTable">
<table class="pure-table">
<thead>
<tr>
<th>Address</th>
<th>Shares</th>
<th>Efficiency</th>
<th>Hashrate</th>
</tr>
</thead>
{{ for(var worker in it.stats.pools[pool].miners) { }}
{{var workerstat = it.stats.pools[pool].miners[worker];}}
<tr class="pure-table-odd">
<td><a href="/workers/{{=worker.split('.')[0]}}">{{=worker.length > 40 ? worker.substring(0, 20) + '...' + worker.substring(worker.length-20, worker.length): worker}}</a></td>
<td>{{=Math.round(workerstat.currRoundShares * 100) / 100}}</td>
<td>{{? workerstat.shares > 0}} {{=Math.floor(10000 * workerstat.shares / (workerstat.shares + workerstat.invalidshares)) / 100}}% {{??}} 0% {{?}}</td>
<td>{{=workerstat.hashrateString}}</td>
</tr>
{{ } }}
</table>
</div>
</div>
</div>
{{ } }}

100
website/zznomp/static/admin.js

@ -0,0 +1,100 @@
var docCookies = {
getItem: function (sKey) {
return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null;
},
setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) {
if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { return false; }
var sExpires = "";
if (vEnd) {
switch (vEnd.constructor) {
case Number:
sExpires = vEnd === Infinity ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; max-age=" + vEnd;
break;
case String:
sExpires = "; expires=" + vEnd;
break;
case Date:
sExpires = "; expires=" + vEnd.toUTCString();
break;
}
}
document.cookie = encodeURIComponent(sKey) + "=" + encodeURIComponent(sValue) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + (bSecure ? "; secure" : "");
return true;
},
removeItem: function (sKey, sPath, sDomain) {
if (!sKey || !this.hasItem(sKey)) { return false; }
document.cookie = encodeURIComponent(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + ( sDomain ? "; domain=" + sDomain : "") + ( sPath ? "; path=" + sPath : "");
return true;
},
hasItem: function (sKey) {
return (new RegExp("(?:^|;\\s*)" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie);
}
};
var password = docCookies.getItem('password');
function showLogin(){
$('#adminCenter').hide();
$('#passwordForm').show();
}
function showAdminCenter(){
$('#passwordForm').hide();
$('#adminCenter').show();
}
function tryLogin(){
apiRequest('pools', {}, function(response){
showAdminCenter();
displayMenu(response.result)
});
}
function displayMenu(pools){
$('#poolList').after(Object.keys(pools).map(function(poolName){
return '<li class="poolMenuItem"><a href="#">' + poolName + '</a></li>';
}).join(''));
}
function apiRequest(func, data, callback){
var httpRequest = new XMLHttpRequest();
httpRequest.onreadystatechange = function(){
if (httpRequest.readyState === 4 && httpRequest.responseText){
if (httpRequest.status === 401){
docCookies.removeItem('password');
$('#password').val('');
showLogin();
alert('Incorrect Password');
}
else{
var response = JSON.parse(httpRequest.responseText);
callback(response);
}
}
};
httpRequest.open('POST', '/api/admin/' + func);
data.password = password;
httpRequest.setRequestHeader('Content-Type', 'application/json');
httpRequest.send(JSON.stringify(data));
}
if (password){
tryLogin();
}
else{
showLogin();
}
$('#passwordForm').submit(function(event){
event.preventDefault();
password = $('#password').val();
if (password){
if ($('#remember').is(':checked'))
docCookies.setItem('password', password, Infinity);
else
docCookies.setItem('password', password);
tryLogin();
}
return false;
});

BIN
website/zznomp/static/favicon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 413 B

BIN
website/zznomp/static/favicon/android-icon-144x144.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
website/zznomp/static/favicon/android-icon-192x192.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

BIN
website/zznomp/static/favicon/android-icon-36x36.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
website/zznomp/static/favicon/android-icon-48x48.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
website/zznomp/static/favicon/android-icon-72x72.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
website/zznomp/static/favicon/android-icon-96x96.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
website/zznomp/static/favicon/apple-icon-114x114.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
website/zznomp/static/favicon/apple-icon-120x120.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

BIN
website/zznomp/static/favicon/apple-icon-144x144.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
website/zznomp/static/favicon/apple-icon-152x152.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
website/zznomp/static/favicon/apple-icon-180x180.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
website/zznomp/static/favicon/apple-icon-57x57.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
website/zznomp/static/favicon/apple-icon-60x60.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
website/zznomp/static/favicon/apple-icon-72x72.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
website/zznomp/static/favicon/apple-icon-76x76.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
website/zznomp/static/favicon/apple-icon-precomposed.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

BIN
website/zznomp/static/favicon/apple-icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

2
website/zznomp/static/favicon/browserconfig.xml

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig><msapplication><tile><square70x70logo src="/static/favicon/ms-icon-70x70.png"/><square150x150logo src="/static/favicon/ms-icon-150x150.png"/><square310x310logo src="/static/favicon/ms-icon-310x310.png"/><TileColor>#BB9645</TileColor></tile></msapplication></browserconfig>

BIN
website/zznomp/static/favicon/favicon-16x16.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 641 B

BIN
website/zznomp/static/favicon/favicon-32x32.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
website/zznomp/static/favicon/favicon-96x96.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
website/zznomp/static/favicon/favicon.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

41
website/zznomp/static/favicon/manifest.json

@ -0,0 +1,41 @@
{
"name": "App",
"icons": [
{
"src": "\/static\/favicon\/android-icon-36x36.png",
"sizes": "36x36",
"type": "image\/png",
"density": "0.75"
},
{
"src": "\/static\/favicon\/android-icon-48x48.png",
"sizes": "48x48",
"type": "image\/png",
"density": "1.0"
},
{
"src": "\/static\/favicon\/android-icon-72x72.png",
"sizes": "72x72",
"type": "image\/png",
"density": "1.5"
},
{
"src": "\/static\/favicon\/android-icon-96x96.png",
"sizes": "96x96",
"type": "image\/png",
"density": "2.0"
},
{
"src": "\/static\/favicon\/android-icon-144x144.png",
"sizes": "144x144",
"type": "image\/png",
"density": "3.0"
},
{
"src": "\/static\/favicon\/android-icon-192x192.png",
"sizes": "192x192",
"type": "image\/png",
"density": "4.0"
}
]
}

BIN
website/zznomp/static/favicon/ms-icon-144x144.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
website/zznomp/static/favicon/ms-icon-150x150.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
website/zznomp/static/favicon/ms-icon-310x310.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

BIN
website/zznomp/static/favicon/ms-icon-70x70.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

145
website/zznomp/static/home.js

@ -0,0 +1,145 @@
var poolHashrateData;
var poolHashrateChart;
var statData;
var poolKeys;
function buildChartData(){
var pools = {};
poolKeys = [];
for (var i = 0; i < statData.length; i++){
for (var pool in statData[i].pools){
if (poolKeys.indexOf(pool) === -1)
poolKeys.push(pool);
}
}
for (var i = 0; i < statData.length; i++) {
var time = statData[i].time * 1000;
for (var f = 0; f < poolKeys.length; f++){
var pName = poolKeys[f];
var a = pools[pName] = (pools[pName] || {
hashrate: []
});
if (pName in statData[i].pools){
a.hashrate.push([time, statData[i].pools[pName].hashrate]);
}
else{
a.hashrate.push([time, 0]);
}
}
}
poolHashrateData = [];
for (var pool in pools){
poolHashrateData.push({
key: pool,
values: pools[pool].hashrate
});
$('#statsHashrateAvg' + pool).text(getReadableHashRateString(calculateAverageHashrate(pool)));
}
}
function calculateAverageHashrate(pool) {
var count = 0;
var total = 1;
var avg = 0;
for (var i = 0; i < poolHashrateData.length; i++) {
count = 0;
for (var ii = 0; ii < poolHashrateData[i].values.length; ii++) {
if (pool == null || poolHashrateData[i].key === pool) {
count++;
avg += parseFloat(poolHashrateData[i].values[ii][1]);
}
}
if (count > total)
total = count;
}
avg = avg / total;
return avg;
}
function getReadableHashRateString(hashrate){
hashrate = (hashrate * 2);
if (hashrate < 1000000) {
return (Math.round(hashrate / 1000) / 1000 ).toFixed(2)+' Sol/s';
}
var byteUnits = [ ' Sol/s', ' KSol/s', ' MSol/s', ' GSol/s', ' TSol/s', ' PSol/s' ];
var i = Math.floor((Math.log(hashrate/1000) / Math.log(1000)) - 1);
hashrate = (hashrate/1000) / Math.pow(1000, i + 1);
return hashrate.toFixed(2) + byteUnits[i];
}
function timeOfDayFormat(timestamp){
var dStr = d3.time.format('%I:%M %p')(new Date(timestamp));
if (dStr.indexOf('0') === 0) dStr = dStr.slice(1);
return dStr;
}
function displayCharts(){
nv.addGraph(function() {
poolHashrateChart = nv.models.lineChart()
.margin({left: 80, right: 30})
.x(function(d){ return d[0] })
.y(function(d){ return d[1] })
.useInteractiveGuideline(true);
poolHashrateChart.xAxis.tickFormat(timeOfDayFormat);
poolHashrateChart.yAxis.tickFormat(function(d){
return getReadableHashRateString(d);
});
d3.select('#poolHashrate').datum(poolHashrateData).call(poolHashrateChart);
return poolHashrateChart;
});
}
function triggerChartUpdates(){
poolHashrateChart.update();
}
nv.utils.windowResize(triggerChartUpdates);
$.getJSON('/api/pool_stats', function(data){
statData = data;
buildChartData();
});
$(function() {
statsSource.addEventListener('message', function(e){
var stats = JSON.parse(e.data);
statData.push(stats);
var newPoolAdded = (function(){
for (var p in stats.pools){
if (poolKeys.indexOf(p) === -1)
return true;
}
return false;
})();
if (newPoolAdded || Object.keys(stats.pools).length > poolKeys.length){
buildChartData();
displayCharts();
}
else {
var time = stats.time * 1000;
for (var f = 0; f < poolKeys.length; f++) {
var pool = poolKeys[f];
for (var i = 0; i < poolHashrateData.length; i++) {
if (poolHashrateData[i].key === pool) {
poolHashrateData[i].values.shift();
poolHashrateData[i].values.push([time, pool in stats.pools ? stats.pools[pool].hashrate : 0]);
$('#statsHashrateAvg' + pool).text(getReadableHashRateString(calculateAverageHashrate(pool)));
break;
}
}
}
//triggerChartUpdates();
}
});
});

13
website/zznomp/static/kmdfavicon.svg

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 72 72" style="enable-background:new 0 0 72 72;" xml:space="preserve">
<style type="text/css">
.st0{fill:#316565;}
.st1{fill:#FFFFFF;}
</style>
<rect x="0" y="0" class="st0" width="72" height="72"/>
<path class="st1" d="M35.9,65.4l20.8-8.5l8.7-20.8l-8.5-21L36.1,6.6l-20.8,8.5v0.2L6.6,36.1l8.5,20.8L35.9,65.4z M23,22.9L23,22.9
l13.1-5.5l13.1,5.5l5.5,13.1l-5.5,13.1l-13.1,5.5L23,49.2l-5.5-13.1L23,22.9z"/>
<polygon class="st1" points="36,46.9 43.7,43.7 46.9,35.9 43.7,28.3 36,25.1 28.4,28.3 25.2,35.9 28.2,43.7 "/>
</svg>

After

Width:  |  Height:  |  Size: 797 B

BIN
website/zznomp/static/komodo-logo-horizontal-01.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

13
website/zznomp/static/logo.svg

@ -0,0 +1,13 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" width="350px" height="350px" viewBox="0 0 350 350" enable-background="new 0 0 350 350" xml:space="preserve" xmlns:xml="http://www.w3.org/XML/1998/namespace">
<g>
<path fill="#F48438" d="M138,346H93c0,0-9,0-9-9s0-18,0-18h63c0,0,0,9,0,18S138,346,138,346z"/>
<path fill="#F48438" d="M255,346h-45c0,0-9,0-9-9s0-18,0-18h63c0,0,0,9,0,18S255,346,255,346z"/>
<path fill="#F48438" d="M30,139c0-63,105.099-79.872,143.186-80C210.458,58.875,318,76,318,139c0,0,0,84.71,0,153c0,27-27,27-27,27 H57c0,0-27,0-27-27V139z"/>
<path fill="#FFFFFF" d="M246,264.056c0,4.643-3.428,8.944-9.12,8.944H112.805c-5.691,0-10.805-4.301-10.805-8.944v-65.15 c0-4.643,5.114-7.906,10.805-7.906H236.88c5.691,0,9.12,3.264,9.12,7.906V264.056z"/>
<circle fill="#FFFFFF" cx="94.667" cy="141.667" r="20.333"/>
<circle fill="#FFFFFF" cx="252.667" cy="141.667" r="20.333"/>
<path fill="#F48438" d="M174.24,45.664c24.69-30.635,70.778-25.601,70.778-25.601l6.603,13.863c0,0-48.596-0.658-62.896,24.075 S149.551,76.3,174.24,45.664z"/>
<circle fill="#F48438" cx="259.083" cy="24.083" r="21.083"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

34
website/zznomp/static/main.js

@ -0,0 +1,34 @@
$(function(){
var hotSwap = function(page, pushSate){
if (pushSate) history.pushState(null, null, '/' + page);
$('.pure-menu-selected').removeClass('pure-menu-selected');
if (page.length > 0) {
$('a[href="/' + page + '"]').parent().addClass('pure-menu-selected');
} else {
$('a[href="/"]').addClass('pure-menu-selected');
}
$.get("/get_page", {id: page}, function(data){
$('main').html(data);
}, 'html')
};
$('.hot-swapper').click(function(event){
if (event.which !== 1) return;
var pageId = $(this).attr('href').slice(1);
hotSwap(pageId, true);
event.preventDefault();
return false;
});
window.addEventListener('load', function() {
setTimeout(function() {
window.addEventListener("popstate", function(e) {
hotSwap(location.pathname.slice(1));
});
}, 0);
});
window.statsSource = new EventSource("/api/live_stats");
});

247
website/zznomp/static/miner_stats.js

@ -0,0 +1,247 @@
var workerHashrateData;
var workerHashrateChart;
var workerHistoryMax = 160;
var statData;
var totalHash;
var totalImmature;
var totalBal;
var totalPaid;
var totalShares;
function getReadableHashRateString(hashrate){
hashrate = (hashrate * 2);
if (hashrate < 1000000) {
return (Math.round(hashrate / 1000) / 1000 ).toFixed(2)+' Sol/s';
}
var byteUnits = [ ' Sol/s', ' KSol/s', ' MSol/s', ' GSol/s', ' TSol/s', ' PSol/s' ];
var i = Math.floor((Math.log(hashrate/1000) / Math.log(1000)) - 1);
hashrate = (hashrate/1000) / Math.pow(1000, i + 1);
return hashrate.toFixed(2) + byteUnits[i];
}
function timeOfDayFormat(timestamp){
var dStr = d3.time.format('%I:%M %p')(new Date(timestamp));
if (dStr.indexOf('0') === 0) dStr = dStr.slice(1);
return dStr;
}
function getWorkerNameFromAddress(w) {
var worker = w;
if (w.split(".").length > 1) {
worker = w.split(".")[1];
if (worker == null || worker.length < 1) {
worker = "noname";
}
} else {
worker = "noname";
}
return worker;
}
function buildChartData(){
var workers = {};
for (var w in statData.history) {
var worker = getWorkerNameFromAddress(w);
var a = workers[worker] = (workers[worker] || {
hashrate: []
});
for (var wh in statData.history[w]) {
a.hashrate.push([statData.history[w][wh].time * 1000, statData.history[w][wh].hashrate]);
}
if (a.hashrate.length > workerHistoryMax) {
workerHistoryMax = a.hashrate.length;
}
}
var i=0;
workerHashrateData = [];
for (var worker in workers){
workerHashrateData.push({
key: worker,
//disabled: (i > Math.min((_workerCount-1), 3)),
disabled: false,
values: workers[worker].hashrate
});
i++;
}
}
function updateChartData(){
var workers = {};
for (var w in statData.history) {
var worker = getWorkerNameFromAddress(w);
// get a reference to lastest workerhistory
for (var wh in statData.history[w]) { }
//var wh = statData.history[w][statData.history[w].length - 1];
var foundWorker = false;
for (var i = 0; i < workerHashrateData.length; i++) {
if (workerHashrateData[i].key === worker) {
foundWorker = true;
if (workerHashrateData[i].values.length >= workerHistoryMax) {
workerHashrateData[i].values.shift();
}
workerHashrateData[i].values.push([statData.history[w][wh].time * 1000, statData.history[w][wh].hashrate]);
break;
}
}
if (!foundWorker) {
var hashrate = [];
hashrate.push([statData.history[w][wh].time * 1000, statData.history[w][wh].hashrate]);
workerHashrateData.push({
key: worker,
values: hashrate
});
rebuildWorkerDisplay();
return true;
}
}
triggerChartUpdates();
return false;
}
function calculateAverageHashrate(worker) {
var count = 0;
var total = 1;
var avg = 0;
for (var i = 0; i < workerHashrateData.length; i++) {
count = 0;
for (var ii = 0; ii < workerHashrateData[i].values.length; ii++) {
if (worker == null || workerHashrateData[i].key === worker) {
count++;
avg += parseFloat(workerHashrateData[i].values[ii][1]);
}
}
if (count > total)
total = count;
}
avg = avg / total;
return avg;
}
function triggerChartUpdates(){
workerHashrateChart.update();
}
function displayCharts() {
nv.addGraph(function() {
workerHashrateChart = nv.models.lineChart()
.margin({left: 80, right: 30})
.x(function(d){ return d[0] })
.y(function(d){ return d[1] })
.useInteractiveGuideline(true);
workerHashrateChart.xAxis.tickFormat(timeOfDayFormat);
workerHashrateChart.yAxis.tickFormat(function(d){
return getReadableHashRateString(d);
});
d3.select('#workerHashrate').datum(workerHashrateData).call(workerHashrateChart);
return workerHashrateChart;
});
}
function updateStats() {
totalHash = statData.totalHash;
totalPaid = statData.paid;
totalBal = statData.balance;
totalImmature = statData.immature;
totalShares = statData.totalShares;
// do some calculations
var _blocktime = 250;
var _networkHashRate = parseFloat(statData.networkSols) * 1.2;
var _myHashRate = (totalHash / 1000000) * 2;
var luckDays = ((_networkHashRate / _myHashRate * _blocktime) / (24 * 60 * 60)).toFixed(3);
// update miner stats
$("#statsHashrate").text(getReadableHashRateString(totalHash));
$("#statsHashrateAvg").text(getReadableHashRateString(calculateAverageHashrate(null)));
$("#statsLuckDays").text(luckDays);
$("#statsTotalImmature").text(totalImmature);
$("#statsTotalBal").text(totalBal);
$("#statsTotalPaid").text(totalPaid);
$("#statsTotalShares").text(totalShares.toFixed(2));
}
function updateWorkerStats() {
// update worker stats
var i=0;
for (var w in statData.workers) { i++;
var htmlSafeWorkerName = w.split('.').join('_').replace(/[^\w\s]/gi, '');
var saneWorkerName = getWorkerNameFromAddress(w);
$("#statsHashrate"+htmlSafeWorkerName).text(getReadableHashRateString(statData.workers[w].hashrate));
$("#statsHashrateAvg"+htmlSafeWorkerName).text(getReadableHashRateString(calculateAverageHashrate(saneWorkerName)));
$("#statsLuckDays"+htmlSafeWorkerName).text(statData.workers[w].luckDays);
$("#statsPaid"+htmlSafeWorkerName).text(statData.workers[w].paid);
$("#statsBalance"+htmlSafeWorkerName).text(statData.workers[w].balance);
$("#statsShares"+htmlSafeWorkerName).text(Math.round(statData.workers[w].currRoundShares * 100) / 100);
$("#statsDiff"+htmlSafeWorkerName).text(statData.workers[w].diff);
}
}
function addWorkerToDisplay(name, htmlSafeName, workerObj) {
var htmlToAdd = "";
htmlToAdd = '<div class="boxStats" id="boxStatsLeft" style="float:left; margin: 9px; min-width: 260px;"><div class="boxStatsList">';
if (htmlSafeName.indexOf("_") >= 0) {
htmlToAdd+= '<div class="boxLowerHeader">'+htmlSafeName.substr(htmlSafeName.indexOf("_")+1,htmlSafeName.length)+'</div>';
} else {
htmlToAdd+= '<div class="boxLowerHeader">noname</div>';
}
htmlToAdd+='<div><i class="fas fa-tachometer-alt fa-fw"></i> <span id="statsHashrate'+htmlSafeName+'">'+getReadableHashRateString(workerObj.hashrate)+'</span> (Now)</div>';
htmlToAdd+='<div><i class="fas fa-tachometer-alt fa-fw"></i> <span id="statsHashrateAvg'+htmlSafeName+'">'+getReadableHashRateString(calculateAverageHashrate(name))+'</span> (Avg)</div>';
htmlToAdd+='<div><i class="fas fa-unlock-alt fa-fw"></i> <small>Diff:</small> <span id="statsDiff'+htmlSafeName+'">'+workerObj.diff+'</span></div>';
htmlToAdd+='<div><i class="fas fa-cog fa-fw"></i> <small>Shares:</small> <span id="statsShares'+htmlSafeName+'">'+(Math.round(workerObj.currRoundShares * 100) / 100)+'</span></div>';
htmlToAdd+='<div><i class="fas fa-dice fa-fw"></i> <small>Luck <span id="statsLuckDays'+htmlSafeName+'">'+workerObj.luckDays+'</span> Days</small></div>';
htmlToAdd+='<div><i class="fas fa-money-bill-wave fa-fw"></i> <small>Bal: <span id="statsBalance'+htmlSafeName+'">'+workerObj.balance+'</span></small></div>';
htmlToAdd+='<div><i class="fas fa-money-bill-wave fa-fw"></i> <small>Paid: <span id="statsPaid'+htmlSafeName+'">'+workerObj.paid+'</span></small></div>';
htmlToAdd+='</div></div></div>';
$("#boxesWorkers").html($("#boxesWorkers").html()+htmlToAdd);
}
function rebuildWorkerDisplay() {
$("#boxesWorkers").html("");
var i=0;
for (var w in statData.workers) { i++;
var htmlSafeWorkerName = w.split('.').join('_').replace(/[^\w\s]/gi, '');
var saneWorkerName = getWorkerNameFromAddress(w);
addWorkerToDisplay(saneWorkerName, htmlSafeWorkerName, statData.workers[w]);
}
}
// resize chart on window resize
nv.utils.windowResize(triggerChartUpdates);
// grab initial stats
$.getJSON('/api/worker_stats?'+_miner, function(data){
statData = data;
for (var w in statData.workers) { _workerCount++; }
buildChartData();
displayCharts();
rebuildWorkerDisplay();
updateStats();
});
// live stat updates
statsSource.addEventListener('message', function(e){
// TODO, create miner_live_stats...
// miner_live_stats will return the same josn except without the worker history
// FOR NOW, use this to grab updated stats
$.getJSON('/api/worker_stats?'+_miner, function(data){
statData = data;
// check for missing workers
var wc = 0;
var rebuilt = false;
// update worker stats
for (var w in statData.workers) { wc++; }
// TODO, this isn't 100% fool proof!
if (_workerCount != wc) {
if (_workerCount > wc) {
rebuildWorkerDisplay();
rebuilt = true;
}
_workerCount = wc;
}
rebuilt = (rebuilt || updateChartData());
updateStats();
if (!rebuilt) {
updateWorkerStats();
}
});
});

1
website/zznomp/static/nvd3.css

File diff suppressed because one or more lines are too long

6
website/zznomp/static/nvd3.js

File diff suppressed because one or more lines are too long

84
website/zznomp/static/payments.js

@ -0,0 +1,84 @@
$(function() {
initStatData();
statsSource.addEventListener('message', function (e) {
if (document.querySelector('#pagePayments') !== null) {
var stats = JSON.parse(e.data);
for (var f = 0; f < poolKeys.length; f++) {
var pool = poolKeys[f];
for (var i = 0; i < stats.pools[pool].payments.length; i++) {
var paymentstat = stats.pools[pool].payments[i];
var existingRow = document.querySelector('#payment' + pool + paymentstat.time);
if (existingRow == null) {
clearInterval(nextPaymentTimer);
paymentTimerOn = false;
//Add new
var insertPaymentTr = document.createElement('tr');
insertPaymentTr.id = 'payment' + pool + paymentstat.time;
insertPaymentTr.setAttribute('class', 'dynamicallyInserted');
insertPaymentTr.style.opacity = 0;
insertPaymentTr.style.transition = 'opacity 1s ease-in';
if (typeof paymentstat.txid !== 'undefined') {
var explorerlink = '<a href="' + explorerURL + 'tx/' + paymentstat.txid + '" target="_blank" rel="noopener noreferrer">' + paymentstat.blocks + '</a>';
} else {
var explorerlink = '<a>' + paymentstat.blocks + '</a>';
}
insertPaymentTr.innerHTML = '<td class="paymentblocks" title="Blocks:' + paymentstat.blocks.length + ' ' + paymentstat.opid + '">'
+ '<span class="responsiveTableLabel"><i class="fas fa-link fa-fw"></i></span> <span>Blocks: [' + paymentstat.blocks.length + '] </span>'
+ explorerlink + '<div class="fade">&#9660;</div></td>';
insertPaymentTr.innerHTML += '<td><span class="responsiveTableLabel"><i class="far fa-clock fa-fw"></i> Time: </span>' + readableDate(paymentstat.time) + '</td>';
insertPaymentTr.innerHTML += '<td><span class="responsiveTableLabel"><i class="fas fa-users fa-fw"></i> Miners: </span>' + paymentstat.miners + '</td>';
insertPaymentTr.innerHTML += '<td><span class="responsiveTableLabel"><i class="fas fa-cog fa-fw"></i> Shares: </span>' + bigNumber(paymentstat.shares) + '</td>';
insertPaymentTr.innerHTML += '<td><span class="responsiveTableLabel"><i class="fas fa-money-bill-wave fa-fw"></i> Amount: </span>' + paymentstat.paid + ' ' + stats.pools[pool].symbol + '</td>';
var paymentTable = document.querySelector('#paymentTable' + pool + ' tbody');
if (paymentTable != null) {
paymentTable.insertBefore(insertPaymentTr, paymentTable.firstChild);
setTimeout(() => {
document.querySelectorAll('.dynamicallyInserted').forEach(function(newPayment) {
newPayment.style.opacity = 1;
});
}, 25);
console.log('Added new payment!');
}
} else {
//Update existing (txid) for private chains
if (typeof paymentstat.txid !== 'undefined' && (String(stats.pools[pool].name).startsWith("pirate") || String(stats.pools[pool].name).startsWith("arrr")) ) {
var explorer = 'https://explorer.pirate.black/tx/';
var paymentblock = document.querySelector('#payment' + pool + paymentstat.time + ' .paymentblocks a');
paymentblock.setAttribute('href', explorer + paymentstat.txid);
paymentblock.setAttribute('target', '_blank');
paymentblock.setAttribute('rel', 'noopener noreferrer');
}
}
}
//Global var from main.js - cleared on initStatData(), this needs to be started after the loop in case a new payment was added and old timer needs to be reset
if (!paymentTimerOn) {
nextPaymentTimer = setInterval(function() {
var timeElement = document.querySelector('#statsNextPayment' + pool);
if (timeElement !== null) {
var timeleft=(paymentInterval-parseInt((new Date().getTime() - parseInt(stats.pools[pool].payments[0].time))/1000));
if (timeleft > 0) {
timeElement.innerHTML = timeTil(timeleft);
timeElement.setAttribute('title', timeTilNumbers(timeleft));
} else {
timeElement.innerHTML = 'Now';
timeElement.setAttribute('title', '00:00:00');
}
}
}, 1000);
paymentTimerOn = true;
}
}
}
});
});

BIN
website/zznomp/static/pirate128.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
website/zznomp/static/skull.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
website/zznomp/static/skull256.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

143
website/zznomp/static/stats.js

@ -0,0 +1,143 @@
var poolHashrateData;
var poolHashrateChart;
var statData;
var poolKeys;
function buildChartData(){
var pools = {};
poolKeys = [];
for (var i = 0; i < statData.length; i++){
for (var pool in statData[i].pools){
if (poolKeys.indexOf(pool) === -1)
poolKeys.push(pool);
}
}
for (var i = 0; i < statData.length; i++) {
var time = statData[i].time * 1000;
for (var f = 0; f < poolKeys.length; f++){
var pName = poolKeys[f];
var a = pools[pName] = (pools[pName] || {
hashrate: []
});
if (pName in statData[i].pools){
a.hashrate.push([time, statData[i].pools[pName].hashrate]);
}
else{
a.hashrate.push([time, 0]);
}
}
}
poolHashrateData = [];
for (var pool in pools){
poolHashrateData.push({
key: pool,
values: pools[pool].hashrate
});
$('#statsHashrateAvg' + pool).text(getReadableHashRateString(calculateAverageHashrate(pool)));
}
}
function calculateAverageHashrate(pool) {
var count = 0;
var total = 1;
var avg = 0;
for (var i = 0; i < poolHashrateData.length; i++) {
count = 0;
for (var ii = 0; ii < poolHashrateData[i].values.length; ii++) {
if (pool == null || poolHashrateData[i].key === pool) {
count++;
avg += parseFloat(poolHashrateData[i].values[ii][1]);
}
}
if (count > total)
total = count;
}
avg = avg / total;
return avg;
}
function getReadableHashRateString(hashrate){
hashrate = (hashrate * 2);
if (hashrate < 1000000) {
return (Math.round(hashrate / 1000) / 1000 ).toFixed(2)+' Sol/s';
}
var byteUnits = [ ' Sol/s', ' KSol/s', ' MSol/s', ' GSol/s', ' TSol/s', ' PSol/s' ];
var i = Math.floor((Math.log(hashrate/1000) / Math.log(1000)) - 1);
hashrate = (hashrate/1000) / Math.pow(1000, i + 1);
return hashrate.toFixed(2) + byteUnits[i];
}
function timeOfDayFormat(timestamp){
var dStr = d3.time.format('%I:%M %p')(new Date(timestamp));
if (dStr.indexOf('0') === 0) dStr = dStr.slice(1);
return dStr;
}
function displayCharts(){
nv.addGraph(function() {
poolHashrateChart = nv.models.lineChart()
.margin({left: 80, right: 30})
.x(function(d){ return d[0] })
.y(function(d){ return d[1] })
.useInteractiveGuideline(true);
poolHashrateChart.xAxis.tickFormat(timeOfDayFormat);
poolHashrateChart.yAxis.tickFormat(function(d){
return getReadableHashRateString(d);
});
d3.select('#poolHashrate').datum(poolHashrateData).call(poolHashrateChart);
return poolHashrateChart;
});
}
function triggerChartUpdates(){
poolHashrateChart.update();
}
nv.utils.windowResize(triggerChartUpdates);
$.getJSON('/api/pool_stats', function(data){
statData = data;
buildChartData();
displayCharts();
});
statsSource.addEventListener('message', function(e){
var stats = JSON.parse(e.data);
statData.push(stats);
var newPoolAdded = (function(){
for (var p in stats.pools){
if (poolKeys.indexOf(p) === -1)
return true;
}
return false;
})();
if (newPoolAdded || Object.keys(stats.pools).length > poolKeys.length){
buildChartData();
displayCharts();
}
else {
var time = stats.time * 1000;
for (var f = 0; f < poolKeys.length; f++) {
var pool = poolKeys[f];
for (var i = 0; i < poolHashrateData.length; i++) {
if (poolHashrateData[i].key === pool) {
poolHashrateData[i].values.shift();
poolHashrateData[i].values.push([time, pool in stats.pools ? stats.pools[pool].hashrate : 0]);
$('#statsHashrateAvg' + pool).text(getReadableHashRateString(calculateAverageHashrate(pool)));
break;
}
}
}
triggerChartUpdates();
}
});

612
website/zznomp/static/style.css

@ -0,0 +1,612 @@
html, body, button, input, select, textarea, .pure-g [class *= "pure-u"], .pure-g-r [class *= "pure-u"]{
font-family: 'Open Sans', sans-serif;
}
body{
background-color:#000;
display: flex;
flex-direction: column;
max-width: 1160px;
margin: 0 auto;
}
header > .home-menu {
background: inherit !important;
/* height: 54px; */
padding: 10px 0;
display: flex;
}
header > .home-menu > a.pure-menu-heading, header > .home-menu > ul, header > .home-menu > ul > li{
display: flex !important;
align-items: center;
justify-content: center;
line-height: normal !important;
flex-wrap:wrap;
}
header > .home-menu a {
outline:none;
}
header > .home-menu > a.pure-menu-heading {
color: #b1de5a;
font-size: 1.5em;
}
header > .home-menu > ul > li > a {
color: #b1de5a;
}
header > .home-menu > ul > li > a:hover,
header > .home-menu > ul > li > a:focus{
background: inherit !important;
}
header > .home-menu > a.pure-menu-heading.pure-menu-selected,
header > .home-menu > ul > li > a:hover,
header > .home-menu > ul > li.pure-menu-selected > a {
color: #FCAD4C;
}
a, a:link, a:visited {
color:#FFF;
}
main{
background-color: #2d2d2d;
color:#FFF;
position: relative;
}
footer{
text-align: center;
color: #b3b3b3;
text-decoration: none;
font-size: 0.8em;
padding: 15px;
line-height: 24px;
}
footer a{
color: #fff;
text-decoration: none;
}
footer iframe{
vertical-align: middle;
}
code {
font-family: monospace, serif;
display:block;
margin:15px;
padding:20px;
background-color:#725F49;
}
input, button {
color:#000;
}
.content {
margin:15px;
}
/* PURE TABLE */
.pure-table thead {
background-color:#C99631;
}
.pure-table-odd td,
.pure-table-even td {
background-color: #1F152A
}
/* PAGE STYLES */
/* HOME */
#boxWelcome{
background-color: #887705;
color: white;
margin: 18px;
}
#logoImg{
height: 285px;
margin: 55px;
}
#welcomeText{
font-size: 2.7em;
margin: 50px 18px 10px 18px;
}
#welcomeItems{
list-style-type: none;
font-size: 1.3em;
padding: 0 !important;
margin: 0 0 0 18px !important;
}
#welcomeItems > li{
margin: 30px !important;
}
#boxesLower {
margin: 0 9px;
}
#boxesLower > div {
display: flex;
}
#boxesLower > div > div {
flex: 1 1 auto;
margin: 0 9px 18px 9px;
padding: 10px;
display: flex;
flex-direction: column;
}
.boxLowerHeader{
font-size: 1.3em;
margin: 0 0 5px 10px;
}
#boxStatsLeft, #boxStatsRight{
background-color: #1F152A;
}
.boxStats{
color: white;
}
.boxStatsList{
display: flex;
flex-flow: row wrap;
justify-content: space-around;
opacity: 0.77;
margin-bottom: 5px;
flex: 1 1 auto;
/* align-content: center; */
}
.boxStatsList i.fa{
height: 15px;
width: 33px;
text-align: center;
}
.boxStatsList > div{
padding: 5px 20px;
}
.boxStatsList > div > div{
padding: 3px;
}
/* GETTING STARTED */
#holder{
display: flex;
flex-direction: row;
}
.glow{
box-shadow: inset 0 0 12px 4px #ff6c00;
}
.hidden{
display: none !important;
}
#menu{
background-color: #3d3d3d;
min-width: 170px;
width:100%;
}
#menu > .menuHeader{
color: #FFF;
font-weight:900;
border-bottom: 1px solid #7f878b;
font-size: 1.2em;
padding: 16px 16px 4px 15px;
}
.menuList{
transition-duration: 200ms;
}
.menuList > a:first-child{
margin-top: 10px;
}
.menuList > a{
display: inline-block;
color: #e3f7ff;
text-decoration: none;
padding: 7px;
padding-left: 25px;
width:40px;
}
#main{
flex: 1 1 auto;
display: flex;
flex-direction: column;
margin: 18px;
}
.miningOption{
color: white;
/* display: flex;
flex: 1 1 auto;
flex-direction: row;
flex-wrap: wrap; */
min-height: 215px;
justify-content: center;
align-items: center;
text-decoration: none;
}
a.miningOption:hover{
color: #f69b3a;
}
.miningOption:first-child{
background-color: #C99631;
}
.miningOption:last-child{
background-color: #b064e1;
}
.miningOptionNum{
font-size: 6em;
padding-right: 20px;
width: 140px;
text-align: center;
}
.gettingStartedMenu,
.gettingStartedMenu.pure-menu-open {
display: inline-block;
background-color: #887705;
width:30%;
}
.pure-menu.pure-menu-open, .pure-menu.pure-menu-horizontal li .pure-menu-children {
border:none;
}
.pure-menu .pure-menu-heading {
color: #FFF;
}
.pure-menu li a:hover,
.pure-menu li a:focus {
background-color:#FCAD4C;
color:#1F152A;
}
#orHolder{
height: 37px;
text-align: center;
}
#orLine{
border-bottom: 1px solid #c2cacf;
height: 19px;
margin-bottom: -13px;
}
#orText{
background-color: #ebf4fa;
color: #5c5c5c;
display: inline-block;
width: 35px;
font-style: italic;
}
#coinList code {
background-color:#1F152A;
}
#coinInfoBackground{
transition-duration: 400ms;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: black;
opacity: 0.0;
}
#coinInfo{
display: flex;
flex-direction: column;
color: white;
width: 750px;
min-height: 400px;
top: 50px;
left: 50%;
margin-left: -375px;
position: absolute;
background-color: #1F152A;
}
#coinInfo > div:first-of-type{
font-size: 1.8em;
text-align: center;
margin-top: 40px;
margin-bottom: 35px;
}
.coinInfoHeader {
color: #FCAD4C;
font-weight:900;
font-family: 'Open Sans', sans-serif;
font-size:1.2em;
}
#coinInfoRows,
.coinInfoRows {
display: flex;
flex-direction: row;
justify-content: center;
flex: 1 1 auto;
margin-bottom: 70px;
}
code #coinInfoRows,
code .coinInfoRows {
margin-bottom:inherit;
}
#coinInfoRows > div,
.coinInfoRows > div {
display: flex;
flex-direction: column;
justify-content: center;
}
#coinInfoRows > div > div,
.coinInfoRows > div > div {
padding: 3px;
}
#coinInfoRowKeys,
.coinInfoRowKeys {
font-weight: bold;
padding-right: 30px;
}
#coinInfoRowKeys .coinInfoSubtle,
.coinInfoRowKeys .coinInfoSubtle {
font-weight: normal;
}
#coinInfoClose{
position: absolute;
font-size: 3em;
top: 0;
right: 0;
width: 60px;
height: 60px;
text-align: center;
color: white;
text-decoration: none;
}
#coinInfoClose:hover{
color: #50f0e3;
}
/* STATS */
#topCharts{
color:#000;
padding: 18px;
}
#topCharts > div > div > svg{
display: block;
height: 280px;
}
.chartWrapper{
background-color:#7e7e7e;
border: solid 1px #c7c7c7;
border-radius: 5px;
padding: 5px;
margin-bottom: 18px;
}
.chartLabel{
font-size: 1.2em;
text-align: center;
padding: 4px;
}
#boxesLower {
margin: 0 9px;
}
#boxesLower > div {
display: flex;
}
#boxesLower > div > div {
flex: 1 1 auto;
margin: 0 9px 18px 9px;
padding: 10px;
display: flex;
flex-direction: column;
}
.boxLowerHeader{
font-size: 1.3em;
margin: 0 0 5px 10px;
}
#boxStatsLeft{
color: #FFF;
background-color: #1F152A;
}
#boxStatsRight{
color: #FFF;
background-color: #1F152A;
}
.boxStats{
color: white;
}
.boxStatsList{
display: flex;
flex-flow: row wrap;
justify-content: space-around;
opacity: 0.77;
margin-bottom: 5px;
flex: 1 1 auto;
align-content: center;
}
.boxStatsList i.fa{
height: 15px;
width: 33px;
text-align: center;
}
.boxStatsList > div{
padding: 5px 20px;
}
.boxStatsList > div > div{
padding: 3px;
}
div.tooltip {
/*position: absolute; */
text-align: center;
padding: 2px 10px;
/* font: 12px sans-serif; */
background: #000;
color: #EBEBEB;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
#tooltip.hidden {
opacity: 0;
}
/* TAB STATS */
#topCharts {
padding: 18px;
}
#topCharts > div > div > svg {
display: block;
height: 280px;
}
.chartWrapper {
border: solid 1px #c7c7c7;
border-radius: 5px;
padding: 5px;
margin-bottom: 18px;
}
.chartLabel {
font-size: 1.2em;
text-align: center;
padding: 4px;
}
table {
width: 100%;
}
/* WORKERS */
#bottomNotes {
display: block;
padding-left: 18px;
padding-right: 18px;
padding-bottom: 18px;
}
#topPool > div > div > svg {
display: block;
height: 280px;
}
.poolWrapper {
border: solid 1px #c7c7c7;
padding: 5px;
margin-bottom: 18px;
}
.poolLabel {
font-size: 1.2em;
text-align: center;
padding: 4px;
}
.poolMinerTable {
}
table {
width: 100%;
}
/* PAYMENTS */
.paymentblocks {
max-width:475px;
word-wrap:break-word;
}
#bottomNotes {
display: block;
padding-left: 18px;
padding-right: 18px;
padding-bottom: 18px;
}
#topPool > div > div > svg {
display: block;
height: 280px;
}
.poolLabel {
font-size: 1.2em;
text-align: center;
padding: 4px;
}
table {
width: 100%;
}
/* WORKER STATS */
#topCharts{
padding-left: 18px;
padding-right: 18px;
padding-top: 18px;
padding-bottom: 0px;
}
#topCharts > div > div > svg{
display: block;
height: 280px;
}
.chartWrapper{
border: solid 1px #c7c7c7;
border-radius: 5px;
padding: 5px;
margin-bottom: 18px;
}
.chartLabel{
font-size: 1.2em;
text-align: center;
padding: 4px;
}
.chartHolder{
}
#boxesWorkers {
margin: 0 9px;
}
#boxesWorkers > div {
display: flex;
}
#boxesWorkers > div > div {
flex: 1 1 auto;
margin: 0 9px 18px 9px;
padding: 10px;
display: flex;
flex-direction: column;
}
.boxLowerHeader{
font-size: 1.3em;
margin: 0 0 5px 10px;
}
.boxStats{
color: white;
}
.boxStatsList{
display: flex;
flex-flow: row wrap;
justify-content: space-around;
opacity: 0.77;
margin-bottom: 5px;
flex: 1 1 auto;
align-content: center;
}
.boxStatsList i.fa{
height: 15px;
width: 33px;
text-align: center;
}
.boxStatsList > div{
padding: 5px 20px;
}
.boxStatsList > div > div{
padding: 3px;
}

79
website/zznomp/static/workers.js

@ -0,0 +1,79 @@
$(function() {
initStatData();
$('.btn-lg').click(function(){
window.location = "workers/" + $('.input-lg').val();
});
statsSource.addEventListener('message', function (e) {
if (document.querySelector('#pageWorkers') !== null) {
var stats = JSON.parse(e.data);
for (var f = 0; f < poolKeys.length; f++) {
var pool = poolKeys[f];
var sharesTotal = 0;
for (var addr in stats.pools[pool].miners) {
var workerstat = stats.pools[pool].miners[addr];
sharesTotal += parseFloat(workerstat.shares);
var existingRow = document.querySelector('#workers' + pool + ' #worker' + addr);
var minerEfficiency = ( workerstat.shares > 0 ) ? Math.floor(10000 * workerstat.shares / (workerstat.shares + workerstat.invalidshares)) / 100 : 0;
if (existingRow == null) {
//Add new
var insertMinerTr = document.createElement('tr');
insertMinerTr.id = 'worker' + addr;
insertMinerTr.setAttribute('data-hashrate', workerstat.hashrate);
insertMinerTr.innerHTML = '<td><span class="responsiveTableLabel"><i class="far fa-address-card fa-fw"></i> Address: </span><a href="/workers/' + addr + '" title="' + addr + '">'+ middleEllipsis(addr, 20) + '</a></td>';
insertMinerTr.innerHTML += '<td><span class="responsiveTableLabel"><i class="fas fa-cog fa-fw"></i> Shares: </span><span>' + bigNumber(workerstat.shares) + '</span></td>';
insertMinerTr.innerHTML += '<td><span class="responsiveTableLabel"><i class="fas fa-bullseye fa-fw"></i> Efficiency: </span><span> ' + minerEfficiency + '%</span></td>';
insertMinerTr.innerHTML += '<td><span class="responsiveTableLabel"><i class="fas fa-tachometer-alt fa-fw"></i> Hashrate: </span><span>' + workerstat.hashrateString + '</span></td>';
document.querySelector('#workers' + pool + ' .poolMinerTable tbody').appendChild(insertMinerTr);
console.log('Added new miner! [' + addr + ']');
} else {
//Update existing
document.querySelector('#workers' + pool + ' #worker' + addr + ' td:nth-child(2) span:nth-child(2)').innerHTML = bigNumber(workerstat.shares);
document.querySelector('#workers' + pool + ' #worker' + addr + ' td:nth-child(3) span:nth-child(2)').innerHTML = minerEfficiency + '%';
document.querySelector('#workers' + pool + ' #worker' + addr + ' td:nth-child(4) span:nth-child(2)').innerHTML = workerstat.hashrateString;
document.querySelector('#workers' + pool + ' #worker' + addr).setAttribute('data-hashrate', workerstat.hashrate);
}
}
document.querySelector('#statsShares' + pool).innerHTML = bigNumber(sharesTotal);
//Remove inactive
var workerList = document.querySelectorAll('#workers' + pool + ' .poolMinerTable tbody tr');
for ( var i = workerList.length-1; i >= 0; i--) {
var workerTrID = workerList[i].id.substring(6);
if( typeof stats.pools[pool].miners[workerTrID] == 'undefined') {
console.log('Removing miner :( [' + workerTrID + ']');
workerList[i].parentNode.removeChild(workerList[i]);
}
}
//Resort table
var table = document.querySelector('#workers' + pool + ' table.poolMinerTable tbody');
var rows = document.querySelectorAll('#workers' + pool + ' table.poolMinerTable tbody tr');
var rowsArr = [].slice.call(rows).sort(function (a, b) {
return (parseFloat(a.dataset.hashrate) == parseFloat(b.dataset.hashrate)) ? 0 : ((parseFloat(a.dataset.hashrate) < parseFloat(b.dataset.hashrate)) ? 1 : -1);
});
for (var i = 0; i < rowsArr.length; i++){ table.append(rowsArr[i]); }
}
}
});
});
function searchKeyPress(e)
{
// look for window.event in case event isn't passed in
e = e || window.event;
if (e.keyCode == 13)
{
document.getElementById('btnSearch').click();
return false;
}
return true;
}
Loading…
Cancel
Save