Merge branch 'next' of github.com:TheSerapher/php-mmcfe-ng into next
This commit is contained in:
commit
313e87defb
1
cronjobs/blockupdate.php
Normal file → Executable file
1
cronjobs/blockupdate.php
Normal file → Executable file
@ -1,3 +1,4 @@
|
||||
#!/usr/bin/php
|
||||
<?php
|
||||
|
||||
/*
|
||||
|
||||
1
cronjobs/findblock.php
Normal file → Executable file
1
cronjobs/findblock.php
Normal file → Executable file
@ -1,3 +1,4 @@
|
||||
#!/usr/bin/php
|
||||
<?php
|
||||
|
||||
/*
|
||||
|
||||
1
cronjobs/pps_payout.php
Normal file → Executable file
1
cronjobs/pps_payout.php
Normal file → Executable file
@ -1,3 +1,4 @@
|
||||
#!/usr/bin/php
|
||||
<?php
|
||||
|
||||
/*
|
||||
|
||||
@ -23,6 +23,9 @@ class Block {
|
||||
public function getError() {
|
||||
return $this->sError;
|
||||
}
|
||||
public function getTableName() {
|
||||
return $this->table;
|
||||
}
|
||||
|
||||
public function getLast() {
|
||||
$stmt = $this->mysqli->prepare("SELECT * FROM $this->table ORDER BY height DESC LIMIT 1");
|
||||
@ -108,7 +111,7 @@ class Block {
|
||||
$stmt->close();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
public function setFinder($block_id, $account_id=NULL) {
|
||||
|
||||
@ -8,12 +8,13 @@ class Statistics {
|
||||
private $sError = '';
|
||||
private $table = 'statistics_shares';
|
||||
|
||||
public function __construct($debug, $mysqli, $config, $share, $user) {
|
||||
public function __construct($debug, $mysqli, $config, $share, $user, $block) {
|
||||
$this->debug = $debug;
|
||||
$this->mysqli = $mysqli;
|
||||
$this->share = $share;
|
||||
$this->config = $config;
|
||||
$this->user = $user;
|
||||
$this->block = $block;
|
||||
$this->debug->append("Instantiated Share class", 2);
|
||||
}
|
||||
|
||||
@ -34,6 +35,19 @@ class Statistics {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getBlocksFound($limit=10) {
|
||||
$stmt = $this->mysqli->prepare("
|
||||
SELECT b.*, a.username as finder
|
||||
FROM " . $this->block->getTableName() . " AS b
|
||||
LEFT JOIN accounts AS a
|
||||
ON b.account_id = a.id
|
||||
ORDER BY height DESC LIMIT ?");
|
||||
if ($this->checkStmt($stmt) && $stmt->bind_param("i", $limit) && $stmt->execute() && $result = $stmt->get_result())
|
||||
return $result->fetch_all(MYSQLI_ASSOC);
|
||||
// Catchall
|
||||
$this->debug->append("Failed to find blocks:" . $this->mysqli->error);
|
||||
return false;
|
||||
}
|
||||
public function updateShareStatistics($aStats, $iBlockId) {
|
||||
$stmt = $this->mysqli->prepare("INSERT INTO $this->table (account_id, valid, invalid, block_id) VALUES (?, ?, ?, ?)");
|
||||
if ($this->checkStmt($stmt) && $stmt->bind_param('iiii', $aStats['id'], $aStats['valid'], $aStats['invalid'], $iBlockId) && $stmt->execute()) return true;
|
||||
@ -76,23 +90,50 @@ class Statistics {
|
||||
( SELECT IFNULL(count(id), 0)
|
||||
FROM " . $this->share->getTableName() . "
|
||||
WHERE UNIX_TIMESTAMP(time) >IFNULL((SELECT MAX(time) FROM blocks),0)
|
||||
AND our_result = 'Y' ) as valid,
|
||||
AND our_result = 'Y' ) as valid,
|
||||
( SELECT IFNULL(count(id), 0)
|
||||
FROM " . $this->share->getTableName() . "
|
||||
WHERE UNIX_TIMESTAMP(time) >IFNULL((SELECT MAX(time) FROM blocks),0)
|
||||
AND our_result = 'N' ) as invalid");
|
||||
AND our_result = 'N' ) as invalid");
|
||||
if ( $this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result() ) return $result->fetch_assoc();
|
||||
// Catchall
|
||||
$this->debug->append("Failed to fetch round shares: " . $this->mysqli->error);
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getUserShares($account_id) {
|
||||
$stmt = $this->mysqli->prepare("
|
||||
SELECT
|
||||
(
|
||||
SELECT COUNT(s.id)
|
||||
FROM " . $this->share->getTableName() . " AS s,
|
||||
" . $this->user->getTableName() . " AS u
|
||||
WHERE u.username = SUBSTRING_INDEX( s.username, '.', 1 )
|
||||
AND UNIX_TIMESTAMP(s.time) >IFNULL((SELECT MAX(b.time) FROM blocks AS b),0)
|
||||
AND our_result = 'Y'
|
||||
AND u.id = ?
|
||||
) AS valid,
|
||||
(
|
||||
SELECT COUNT(s.id)
|
||||
FROM " . $this->share->getTableName() . " AS s,
|
||||
" . $this->user->getTableName() . " AS u
|
||||
WHERE u.username = SUBSTRING_INDEX( s.username, '.', 1 )
|
||||
AND UNIX_TIMESTAMP(s.time) >IFNULL((SELECT MAX(b.time) FROM blocks AS b),0)
|
||||
AND our_result = 'N'
|
||||
AND u.id = ?
|
||||
) AS invalid");
|
||||
if ($stmt && $stmt->bind_param("ii", $account_id, $account_id) && $stmt->execute() && $result = $stmt->get_result()) return $result->fetch_assoc();
|
||||
// Catchall
|
||||
$this->debug->append("Unable to fetch user round shares: " . $this->mysqli->error);
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getUserHashrate($account_id) {
|
||||
$stmt = $this->mysqli->prepare("
|
||||
SELECT ROUND(COUNT(s.id) * POW(2,21)/600/1000) AS hashrate
|
||||
SELECT ROUND(COUNT(s.id) * POW(2, " . $this->config['difficulty'] . ")/600/1000) AS hashrate
|
||||
FROM " . $this->share->getTableName() . " AS s,
|
||||
" . $this->user->getTableName() . " AS u
|
||||
WHERE u.username = SUBSTRING_INDEX( s.username, '.', 1 )
|
||||
" . $this->user->getTableName() . " AS u
|
||||
WHERE u.username = SUBSTRING_INDEX( s.username, '.', 1 )
|
||||
AND s.time > DATE_SUB(now(), INTERVAL 10 MINUTE)
|
||||
AND u.id = ?");
|
||||
if ($this->checkStmt($stmt) && $stmt->bind_param("i", $account_id) && $stmt->execute() && $result = $stmt->get_result() ) return $result->fetch_object()->hashrate;
|
||||
@ -105,8 +146,8 @@ class Statistics {
|
||||
$stmt = $this->mysqli->prepare("
|
||||
SELECT ROUND(COUNT(s.id) * POW(2,21)/600/1000) AS hashrate
|
||||
FROM " . $this->share->getTableName() . " AS s,
|
||||
" . $this->user->getTableName() . " AS u
|
||||
WHERE u.username = SUBSTRING_INDEX( s.username, '.', 1 )
|
||||
" . $this->user->getTableName() . " AS u
|
||||
WHERE u.username = SUBSTRING_INDEX( s.username, '.', 1 )
|
||||
AND s.time > DATE_SUB(now(), INTERVAL 10 MINUTE)
|
||||
AND u.id = ?");
|
||||
if ($this->checkStmt($stmt) && $stmt->bind_param("i", $account_id) && $stmt->execute() && $result = $stmt->get_result() ) return $result->fetch_object()->hashrate;
|
||||
@ -114,6 +155,58 @@ class Statistics {
|
||||
$this->debug->append("Failed to fetch hashrate: " . $this->mysqli->error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$statistics = new Statistics($debug, $mysqli, $config, $share, $user);
|
||||
public function getTopContributors($limit=15) {
|
||||
$stmt = $this->mysqli->prepare("
|
||||
SELECT
|
||||
ROUND(COUNT(id) / 60 / 10, 2) AS sharesps,
|
||||
ROUND(COUNT(id) * POW(2," . $this->config['difficulty'] . ")/600/1000,2) AS hashrate,
|
||||
SUBSTRING_INDEX( username, '.', 1 ) AS account
|
||||
FROM " . $this->share->getTableName() . "
|
||||
WHERE time > DATE_SUB(now(), INTERVAL 10 MINUTE)
|
||||
GROUP BY account
|
||||
ORDER BY hashrate DESC LIMIT ?");
|
||||
if ($this->checkStmt($stmt) && $stmt->bind_param("i", $limit) && $stmt->execute() && $hashrates= $stmt->get_result()) {
|
||||
$aHashData = $hashrates->fetch_all(MYSQLI_ASSOC);
|
||||
$stmt->close();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
foreach ($aHashData as $key => $aData) {
|
||||
$stmt = $this->mysqli->prepare("SELECT COUNT(id) FROM " . $this->share->getTableName() . " WHERE SUBSTRING_INDEX( username , '.', 1 ) = ?");
|
||||
if ($stmt->bind_param("s", $aData['username']) && $stmt->execute() && $result = $stmt->get_result()) {
|
||||
$aHashData[$key]['shares'] = $this->getUserShares($this->user->getUserId($aData['account']))['valid'];
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return $aHashData;
|
||||
}
|
||||
|
||||
public function getHourlyHashrateByAccount($account_id) {
|
||||
$stmt = $this->mysqli->prepare("
|
||||
SELECT
|
||||
ROUND(COUNT(s.id) * POW(2, 12)/600/1000) AS hashrate,
|
||||
HOUR(s.time) AS hour
|
||||
FROM " . $this->share->getTableName() . " AS s, accounts AS a
|
||||
WHERE time < NOW() - INTERVAL 1 HOUR AND time > NOW() - INTERVAL 25 HOUR
|
||||
AND a.username = SUBSTRING_INDEX( s.username, '.', 1 )
|
||||
AND a.id = ?
|
||||
GROUP BY HOUR(time)
|
||||
UNION ALL
|
||||
SELECT
|
||||
ROUND(COUNT(s.id) * POW(2, 12)/600/1000) AS hashrate,
|
||||
HOUR(s.time) AS hour
|
||||
FROM " . $this->share->getArchiveTableName() . " AS s, accounts AS a
|
||||
WHERE time < NOW() - INTERVAL 1 HOUR AND time > NOW() - INTERVAL 25 HOUR
|
||||
AND a.username = SUBSTRING_INDEX( s.username, '.', 1 )
|
||||
AND a.id = ?
|
||||
GROUP BY HOUR(time)");
|
||||
if ($this->checkStmt($stmt) && $stmt->bind_param("ii", $account_id, $account_id) && $stmt->execute() && $hourlyhashrates = $stmt->get_result())
|
||||
return $hourlyhashrates->fetch_all(MYSQLI_ASSOC);
|
||||
// Catchall
|
||||
$this->debug->append("Failed to fetch hourly hashrate: " . $this->mysqli->error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$statistics = new Statistics($debug, $mysqli, $config, $share, $user, $block);
|
||||
|
||||
@ -27,11 +27,11 @@ class User {
|
||||
}
|
||||
|
||||
public function getUserName($id) {
|
||||
return $this->getSingle($id, 'username');
|
||||
return $this->getSingle($id, 'username', 'id');
|
||||
}
|
||||
|
||||
public function getUserId($username) {
|
||||
return $this->getSingle($username, 'id', 'username');
|
||||
return $this->getSingle($username, 'id', 'username', 's');
|
||||
}
|
||||
|
||||
public function checkLogin($username, $password) {
|
||||
@ -55,10 +55,10 @@ class User {
|
||||
return $pin_hash === $row_pin;
|
||||
}
|
||||
|
||||
private function getSingle($value, $search='id', $field='id') {
|
||||
private function getSingle($value, $search='id', $field='id', $type="i") {
|
||||
$stmt = $this->mysqli->prepare("SELECT $search FROM $this->table WHERE $field = ? LIMIT 1");
|
||||
if ($this->checkStmt($stmt)) {
|
||||
$stmt->bind_param('i', $value);
|
||||
$stmt->bind_param($type, $value);
|
||||
$stmt->execute();
|
||||
$stmt->bind_result($retval);
|
||||
$stmt->fetch();
|
||||
@ -69,7 +69,7 @@ class User {
|
||||
}
|
||||
|
||||
public function getCoinAddress($userID) {
|
||||
return $this->getSingle($userID, 'coin_address');
|
||||
return $this->getSingle($userID, 'coin_address', 'id', 's');
|
||||
}
|
||||
|
||||
private function updateSingle($userID, $field, $table) {
|
||||
@ -171,21 +171,7 @@ class User {
|
||||
$stmt = $this->mysqli->prepare("
|
||||
SELECT
|
||||
id, username, pin, pass, admin,
|
||||
IFNULL(donate_percent, '0') as donate_percent, coin_address, ap_threshold,
|
||||
(
|
||||
SELECT COUNT(id)
|
||||
FROM shares
|
||||
WHERE $this->table.username = SUBSTRING_INDEX( `username` , '.', 1 )
|
||||
AND UNIX_TIMESTAMP(time) >IFNULL((SELECT MAX(time) FROM blocks),0)
|
||||
AND our_result = 'Y'
|
||||
) AS valid,
|
||||
(
|
||||
SELECT COUNT(id)
|
||||
FROM shares
|
||||
WHERE $this->table.username = SUBSTRING_INDEX( `username` , '.', 1 )
|
||||
AND UNIX_TIMESTAMP(time) >IFNULL((SELECT MAX(time) FROM blocks),0)
|
||||
AND our_result = 'N'
|
||||
) AS invalid
|
||||
IFNULL(donate_percent, '0') as donate_percent, coin_address, ap_threshold
|
||||
FROM $this->table
|
||||
WHERE id = ? LIMIT 0,1");
|
||||
echo $this->mysqli->error;
|
||||
|
||||
@ -16,11 +16,15 @@ define('CLASS_DIR', INCLUDE_DIR . '/classes');
|
||||
define('PAGES_DIR', INCLUDE_DIR . '/pages');
|
||||
|
||||
// Set debugging level for our debug class
|
||||
define('DEBUG', 5);
|
||||
define('DEBUG', 0);
|
||||
|
||||
define('SALT', 'LJKEHFuhgu7%&¤Hg783tr7gf¤%¤fyegfredfoGHYFGYe(%/(&%6');
|
||||
define('SALT', 'PLEASEMAKEMESOMETHINGRANDOM');
|
||||
|
||||
$config = array(
|
||||
'website' => array(
|
||||
'name' => 'The Pool',
|
||||
'slogan' => 'Resistance is futile',
|
||||
),
|
||||
'difficulty' => '31', // Target difficulty for this pool
|
||||
'reward' => '50', // Reward for finding blocks
|
||||
'confirmations' => '120', // Confirmations per block found to credit transactions
|
||||
|
||||
@ -21,45 +21,15 @@ if ($bitcoin->can_connect() === true){
|
||||
}
|
||||
|
||||
if (!$aHashData = $memcache->get('aHashData')) {
|
||||
$debug->append('Hashrates expired in memcache');
|
||||
// Top 15 hashrate list
|
||||
$stmt = $mysqli->prepare("SELECT
|
||||
ROUND(COUNT(id) * POW(2," . $config['difficulty'] . ")/600/1000,2) AS hashrate,
|
||||
SUBSTRING_INDEX( `username` , '.', 1 ) AS account
|
||||
FROM shares
|
||||
WHERE time > DATE_SUB(now(), INTERVAL 10 MINUTE)
|
||||
GROUP BY account
|
||||
ORDER BY hashrate DESC LIMIT 15");
|
||||
$stmt->execute();
|
||||
$hashrates= $stmt->get_result();
|
||||
$aHashData = $hashrates->fetch_all(MYSQLI_ASSOC);
|
||||
$stmt->close();
|
||||
$debug->append('STA Fetching Hashrates from database');
|
||||
$aHashData = $statistics->getTopContributors();
|
||||
$memcache->set('aHashData', $aHashData, 60);
|
||||
$debug->append('END Fetching Hashrates from database');
|
||||
}
|
||||
|
||||
if (! $aContributerData = $memcache->get('aContributerData') ) {
|
||||
// Top 15 Contributers
|
||||
$stmt = $mysqli->prepare("SELECT count(id) AS shares, SUBSTRING_INDEX( `username` , '.', 1 ) AS account FROM shares GROUP BY account ORDER BY shares DESC LIMIT 15");
|
||||
$stmt->execute();
|
||||
$contributers = $stmt->get_result();
|
||||
$aContributerData = $contributers->fetch_all(MYSQLI_ASSOC);
|
||||
$stmt->close();
|
||||
$memcache->set('aContributerData', $aContributerData, 60);
|
||||
}
|
||||
|
||||
// Grab the last block found
|
||||
$stmt = $mysqli->prepare("SELECT * FROM blocks ORDER BY height DESC LIMIT 1");
|
||||
$stmt->execute();
|
||||
$blocks = $stmt->get_result();
|
||||
$aBlockData = $blocks->fetch_array();
|
||||
$stmt->close();
|
||||
|
||||
// Grab the last 10 blocks found
|
||||
$stmt = $mysqli->prepare("SELECT b.*, a.username as finder FROM blocks AS b LEFT JOIN accounts AS a ON b.account_id = a.id ORDER BY height DESC LIMIT 10");
|
||||
$stmt->execute();
|
||||
$blocksfound = $stmt->get_result();
|
||||
$aBlocksFoundData = $blocksfound->fetch_all(MYSQLI_ASSOC);
|
||||
$stmt->close();
|
||||
$aBlocksFoundData = $statistics->getBlocksFound(10);
|
||||
$aBlockData = $aBlocksFoundData[0];
|
||||
|
||||
// Estimated time to find the next block
|
||||
if (!$iCurrentPoolHashrate = $memcache->get('iCurrentPoolHashrate')) {
|
||||
@ -81,7 +51,6 @@ if (!empty($aBlockData)) {
|
||||
// Propagate content our template
|
||||
$smarty->assign("ESTTIME", $iEstTime);
|
||||
$smarty->assign("TIMESINCELAST", $dTimeSinceLast);
|
||||
$smarty->assign("CONTRIBUTORS", $aContributerData);
|
||||
$smarty->assign("BLOCKSFOUND", $aBlocksFoundData);
|
||||
$smarty->assign("TOPHASHRATES", $aHashData);
|
||||
$smarty->assign("CURRENTBLOCK", $iBlock);
|
||||
|
||||
37
public/include/pages/statistics/user.inc.php
Normal file
37
public/include/pages/statistics/user.inc.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
// Make sure we are called from index.php
|
||||
if (!defined('SECURITY'))
|
||||
die('Hacking attempt');
|
||||
|
||||
// Fetch data from litecoind
|
||||
if ($bitcoin->can_connect() === true){
|
||||
if (!$dDifficulty = $memcache->get('dDifficulty')) {
|
||||
$dDifficulty = $bitcoin->query('getdifficulty');
|
||||
$memcache->set('dDifficulty', $dDifficulty, 60);
|
||||
}
|
||||
if (!$iBlock = $memcache->get('iBlock')) {
|
||||
$iBlock = $bitcoin->query('getblockcount');
|
||||
$memcache->set('iBlock', $iBlock, 60);
|
||||
}
|
||||
} else {
|
||||
$iDifficulty = 1;
|
||||
$iBlock = 0;
|
||||
$_SESSION['POPUP'][] = array('CONTENT' => 'Unable to connect to pushpool service: ' . $bitcoin->can_connect(), 'TYPE' => 'errormsg');
|
||||
}
|
||||
|
||||
if (!$aHourlyHashRates = $memcache->get('mmcfe_' . $_SESSION['USERDATA']['id'] . '_hourlyhashrate')) {
|
||||
$debug->append('STA Fetching hourly hashrates from database');
|
||||
$aHourlyHashRates = $statistics->getHourlyHashrateByAccount($_SESSION['USERDATA']['id']);
|
||||
$memcache->set('mmcfe_' . $_SESSION['USERDATA']['id'] . '_hourlyhashrate', $aHourlyHashRates, 600);
|
||||
$debug->append('END Fetching hourly hashrates from database');
|
||||
}
|
||||
|
||||
// Propagate content our template
|
||||
$smarty->assign("YOURHASHRATES", $aHourlyHashRates);
|
||||
$smarty->assign("DIFFICULTY", $dDifficulty);
|
||||
|
||||
if ($_SESSION['AUTHENTICATED']) {
|
||||
$smarty->assign("CONTENT", "default.tpl");
|
||||
}
|
||||
?>
|
||||
@ -9,39 +9,40 @@ $debug->append('Global smarty variables', 3);
|
||||
|
||||
// Store some stuff in memcache prior to assigning it to Smarty
|
||||
if (!$aRoundShares = $memcache->get('aRoundShares')) {
|
||||
$debug->append('Fetching aRoundShares from database');
|
||||
$debug->append('STA Fetching aRoundShares from database');
|
||||
$aRoundShares = $statistics->getRoundShares();
|
||||
$memcache->set('aRoundShares', $aRoundShares, 60);
|
||||
$debug->append('END Fetching aRoundShares from database');
|
||||
$memcache->set('aRoundShares', $aRoundShares, 90);
|
||||
}
|
||||
|
||||
if (!$iCurrentActiveWorkers = $memcache->get('iCurrentActiveWorkers')) {
|
||||
$debug->append('Fetching iCurrentActiveWorkers from database');
|
||||
$debug->append('STA Fetching iCurrentActiveWorkers from database');
|
||||
$iCurrentActiveWorkers = $worker->getCountAllActiveWorkers();
|
||||
$memcache->set('iCurrentActiveWorkers', $iCurrentActiveWorkers, 60);
|
||||
$debug->append('END Fetching iCurrentActiveWorkers from database');
|
||||
$memcache->set('iCurrentActiveWorkers', $iCurrentActiveWorkers, 80);
|
||||
}
|
||||
|
||||
if (!$iCurrentPoolHashrate = $memcache->get('iCurrentPoolHashrate')) {
|
||||
$debug->append('Fetching iCurrentPoolHashrate from database');
|
||||
$debug->append('STA Fetching iCurrentPoolHashrate from database');
|
||||
$iCurrentPoolHashrate = $statistics->getCurrentHashrate();
|
||||
$memcache->set('iCurrentPoolHashrate', $iCurrentPoolHashrate, 60);
|
||||
$debug->append('END Fetching iCurrentPoolHashrate from database');
|
||||
$memcache->set('iCurrentPoolHashrate', $iCurrentPoolHashrate, 90);
|
||||
}
|
||||
|
||||
if (!$iCurrentPoolShareRate = $memcache->get('iCurrentPoolShareRate')) {
|
||||
$debug->append('Fetching iCurrentPoolShareRate from database');
|
||||
$debug->append('STA Fetching iCurrentPoolShareRate from database');
|
||||
$iCurrentPoolShareRate = $statistics->getCurrentShareRate();
|
||||
$memcache->set('iCurrentPoolShareRate', $iCurrentPoolShareRate, 60);
|
||||
$debug->append('END Fetching iCurrentPoolShareRate from database');
|
||||
$memcache->set('iCurrentPoolShareRate', $iCurrentPoolShareRate, 90);
|
||||
}
|
||||
|
||||
$aGlobal = array(
|
||||
'slogan' => $settings->getValue('slogan'),
|
||||
'websitename' => $settings->getValue('websitename'),
|
||||
'ltc_usd' => $settings->getValue('btcesell'),
|
||||
'slogan' => $config['website']['slogan'],
|
||||
'websitename' => $config['website']['name'],
|
||||
'hashrate' => $iCurrentPoolHashrate,
|
||||
'sharerate' => $iCurrentPoolShareRate,
|
||||
'workers' => $iCurrentActiveWorkers,
|
||||
'roundshares' => $aRoundShares,
|
||||
'statstime' => $settings->getValue('statstime'),
|
||||
'motd' => $settings->getValue('motd'),
|
||||
'confirmations' => $config['confirmations'],
|
||||
'reward' => $config['reward']
|
||||
);
|
||||
@ -53,9 +54,18 @@ $aGlobal['userdata'] = $_SESSION['USERDATA']['id'] ? $user->getUserData($_SESSIO
|
||||
$aGlobal['userdata']['balance'] = $transaction->getBalance($_SESSION['USERDATA']['id']);
|
||||
|
||||
// Other userdata that we can cache savely
|
||||
if (!$aGlobal['userdata']['shares'] = $memcache->get('global_' . $_SESSION['USERDATA']['id'] . '_shares')) {
|
||||
$debug->append('STA Loading user shares from database');
|
||||
$aGlobal['userdata']['shares'] = $statistics->getUserShares($_SESSION['USERDATA']['id']);
|
||||
$debug->append('END Loading user shares from database');
|
||||
$memcache->set('global_' . $_SESSION['USERDATA']['id'] . '_shares', $aGlobal['userdata']['shares'], 80);
|
||||
}
|
||||
|
||||
if (!$aGlobal['userdata']['hashrate'] = $memcache->get('global_' . $_SESSION['USERDATA']['id'] . '_hashrate') ) {
|
||||
$debug->append('STA Loading user hashrate from database');
|
||||
$aGlobal['userdata']['hashrate'] = $statistics->getUserHashrate($_SESSION['USERDATA']['id']);
|
||||
$memcache->set('global_' . $_SESSION['USERDATA']['id'] . '_hashrate', $aGlobal['userdata']['hashrate'], 60);
|
||||
$debug->append('END Loading user hashrate from database');
|
||||
$memcache->set('global_' . $_SESSION['USERDATA']['id'] . '_hashrate', $aGlobal['userdata']['hashrate'], 70);
|
||||
}
|
||||
|
||||
// Make it available in Smarty
|
||||
|
||||
184
public/site_assets/mmcFE/js/jquery.tablesorter.pager.js
Normal file
184
public/site_assets/mmcFE/js/jquery.tablesorter.pager.js
Normal file
@ -0,0 +1,184 @@
|
||||
(function($) {
|
||||
$.extend({
|
||||
tablesorterPager: new function() {
|
||||
|
||||
function updatePageDisplay(c) {
|
||||
var s = $(c.cssPageDisplay,c.container).val((c.page+1) + c.seperator + c.totalPages);
|
||||
}
|
||||
|
||||
function setPageSize(table,size) {
|
||||
var c = table.config;
|
||||
c.size = size;
|
||||
c.totalPages = Math.ceil(c.totalRows / c.size);
|
||||
c.pagerPositionSet = false;
|
||||
moveToPage(table);
|
||||
fixPosition(table);
|
||||
}
|
||||
|
||||
function fixPosition(table) {
|
||||
var c = table.config;
|
||||
if(!c.pagerPositionSet && c.positionFixed) {
|
||||
var c = table.config, o = $(table);
|
||||
if(o.offset) {
|
||||
c.container.css({
|
||||
top: o.offset().top + o.height() + 'px',
|
||||
position: 'absolute'
|
||||
});
|
||||
}
|
||||
c.pagerPositionSet = true;
|
||||
}
|
||||
}
|
||||
|
||||
function moveToFirstPage(table) {
|
||||
var c = table.config;
|
||||
c.page = 0;
|
||||
moveToPage(table);
|
||||
}
|
||||
|
||||
function moveToLastPage(table) {
|
||||
var c = table.config;
|
||||
c.page = (c.totalPages-1);
|
||||
moveToPage(table);
|
||||
}
|
||||
|
||||
function moveToNextPage(table) {
|
||||
var c = table.config;
|
||||
c.page++;
|
||||
if(c.page >= (c.totalPages-1)) {
|
||||
c.page = (c.totalPages-1);
|
||||
}
|
||||
moveToPage(table);
|
||||
}
|
||||
|
||||
function moveToPrevPage(table) {
|
||||
var c = table.config;
|
||||
c.page--;
|
||||
if(c.page <= 0) {
|
||||
c.page = 0;
|
||||
}
|
||||
moveToPage(table);
|
||||
}
|
||||
|
||||
|
||||
function moveToPage(table) {
|
||||
var c = table.config;
|
||||
if(c.page < 0 || c.page > (c.totalPages-1)) {
|
||||
c.page = 0;
|
||||
}
|
||||
|
||||
renderTable(table,c.rowsCopy);
|
||||
}
|
||||
|
||||
function renderTable(table,rows) {
|
||||
|
||||
var c = table.config;
|
||||
var l = rows.length;
|
||||
var s = (c.page * c.size);
|
||||
var e = (s + c.size);
|
||||
if(e > rows.length ) {
|
||||
e = rows.length;
|
||||
}
|
||||
|
||||
|
||||
var tableBody = $(table.tBodies[0]);
|
||||
|
||||
// clear the table body
|
||||
|
||||
$.tablesorter.clearTableBody(table);
|
||||
|
||||
for(var i = s; i < e; i++) {
|
||||
|
||||
//tableBody.append(rows[i]);
|
||||
|
||||
var o = rows[i];
|
||||
var l = o.length;
|
||||
for(var j=0; j < l; j++) {
|
||||
|
||||
tableBody[0].appendChild(o[j]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fixPosition(table,tableBody);
|
||||
|
||||
$(table).trigger("applyWidgets");
|
||||
|
||||
if( c.page >= c.totalPages ) {
|
||||
moveToLastPage(table);
|
||||
}
|
||||
|
||||
updatePageDisplay(c);
|
||||
}
|
||||
|
||||
this.appender = function(table,rows) {
|
||||
|
||||
var c = table.config;
|
||||
|
||||
c.rowsCopy = rows;
|
||||
c.totalRows = rows.length;
|
||||
c.totalPages = Math.ceil(c.totalRows / c.size);
|
||||
|
||||
renderTable(table,rows);
|
||||
};
|
||||
|
||||
this.defaults = {
|
||||
size: 10,
|
||||
offset: 0,
|
||||
page: 0,
|
||||
totalRows: 0,
|
||||
totalPages: 0,
|
||||
container: null,
|
||||
cssNext: '.next',
|
||||
cssPrev: '.prev',
|
||||
cssFirst: '.first',
|
||||
cssLast: '.last',
|
||||
cssPageDisplay: '.pagedisplay',
|
||||
cssPageSize: '.pagesize',
|
||||
seperator: "/",
|
||||
positionFixed: true,
|
||||
appender: this.appender
|
||||
};
|
||||
|
||||
this.construct = function(settings) {
|
||||
|
||||
return this.each(function() {
|
||||
|
||||
config = $.extend(this.config, $.tablesorterPager.defaults, settings);
|
||||
|
||||
var table = this, pager = config.container;
|
||||
|
||||
$(this).trigger("appendCache");
|
||||
|
||||
config.size = parseInt($(".pagesize",pager).val());
|
||||
|
||||
$(config.cssFirst,pager).click(function() {
|
||||
moveToFirstPage(table);
|
||||
return false;
|
||||
});
|
||||
$(config.cssNext,pager).click(function() {
|
||||
moveToNextPage(table);
|
||||
return false;
|
||||
});
|
||||
$(config.cssPrev,pager).click(function() {
|
||||
moveToPrevPage(table);
|
||||
return false;
|
||||
});
|
||||
$(config.cssLast,pager).click(function() {
|
||||
moveToLastPage(table);
|
||||
return false;
|
||||
});
|
||||
$(config.cssPageSize,pager).change(function() {
|
||||
setPageSize(table,parseInt($(this).val()));
|
||||
return false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
}
|
||||
});
|
||||
// extend plugin scope
|
||||
$.fn.extend({
|
||||
tablesorterPager: $.tablesorterPager.construct
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
806
public/site_assets/mmcFE/js/jquery.visualize.js
Normal file
806
public/site_assets/mmcFE/js/jquery.visualize.js
Normal file
@ -0,0 +1,806 @@
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* jQuery-Plugin "visualize"
|
||||
* by Scott Jehl, scott@filamentgroup.com
|
||||
* http://www.filamentgroup.com
|
||||
* Copyright (c) 2009 Filament Group
|
||||
* Dual licensed under the MIT (filamentgroup.com/examples/mit-license.txt) and GPL (filamentgroup.com/examples/gpl-license.txt) licenses.
|
||||
*
|
||||
* --------------------------------------------------------------------
|
||||
*/
|
||||
(function ($) {
|
||||
$.fn.visualize = function (options, container) {
|
||||
return $(this).each(function () {
|
||||
//configuration
|
||||
var o = $.extend({
|
||||
type: 'bar',
|
||||
//also available: area, pie, line
|
||||
width: $(this).width(),
|
||||
//height of canvas - defaults to table height
|
||||
height: $(this).height(),
|
||||
//height of canvas - defaults to table height
|
||||
appendTitle: true,
|
||||
//table caption text is added to chart
|
||||
title: null,
|
||||
//grabs from table caption if null
|
||||
appendKey: true,
|
||||
//color key is added to chart
|
||||
colors: ['#be1e2d', '#666699', '#92d5ea', '#ee8310', '#8d10ee', '#5a3b16', '#26a4ed', '#f45a90', '#e9e744'],
|
||||
textColors: [],
|
||||
//corresponds with colors array. null/undefined items will fall back to CSS
|
||||
parseDirection: 'x',
|
||||
//which direction to parse the table data
|
||||
pieMargin: 10,
|
||||
//pie charts only - spacing around pie
|
||||
pieLabelsAsPercent: true,
|
||||
pieLabelPos: 'inside',
|
||||
lineWeight: 4,
|
||||
//for line and area - stroke weight
|
||||
lineDots: false,
|
||||
//also available: 'single', 'double'
|
||||
dotInnerColor: "#ffffff",
|
||||
// only used for lineDots:'double'
|
||||
lineMargin: (options.lineDots ? 15 : 0),
|
||||
//for line and area - spacing around lines
|
||||
barGroupMargin: 10,
|
||||
chartId: '',
|
||||
xLabelParser: null,
|
||||
// function to parse labels as values
|
||||
valueParser: null,
|
||||
// function to parse values. must return a Number
|
||||
chartId: '',
|
||||
chartClass: '',
|
||||
barMargin: 1,
|
||||
//space around bars in bar chart (added to both sides of bar)
|
||||
yLabelInterval: 30,
|
||||
//distance between y labels
|
||||
interaction: false // only used for lineDots != false -- triggers mouseover and mouseout on original table
|
||||
}, options);
|
||||
|
||||
//reset width, height to numbers
|
||||
o.width = parseFloat(o.width);
|
||||
o.height = parseFloat(o.height);
|
||||
|
||||
// reset padding if graph is not lines
|
||||
if (o.type != 'line' && o.type != 'area') {
|
||||
o.lineMargin = 0;
|
||||
}
|
||||
|
||||
var self = $(this);
|
||||
|
||||
// scrape data from html table
|
||||
var tableData = {};
|
||||
var colors = o.colors;
|
||||
var textColors = o.textColors;
|
||||
|
||||
|
||||
var parseLabels = function (direction) {
|
||||
var labels = [];
|
||||
if (direction == 'x') {
|
||||
self.find('thead tr').each(function (i) {
|
||||
$(this).find('th').each(function (j) {
|
||||
if (!labels[j]) {
|
||||
labels[j] = [];
|
||||
}
|
||||
labels[j][i] = $(this).text()
|
||||
})
|
||||
});
|
||||
} else {
|
||||
self.find('tbody tr').each(function (i) {
|
||||
$(this).find('th').each(function (j) {
|
||||
if (!labels[i]) {
|
||||
labels[i] = [];
|
||||
}
|
||||
labels[i][j] = $(this).text()
|
||||
});
|
||||
});
|
||||
}
|
||||
return labels;
|
||||
};
|
||||
|
||||
var fnParse = o.valueParser || parseFloat;
|
||||
var dataGroups = tableData.dataGroups = [];
|
||||
if (o.parseDirection == 'x') {
|
||||
self.find('tbody tr').each(function (i, tr) {
|
||||
dataGroups[i] = {};
|
||||
dataGroups[i].points = [];
|
||||
dataGroups[i].color = colors[i];
|
||||
if (textColors[i]) {
|
||||
dataGroups[i].textColor = textColors[i];
|
||||
}
|
||||
$(tr).find('td').each(function (j, td) {
|
||||
dataGroups[i].points.push({
|
||||
value: fnParse($(td).text()),
|
||||
elem: td,
|
||||
tableCords: [i, j]
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
var cols = self.find('tbody tr:eq(0) td').size();
|
||||
for (var i = 0; i < cols; i++) {
|
||||
dataGroups[i] = {};
|
||||
dataGroups[i].points = [];
|
||||
dataGroups[i].color = colors[i];
|
||||
if (textColors[i]) {
|
||||
dataGroups[i].textColor = textColors[i];
|
||||
}
|
||||
self.find('tbody tr').each(function (j) {
|
||||
dataGroups[i].points.push({
|
||||
value: $(this).find('td').eq(i).text() * 1,
|
||||
elem: this,
|
||||
tableCords: [i, j]
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
var allItems = tableData.allItems = [];
|
||||
$(dataGroups).each(function (i, row) {
|
||||
var count = 0;
|
||||
$.each(row.points, function (j, point) {
|
||||
allItems.push(point);
|
||||
count += point.value;
|
||||
});
|
||||
row.groupTotal = count;
|
||||
});
|
||||
|
||||
tableData.dataSum = 0;
|
||||
tableData.topValue = 0;
|
||||
tableData.bottomValue = Infinity;
|
||||
$.each(allItems, function (i, item) {
|
||||
tableData.dataSum += fnParse(item.value);
|
||||
if (fnParse(item.value, 10) > tableData.topValue) {
|
||||
tableData.topValue = fnParse(item.value, 10);
|
||||
}
|
||||
if (item.value < tableData.bottomValue) {
|
||||
tableData.bottomValue = fnParse(item.value);
|
||||
}
|
||||
});
|
||||
var dataSum = tableData.dataSum;
|
||||
var topValue = tableData.topValue;
|
||||
var bottomValue = tableData.bottomValue;
|
||||
|
||||
var xAllLabels = tableData.xAllLabels = parseLabels(o.parseDirection);
|
||||
var yAllLabels = tableData.yAllLabels = parseLabels(o.parseDirection === 'x' ? 'y' : 'x');
|
||||
|
||||
var xLabels = tableData.xLabels = [];
|
||||
$.each(tableData.xAllLabels, function (i, labels) {
|
||||
tableData.xLabels.push(labels[0]);
|
||||
});
|
||||
|
||||
var totalYRange = tableData.totalYRange = tableData.topValue - tableData.bottomValue;
|
||||
|
||||
var zeroLocX = tableData.zeroLocX = 0;
|
||||
|
||||
if ($.isFunction(o.xLabelParser)) {
|
||||
|
||||
var xTopValue = null;
|
||||
var xBottomValue = null;
|
||||
|
||||
$.each(xLabels, function (i, label) {
|
||||
label = xLabels[i] = o.xLabelParser(label);
|
||||
if (i === 0) {
|
||||
xTopValue = label;
|
||||
xBottomValue = label;
|
||||
}
|
||||
if (label > xTopValue) {
|
||||
xTopValue = label;
|
||||
}
|
||||
if (label < xBottomValue) {
|
||||
xBottomValue = label;
|
||||
}
|
||||
});
|
||||
|
||||
var totalXRange = tableData.totalXRange = xTopValue - xBottomValue;
|
||||
|
||||
|
||||
var xScale = tableData.xScale = (o.width - 2 * o.lineMargin) / totalXRange;
|
||||
var marginDiffX = 0;
|
||||
if (o.lineMargin) {
|
||||
var marginDiffX = -2 * xScale - o.lineMargin;
|
||||
}
|
||||
zeroLocX = tableData.zeroLocX = xBottomValue + o.lineMargin;
|
||||
|
||||
tableData.xBottomValue = xBottomValue;
|
||||
tableData.xTopValue = xTopValue;
|
||||
tableData.totalXRange = totalXRange;
|
||||
}
|
||||
|
||||
var yScale = tableData.yScale = (o.height - 2 * o.lineMargin) / totalYRange;
|
||||
var zeroLocY = tableData.zeroLocY = (o.height - 2 * o.lineMargin) * (tableData.topValue / tableData.totalYRange) + o.lineMargin;
|
||||
|
||||
var yLabels = tableData.yLabels = [];
|
||||
|
||||
var numLabels = Math.floor((o.height - 2 * o.lineMargin) / 30);
|
||||
|
||||
var loopInterval = tableData.totalYRange / numLabels; //fix provided from lab
|
||||
loopInterval = Math.round(parseFloat(loopInterval) / 5) * 5;
|
||||
loopInterval = Math.max(loopInterval, 1);
|
||||
|
||||
// var start =
|
||||
for (var j = Math.round(parseInt(tableData.bottomValue) / 5) * 5; j <= tableData.topValue - loopInterval; j += loopInterval) {
|
||||
yLabels.push(j);
|
||||
}
|
||||
if (yLabels[yLabels.length - 1] > tableData.topValue + loopInterval) {
|
||||
yLabels.pop();
|
||||
} else if (yLabels[yLabels.length - 1] <= tableData.topValue - 10) {
|
||||
yLabels.push(tableData.topValue);
|
||||
}
|
||||
|
||||
// populate some data
|
||||
$.each(dataGroups, function (i, row) {
|
||||
row.yLabels = tableData.yAllLabels[i];
|
||||
$.each(row.points, function (j, point) {
|
||||
point.zeroLocY = tableData.zeroLocY;
|
||||
point.zeroLocX = tableData.zeroLocX;
|
||||
point.xLabels = tableData.xAllLabels[j];
|
||||
point.yLabels = tableData.yAllLabels[i];
|
||||
point.color = row.color;
|
||||
});
|
||||
});
|
||||
|
||||
try {
|
||||
console.log(tableData);
|
||||
} catch (e) {}
|
||||
|
||||
var charts = {};
|
||||
|
||||
charts.pie = {
|
||||
interactionPoints: dataGroups,
|
||||
|
||||
setup: function () {
|
||||
charts.pie.draw(true);
|
||||
},
|
||||
draw: function (drawHtml) {
|
||||
|
||||
var centerx = Math.round(canvas.width() / 2);
|
||||
var centery = Math.round(canvas.height() / 2);
|
||||
var radius = centery - o.pieMargin;
|
||||
var counter = 0.0;
|
||||
|
||||
if (drawHtml) {
|
||||
canvasContain.addClass('visualize-pie');
|
||||
|
||||
if (o.pieLabelPos == 'outside') {
|
||||
canvasContain.addClass('visualize-pie-outside');
|
||||
}
|
||||
|
||||
var toRad = function (integer) {
|
||||
return (Math.PI / 180) * integer;
|
||||
};
|
||||
var labels = $('<ul class="visualize-labels"></ul>').insertAfter(canvas);
|
||||
}
|
||||
|
||||
|
||||
//draw the pie pieces
|
||||
$.each(dataGroups, function (i, row) {
|
||||
var fraction = row.groupTotal / dataSum;
|
||||
if (fraction <= 0 || isNaN(fraction)) return;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(centerx, centery);
|
||||
ctx.arc(centerx, centery, radius, counter * Math.PI * 2 - Math.PI * 0.5, (counter + fraction) * Math.PI * 2 - Math.PI * 0.5, false);
|
||||
ctx.lineTo(centerx, centery);
|
||||
ctx.closePath();
|
||||
ctx.fillStyle = dataGroups[i].color;
|
||||
ctx.fill();
|
||||
// draw labels
|
||||
if (drawHtml) {
|
||||
var sliceMiddle = (counter + fraction / 2);
|
||||
var distance = o.pieLabelPos == 'inside' ? radius / 1.5 : radius + radius / 5;
|
||||
var labelx = Math.round(centerx + Math.sin(sliceMiddle * Math.PI * 2) * (distance));
|
||||
var labely = Math.round(centery - Math.cos(sliceMiddle * Math.PI * 2) * (distance));
|
||||
var leftRight = (labelx > centerx) ? 'right' : 'left';
|
||||
var topBottom = (labely > centery) ? 'bottom' : 'top';
|
||||
var percentage = parseFloat((fraction * 100).toFixed(2));
|
||||
|
||||
// interaction variables
|
||||
row.canvasCords = [labelx, labely];
|
||||
row.zeroLocY = tableData.zeroLocY = 0; // related to zeroLocY and plugin API
|
||||
row.zeroLocX = tableData.zeroLocX = 0; // related to zeroLocX and plugin API
|
||||
row.value = row.groupTotal;
|
||||
|
||||
|
||||
if (percentage) {
|
||||
var labelval = (o.pieLabelsAsPercent) ? percentage + '%' : row.groupTotal;
|
||||
var labeltext = $('<span class="visualize-label">' + labelval + '</span>').css(leftRight, 0).css(topBottom, 0);
|
||||
if (labeltext) var label = $('<li class="visualize-label-pos"></li>').appendTo(labels).css({
|
||||
left: labelx,
|
||||
top: labely
|
||||
}).append(labeltext);
|
||||
labeltext.css('font-size', radius / 8).css('margin-' + leftRight, -labeltext.width() / 2).css('margin-' + topBottom, -labeltext.outerHeight() / 2);
|
||||
|
||||
if (dataGroups[i].textColor) {
|
||||
labeltext.css('color', dataGroups[i].textColor);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
counter += fraction;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
(function () {
|
||||
|
||||
var xInterval;
|
||||
|
||||
var drawPoint = function (ctx, x, y, color, size) {
|
||||
ctx.moveTo(x, y);
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y, size / 2, 0, 2 * Math.PI, false);
|
||||
ctx.closePath();
|
||||
ctx.fillStyle = color;
|
||||
ctx.fill();
|
||||
};
|
||||
|
||||
charts.line = {
|
||||
|
||||
interactionPoints: allItems,
|
||||
|
||||
setup: function (area) {
|
||||
|
||||
if (area) {
|
||||
canvasContain.addClass('visualize-area');
|
||||
} else {
|
||||
canvasContain.addClass('visualize-line');
|
||||
}
|
||||
|
||||
//write X labels
|
||||
var xlabelsUL = $('<ul class="visualize-labels-x"></ul>').width(canvas.width()).height(canvas.height()).insertBefore(canvas);
|
||||
|
||||
if (!o.customXLabels) {
|
||||
xInterval = (canvas.width() - 2 * o.lineMargin) / (xLabels.length - 1);
|
||||
$.each(xLabels, function (i) {
|
||||
var thisLi = $('<li><span>' + this + '</span></li>').prepend('<span class="line" />').css('left', o.lineMargin + xInterval * i).appendTo(xlabelsUL);
|
||||
var label = thisLi.find('span:not(.line)');
|
||||
var leftOffset = label.width() / -2;
|
||||
if (i == 0) {
|
||||
leftOffset = -20;
|
||||
} else if (i == xLabels.length - 1) {
|
||||
leftOffset = -label.width() + 20;
|
||||
}
|
||||
label.css('margin-left', leftOffset).addClass('label');
|
||||
});
|
||||
} else {
|
||||
o.customXLabels(tableData, xlabelsUL);
|
||||
}
|
||||
|
||||
//write Y labels
|
||||
var liBottom = (canvas.height() - 2 * o.lineMargin) / (yLabels.length - 1);
|
||||
var ylabelsUL = $('<ul class="visualize-labels-y"></ul>').width(canvas.width()).height(canvas.height())
|
||||
// .css('margin-top',-o.lineMargin)
|
||||
.insertBefore(scroller);
|
||||
|
||||
$.each(yLabels, function (i) {
|
||||
var value = Math.floor(this);
|
||||
var posB = (value - bottomValue) * yScale + o.lineMargin;
|
||||
if (posB >= o.height - 1 || posB < 0) {
|
||||
return;
|
||||
}
|
||||
var thisLi = $('<li><span>' + value + '</span></li>').css('bottom', posB);
|
||||
if (Math.abs(posB) < o.height - 1) {
|
||||
thisLi.prepend('<span class="line" />');
|
||||
}
|
||||
thisLi.prependTo(ylabelsUL);
|
||||
|
||||
var label = thisLi.find('span:not(.line)');
|
||||
var topOffset = label.height() / -2;
|
||||
if (!o.lineMargin) {
|
||||
if (i == 0) {
|
||||
topOffset = -label.height();
|
||||
} else if (i == yLabels.length - 1) {
|
||||
topOffset = 0;
|
||||
}
|
||||
}
|
||||
label.css('margin-top', topOffset).addClass('label');
|
||||
});
|
||||
|
||||
//start from the bottom left
|
||||
ctx.translate(zeroLocX, zeroLocY);
|
||||
|
||||
charts.line.draw(area);
|
||||
|
||||
},
|
||||
|
||||
draw: function (area) {
|
||||
// prevent drawing on top of previous draw
|
||||
ctx.clearRect(-zeroLocX, -zeroLocY, o.width, o.height);
|
||||
// Calculate each point properties before hand
|
||||
var integer;
|
||||
$.each(dataGroups, function (i, row) {
|
||||
integer = o.lineMargin; // the current offset
|
||||
$.each(row.points, function (j, point) {
|
||||
if (o.xLabelParser) {
|
||||
point.canvasCords = [(xLabels[j] - zeroLocX) * xScale - xBottomValue, -(point.value * yScale)];
|
||||
} else {
|
||||
point.canvasCords = [integer, -(point.value * yScale)];
|
||||
}
|
||||
|
||||
if (o.lineDots) {
|
||||
point.dotSize = o.dotSize || o.lineWeight * Math.PI;
|
||||
point.dotInnerSize = o.dotInnerSize || o.lineWeight * Math.PI / 2;
|
||||
if (o.lineDots == 'double') {
|
||||
point.innerColor = o.dotInnerColor;
|
||||
}
|
||||
}
|
||||
integer += xInterval;
|
||||
});
|
||||
});
|
||||
// fire custom event so we can enable rich interaction
|
||||
self.trigger('vizualizeBeforeDraw', {
|
||||
options: o,
|
||||
table: self,
|
||||
canvasContain: canvasContain,
|
||||
tableData: tableData
|
||||
});
|
||||
// draw lines and areas
|
||||
$.each(dataGroups, function (h) {
|
||||
// Draw lines
|
||||
ctx.beginPath();
|
||||
ctx.lineWidth = o.lineWeight;
|
||||
ctx.lineJoin = 'round';
|
||||
$.each(this.points, function (g) {
|
||||
var loc = this.canvasCords;
|
||||
if (g == 0) {
|
||||
ctx.moveTo(loc[0], loc[1]);
|
||||
}
|
||||
ctx.lineTo(loc[0], loc[1]);
|
||||
});
|
||||
ctx.strokeStyle = this.color;
|
||||
ctx.stroke();
|
||||
// Draw fills
|
||||
if (area) {
|
||||
var integer = this.points[this.points.length - 1].canvasCords[0];
|
||||
if (isFinite(integer)) ctx.lineTo(integer, 0);
|
||||
ctx.lineTo(o.lineMargin, 0);
|
||||
ctx.closePath();
|
||||
ctx.fillStyle = this.color;
|
||||
ctx.globalAlpha = .3;
|
||||
ctx.fill();
|
||||
ctx.globalAlpha = 1.0;
|
||||
} else {
|
||||
ctx.closePath();
|
||||
}
|
||||
});
|
||||
// draw points
|
||||
if (o.lineDots) {
|
||||
$.each(dataGroups, function (h) {
|
||||
$.each(this.points, function (g) {
|
||||
drawPoint(ctx, this.canvasCords[0], this.canvasCords[1], this.color, this.dotSize);
|
||||
if (o.lineDots === 'double') {
|
||||
drawPoint(ctx, this.canvasCords[0], this.canvasCords[1], this.innerColor, this.dotInnerSize);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
charts.area = {
|
||||
setup: function () {
|
||||
charts.line.setup(true);
|
||||
},
|
||||
draw: charts.line.draw
|
||||
};
|
||||
|
||||
(function () {
|
||||
|
||||
var horizontal, bottomLabels;
|
||||
|
||||
charts.bar = {
|
||||
setup: function () {
|
||||
/**
|
||||
* We can draw horizontal or vertical bars depending on the
|
||||
* value of the 'barDirection' option (which may be 'vertical' or
|
||||
* 'horizontal').
|
||||
*/
|
||||
|
||||
horizontal = (o.barDirection == 'horizontal');
|
||||
|
||||
canvasContain.addClass('visualize-bar');
|
||||
|
||||
/**
|
||||
* Write labels along the bottom of the chart. If we're drawing
|
||||
* horizontal bars, these will be the yLabels, otherwise they
|
||||
* will be the xLabels. The positioning also varies slightly:
|
||||
* yLabels are values, hence they will span the whole width of
|
||||
* the canvas, whereas xLabels are supposed to line up with the
|
||||
* bars.
|
||||
*/
|
||||
bottomLabels = horizontal ? yLabels : xLabels;
|
||||
|
||||
var xInterval = canvas.width() / (bottomLabels.length - (horizontal ? 1 : 0));
|
||||
|
||||
var xlabelsUL = $('<ul class="visualize-labels-x"></ul>').width(canvas.width()).height(canvas.height()).insertBefore(canvas);
|
||||
|
||||
$.each(bottomLabels, function (i) {
|
||||
var thisLi = $('<li><span class="label">' + this + '</span></li>').prepend('<span class="line" />').css('left', xInterval * i).width(xInterval).appendTo(xlabelsUL);
|
||||
|
||||
if (horizontal) {
|
||||
var label = thisLi.find('span.label');
|
||||
label.css("margin-left", -label.width() / 2);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Write labels along the left of the chart. Follows the same idea
|
||||
* as the bottom labels.
|
||||
*/
|
||||
var leftLabels = horizontal ? xLabels : yLabels;
|
||||
var liBottom = canvas.height() / (leftLabels.length - (horizontal ? 0 : 1));
|
||||
|
||||
var ylabelsUL = $('<ul class="visualize-labels-y"></ul>').width(canvas.width()).height(canvas.height()).insertBefore(canvas);
|
||||
|
||||
$.each(leftLabels, function (i) {
|
||||
var thisLi = $('<li><span>' + this + '</span></li>').prependTo(ylabelsUL);
|
||||
|
||||
var label = thisLi.find('span:not(.line)').addClass('label');
|
||||
|
||||
if (horizontal) {
|
||||
/**
|
||||
* For left labels, we want to vertically align the text
|
||||
* to the middle of its container, but we don't know how
|
||||
* many lines of text we will have, since the labels could
|
||||
* be very long.
|
||||
*
|
||||
* So we set a min-height of liBottom, and a max-height
|
||||
* of liBottom + 1, so we can then check the label's actual
|
||||
* height to determine if it spans one line or more lines.
|
||||
*/
|
||||
label.css({
|
||||
'min-height': liBottom,
|
||||
'max-height': liBottom + 1,
|
||||
'vertical-align': 'middle'
|
||||
});
|
||||
thisLi.css({
|
||||
'top': liBottom * i,
|
||||
'min-height': liBottom
|
||||
});
|
||||
|
||||
var r = label[0].getClientRects()[0];
|
||||
if (r.bottom - r.top == liBottom) {
|
||||
/* This means we have only one line of text; hence
|
||||
* we can centre the text vertically by setting the line-height,
|
||||
* as described at:
|
||||
* http://www.ampsoft.net/webdesign-l/vertical-aligned-nav-list.html
|
||||
*
|
||||
* (Although firefox has .height on the rectangle, IE doesn't,
|
||||
* so we use r.bottom - r.top rather than r.height.)
|
||||
*/
|
||||
label.css('line-height', parseInt(liBottom) + 'px');
|
||||
} else {
|
||||
/*
|
||||
* If there is more than one line of text, then we shouldn't
|
||||
* touch the line height, but we should make sure the text
|
||||
* doesn't overflow the container.
|
||||
*/
|
||||
label.css("overflow", "hidden");
|
||||
}
|
||||
} else {
|
||||
thisLi.css('bottom', liBottom * i).prepend('<span class="line" />');
|
||||
label.css('margin-top', -label.height() / 2)
|
||||
}
|
||||
});
|
||||
|
||||
charts.bar.draw();
|
||||
|
||||
},
|
||||
|
||||
draw: function () {
|
||||
// Draw bars
|
||||
if (horizontal) {
|
||||
// for horizontal, keep the same code, but rotate everything 90 degrees
|
||||
// clockwise.
|
||||
ctx.rotate(Math.PI / 2);
|
||||
} else {
|
||||
// for vertical, translate to the top left corner.
|
||||
ctx.translate(0, zeroLocY);
|
||||
}
|
||||
|
||||
// Don't attempt to draw anything if all the values are zero,
|
||||
// otherwise we will get weird exceptions from the canvas methods.
|
||||
if (totalYRange <= 0) return;
|
||||
|
||||
var yScale = (horizontal ? canvas.width() : canvas.height()) / totalYRange;
|
||||
var barWidth = horizontal ? (canvas.height() / xLabels.length) : (canvas.width() / (bottomLabels.length));
|
||||
var linewidth = (barWidth - o.barGroupMargin * 2) / dataGroups.length;
|
||||
|
||||
for (var h = 0; h < dataGroups.length; h++) {
|
||||
ctx.beginPath();
|
||||
|
||||
var strokeWidth = linewidth - (o.barMargin * 2);
|
||||
ctx.lineWidth = strokeWidth;
|
||||
var points = dataGroups[h].points;
|
||||
var integer = 0;
|
||||
for (var i = 0; i < points.length; i++) {
|
||||
// If the last value is zero, IE will go nuts and not draw anything,
|
||||
// so don't try to draw zero values at all.
|
||||
if (points[i].value != 0) {
|
||||
var xVal = (integer - o.barGroupMargin) + (h * linewidth) + linewidth / 2;
|
||||
xVal += o.barGroupMargin * 2;
|
||||
ctx.moveTo(xVal, 0);
|
||||
ctx.lineTo(xVal, Math.round(-points[i].value * yScale));
|
||||
}
|
||||
integer += barWidth;
|
||||
}
|
||||
ctx.strokeStyle = dataGroups[h].color;
|
||||
ctx.stroke();
|
||||
ctx.closePath();
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
//create new canvas, set w&h attrs (not inline styles)
|
||||
var canvasNode = document.createElement("canvas");
|
||||
var canvas = $(canvasNode).attr({
|
||||
'height': o.height,
|
||||
'width': o.width
|
||||
});
|
||||
|
||||
//get title for chart
|
||||
var title = o.title || self.find('caption').text();
|
||||
|
||||
//create canvas wrapper div, set inline w&h, append
|
||||
var canvasContain = (container || $('<div ' + (o.chartId ? 'id="' + o.chartId + '" ' : '') + 'class="visualize ' + o.chartClass + '" role="img" aria-label="Chart representing data from the table: ' + title + '" />')).height(o.height).width(o.width);
|
||||
|
||||
var scroller = $('<div class="visualize-scroller"></div>').appendTo(canvasContain).append(canvas);
|
||||
|
||||
//title/key container
|
||||
if (o.appendTitle || o.appendKey) {
|
||||
var infoContain = $('<div class="visualize-info"></div>').appendTo(canvasContain);
|
||||
}
|
||||
|
||||
//append title
|
||||
if (o.appendTitle) {
|
||||
$('<div class="visualize-title">' + title + '</div>').appendTo(infoContain);
|
||||
}
|
||||
|
||||
|
||||
//append key
|
||||
if (o.appendKey) {
|
||||
var newKey = $('<ul class="visualize-key"></ul>');
|
||||
$.each(yAllLabels, function (i, label) {
|
||||
$('<li><span class="visualize-key-color" style="background: ' + dataGroups[i].color + '"></span><span class="visualize-key-label">' + label + '</span></li>').appendTo(newKey);
|
||||
});
|
||||
newKey.appendTo(infoContain);
|
||||
};
|
||||
|
||||
// init interaction
|
||||
if (o.interaction) {
|
||||
// sets the canvas to track interaction
|
||||
// IE needs one div on top of the canvas since the VML shapes prevent mousemove from triggering correctly.
|
||||
// Pie charts needs tracker because labels goes on top of the canvas and also messes up with mousemove
|
||||
var tracker = $('<div class="visualize-interaction-tracker"/>').css({
|
||||
'height': o.height + 'px',
|
||||
'width': o.width + 'px',
|
||||
'position': 'relative',
|
||||
'z-index': 200
|
||||
}).insertAfter(canvas);
|
||||
|
||||
var triggerInteraction = function (overOut, data) {
|
||||
var data = $.extend({
|
||||
canvasContain: canvasContain,
|
||||
tableData: tableData
|
||||
}, data);
|
||||
self.trigger('vizualize' + overOut, data);
|
||||
};
|
||||
|
||||
var over = false,
|
||||
last = false,
|
||||
started = false;
|
||||
tracker.mousemove(function (e) {
|
||||
var x, y, x1, y1, data, dist, i, current, selector, zLabel, elem, color, minDist, found, ev = e.originalEvent;
|
||||
|
||||
// get mouse position relative to the tracker/canvas
|
||||
x = ev.layerX || ev.offsetX || 0;
|
||||
y = ev.layerY || ev.offsetY || 0;
|
||||
|
||||
found = false;
|
||||
minDist = started ? 30000 : (o.type == 'pie' ? (Math.round(canvas.height() / 2) - o.pieMargin) / 3 : o.lineWeight * 4);
|
||||
// iterate datagroups to find points with matching
|
||||
$.each(charts[o.type].interactionPoints, function (i, current) {
|
||||
x1 = current.canvasCords[0] + zeroLocX;
|
||||
y1 = current.canvasCords[1] + (o.type == "pie" ? 0 : zeroLocY);
|
||||
dist = Math.sqrt((x1 - x) * (x1 - x) + (y1 - y) * (y1 - y));
|
||||
if (dist < minDist) {
|
||||
found = current;
|
||||
minDist = dist;
|
||||
}
|
||||
});
|
||||
|
||||
if (o.multiHover && found) {
|
||||
x = found.canvasCords[0] + zeroLocX;
|
||||
y = found.canvasCords[1] + (o.type == "pie" ? 0 : zeroLocY);
|
||||
found = [found];
|
||||
$.each(charts[o.type].interactionPoints, function (i, current) {
|
||||
if (current == found[0]) {
|
||||
return;
|
||||
}
|
||||
x1 = current.canvasCords[0] + zeroLocX;
|
||||
y1 = current.canvasCords[1] + zeroLocY;
|
||||
dist = Math.sqrt((x1 - x) * (x1 - x) + (y1 - y) * (y1 - y));
|
||||
if (dist <= o.multiHover) {
|
||||
found.push(current);
|
||||
}
|
||||
});
|
||||
}
|
||||
// trigger over and out only when state changes, instead of on every mousemove
|
||||
over = found;
|
||||
if (over != last) {
|
||||
if (over) {
|
||||
if (last) {
|
||||
triggerInteraction('Out', {
|
||||
point: last
|
||||
});
|
||||
}
|
||||
triggerInteraction('Over', {
|
||||
point: over
|
||||
});
|
||||
last = over;
|
||||
}
|
||||
if (last && !over) {
|
||||
triggerInteraction('Out', {
|
||||
point: last
|
||||
});
|
||||
last = false;
|
||||
}
|
||||
started = true;
|
||||
}
|
||||
});
|
||||
tracker.mouseleave(function () {
|
||||
triggerInteraction('Out', {
|
||||
point: last,
|
||||
mouseOutGraph: true
|
||||
});
|
||||
over = (last = false);
|
||||
});
|
||||
}
|
||||
|
||||
//append new canvas to page
|
||||
if (!container) {
|
||||
canvasContain.insertAfter(this);
|
||||
}
|
||||
if (typeof (G_vmlCanvasManager) != 'undefined') {
|
||||
G_vmlCanvasManager.init();
|
||||
G_vmlCanvasManager.initElement(canvas[0]);
|
||||
}
|
||||
|
||||
//set up the drawing board
|
||||
var ctx = canvas[0].getContext('2d');
|
||||
|
||||
// Scroll graphs
|
||||
scroller.scrollLeft(o.width - scroller.width());
|
||||
|
||||
// init plugins
|
||||
$.each($.visualizePlugins, function (i, plugin) {
|
||||
plugin.call(self, o, tableData);
|
||||
});
|
||||
|
||||
//create chart
|
||||
charts[o.type].setup();
|
||||
|
||||
if (!container) {
|
||||
//add event for updating
|
||||
self.bind('visualizeRefresh', function () {
|
||||
self.visualize(o, $(this).empty());
|
||||
});
|
||||
//add event for redraw
|
||||
self.bind('visualizeRedraw', function () {
|
||||
charts[o.type].draw();
|
||||
});
|
||||
}
|
||||
}).next(); //returns canvas(es)
|
||||
};
|
||||
// create array for plugins. if you wish to make a plugin,
|
||||
// just push your init funcion into this array
|
||||
$.visualizePlugins = [];
|
||||
|
||||
})(jQuery);
|
||||
@ -1,5 +1,5 @@
|
||||
<center>
|
||||
Litecoin Pool using on <a href="https://github.com/litecoin-project/litecoin">litecoind</a>, <a href="https://github.com/ArtForz/pushpool/tree/tenebrix">pushpoold</a><br/>
|
||||
Website based on <a href="https://github.com/Greedi/mmcFE">mmcfe</a>, overhauled by TheSerapher, available on GitHub<br/>
|
||||
Litecoin Pool using <a href="https://github.com/litecoin-project/litecoin">litecoind</a>, <a href="https://github.com/ArtForz/pushpool/tree/tenebrix">pushpoold</a><br/>
|
||||
<a href="https://github.com/TheSerapher/php-mmcfe-ng">mmcfe-ng</a> Website based on <a href="https://github.com/Greedi/mmcFE">mmcfe</a>, overhauled by TheSerapher, available on <a href="https://github.com/TheSerapher/php-mmcfe-ng">GitHub</a><br/>
|
||||
<i style="color: grey">LTC: Lge95QR2frp9y1wJufjUPCycVsg5gLJPW8<br/></i><br/><br/>
|
||||
</center>
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
<div id="ministats">
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td><li>Ł/usd: {$GLOBAL.ltc_usd} </li></td>
|
||||
<td><li>Pool Hashrate: {$GLOBAL.hashrate / 1000} MH/s </li></td>
|
||||
<td><li>Pool Sharerate: {$GLOBAL.sharerate} Shares/s </li></td>
|
||||
<td><li>Pool Workers: {$GLOBAL.workers} </li></td>
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
</ul>
|
||||
</li>
|
||||
{/if}
|
||||
{if $smarty.session.AUTHENTICATED == 1 && $GLOBAL.userdata.admin == 1}<li><a href="/adminPanel">Admin Panel</a></li>{/if}
|
||||
{if $smarty.session.AUTHENTICATED == 1 && $GLOBAL.userdata.admin == 1}<li><a href="#">Admin Panel</a></li>{/if}
|
||||
<li><a href="{$smarty.server.PHP_SELF}?page=statistics">Statistics</a>
|
||||
<ul>
|
||||
<li><a href="{$smarty.server.PHP_SELF}?page=statistics&action=pool">Pool Stats</a></li>
|
||||
|
||||
@ -9,20 +9,16 @@
|
||||
<b><u>Your Current Hashrate</u></b><br/>
|
||||
<i><b>{$GLOBAL.userdata.hashrate} KH/s</b></i><br/><br/>
|
||||
<u><b>Unpaid Shares</b></u><span id='tt'><img src='{$PATH}/images/questionmark.png' height='15px' width='15px' title='Submitted shares between the last 120 confirms block until now.'></span><br/>
|
||||
Your Valid: <b><i>{$GLOBAL.userdata.valid}</i><font size='1px'></font></b><br/>
|
||||
Your Valid: <b><i>{$GLOBAL.userdata.shares.valid}</i><font size='1px'></font></b><br/>
|
||||
Pool Valid: <b><i>{$GLOBAL.roundshares.valid}</i> <font size='1px'></font></b><br/><br>
|
||||
<u><b>Round Shares </b></u><span id='tt'><img src='{$PATH}/images/questionmark.png' height='15px' width='15px' title='Submitted shares since last found block (ie. round shares)'></span><br/>
|
||||
Pool Valid: <b><i>{$GLOBAL.roundshares.valid}</i></b><br>
|
||||
Pool Inalid: <b><i>{$GLOBAL.roundshares.invalid}</i></b><br>
|
||||
Your Invalid: <b><i>{$GLOBAL.userdata.invalid}</i><font size='1px'></font></b><br/><br>
|
||||
Your Invalid: <b><i>{$GLOBAL.userdata.shares.invalid}</i><font size='1px'></font></b><br/><br>
|
||||
<u><b>Round Estimate</b></u><font size='1'></font></u><br>
|
||||
<b><i>{math equation="round(( x / y ) * z, 8)" x=$GLOBAL.userdata.valid y=$GLOBAL.roundshares.valid z=$GLOBAL.reward}</i> <font size='1px'>LTC</font></b><br><br>
|
||||
<u><b>Account Balance</b></u><br><b><i>{$GLOBAL.userdata.balance}</i><font size='1px'> LTC</font></b><br/><br>
|
||||
<b><i>{math equation="round(( x / y ) * z, 8)" x=$GLOBAL.userdata.shares.valid y=$GLOBAL.roundshares.valid z=$GLOBAL.reward}</i> <font size='1px'>LTC</font></b><br><br>
|
||||
<u><b>Account Balance</b></u><br><b><i>{$GLOBAL.userdata.balance|default:"0"}</i><font size='1px'> LTC</font></b><br/><br>
|
||||
</p>
|
||||
<center><hr width="90%"></center>
|
||||
<div style="margin-top:-13px; margin-bottom:-15px;">
|
||||
<p><b><font size="1">Stats last updated:</b><br><i>{$GLOBAL.statstime|date_format:"%T"} GMT+1<br>(updated every 60 secs)</font></i><br/></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bendl"></div>
|
||||
<div class="bendr"></div>
|
||||
|
||||
@ -9,6 +9,8 @@
|
||||
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
|
||||
<script src="{$PATH}/js/jquery.browser.js"></script>
|
||||
<script src="{$PATH}/js/jquery.tablesorter.min.js"></script>
|
||||
<script src="{$PATH}/js/jquery.tablesorter.pager.js"></script>
|
||||
<script src="{$PATH}/js/jquery.visualize.js"></script>
|
||||
<script src="{$PATH}/js/custom.js"></script>
|
||||
<script src="{$PATH}/js/tools.js"></script>
|
||||
<!--[if IE]><script type="text/javascript" src="{$PATH}/js/excanvas.js"></script><![endif]-->
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
{include file="global/block_header.tpl" BLOCK_HEADER="Pool Statistics" BLOCK_STYLE="clear:none;"}
|
||||
{include file="global/block_header.tpl" BLOCK_HEADER="Top 15 Hashrates" ALIGN="left" BUTTONS=array(More,Less)}
|
||||
{include file="global/block_header.tpl" BLOCK_HEADER="Top Contributers"}
|
||||
<center>
|
||||
<table width="100%" border="0" style="font-size:13px;">
|
||||
<table width="100%" border="0" style="font-size:13px;" class="sortable">
|
||||
<thead>
|
||||
<tr style="background-color:#B6DAFF;">
|
||||
<th align="left">Rank</th>
|
||||
<th align="left" scope="col">User Name</th>
|
||||
<th align="left" scope="col">KH/s</th>
|
||||
<th align="left" scope="col">Shares</th>
|
||||
<th align="left" scope="col">Shares/s</th>
|
||||
<th align="left">Ł/Day<font size="1"> (est)</font></th>
|
||||
</tr>
|
||||
</thead>
|
||||
@ -17,35 +19,18 @@
|
||||
<td>{$rank++}</td>
|
||||
<td>{$TOPHASHRATES[hashrate].account}</td>
|
||||
<td>{$TOPHASHRATES[hashrate].hashrate|number_format}</td>
|
||||
<td>{$TOPHASHRATES[hashrate].shares|number_format}</td>
|
||||
<td>{$TOPHASHRATES[hashrate].sharesps}</td>
|
||||
<td>{math equation="round(reward / ( diff * pow(2,32) / ( hashrate * 1000 ) / 3600 / 24),3)" diff=$DIFFICULTY reward=$REWARD hashrate=$TOPHASHRATES[hashrate].hashrate}</td>
|
||||
</tr>
|
||||
{/section}
|
||||
</tbody>
|
||||
</table>
|
||||
<div id="pagination" class="pagination"></div>
|
||||
</center>
|
||||
{include file="global/block_footer.tpl"}
|
||||
|
||||
{include file="global/block_header.tpl" BLOCK_HEADER="Top 15 Contributers" ALIGN="right" BUTTONS=array(More,Less)}
|
||||
<center>
|
||||
<table class="" width="100%" style="font-size:13px;">
|
||||
<thead>
|
||||
<tr style="background-color:#B6DAFF;"><th scope="col" align="left">Rank</th><th scope="col" align="left">User Name</th><th scope="col" align="left">Shares</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{assign var=rank value=1}
|
||||
{section contributor $CONTRIBUTORS}
|
||||
<tr class="{cycle values="odd,even"}">
|
||||
<td>{$rank++}</td>
|
||||
<td>{$CONTRIBUTORS[contributor].account}</td>
|
||||
<td>{$CONTRIBUTORS[contributor].shares|number_format}</td>
|
||||
</tr>
|
||||
{/section}
|
||||
</tbody>
|
||||
</table>
|
||||
</center>
|
||||
{include file="global/block_footer.tpl"}
|
||||
|
||||
{include file="global/block_header.tpl" BLOCK_HEADER="Server Stats" BLOCK_STYLE="clear:all;" STYLE="padding-left:5px;padding-right:5px;" BUTTONS=array(More)}
|
||||
{include file="global/block_header.tpl" BLOCK_HEADER="Server Stats" BLOCK_STYLE="clear:all;" STYLE="padding-left:5px;padding-right:5px;"}
|
||||
<table class="" width="100%" style="font-size:13px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
|
||||
23
public/templates/mmcFE/statistics/user/default.tpl
Normal file
23
public/templates/mmcFE/statistics/user/default.tpl
Normal file
@ -0,0 +1,23 @@
|
||||
{include file="global/block_header.tpl" BLOCK_HEADER="Your Average Hourly Hash Rate" BUTTONS=array(mine,pool,both)}
|
||||
<div class="block_content tab_content" id="mine" style="padding-left:30px;">
|
||||
<table class="stats" rel="area" cellpadding="0">
|
||||
<caption>Your Hashrate </caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<td></td>
|
||||
{section hashrate $YOURHASHRATES}
|
||||
<th scope="col">{$YOURHASHRATES[hashrate].hour}</th>
|
||||
{/section}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th scope="row">{$GLOBAL.USERDATA.username}</th>
|
||||
{section hashrate $YOURHASHRATES}
|
||||
<td>{$YOURHASHRATES[hashrate].hashrate|number_format}</td>
|
||||
{/section}
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{include file="global/block_footer.tpl"}
|
||||
Loading…
Reference in New Issue
Block a user