add meteor frontend app

This commit is contained in:
Fabian Vogelsteller
2015-08-14 19:22:53 +02:00
parent b9cd95bedc
commit f53e5559f8
233 changed files with 115140 additions and 0 deletions

View File

@@ -0,0 +1,26 @@
(function(){/* Services */
_ = lodash;
socket = new Primus({url: 'wss://stats.ethdev.com'});
toastr = window.toastr;
toastr.options = {
"closeButton": false,
"debug": false,
"progressBar": false,
"newestOnTop": true,
"positionClass": "toast-top-right",
"preventDuplicates": false,
"onclick": null,
"showDuration": "300",
"hideDuration": "1000",
"timeOut": "5000",
"extendedTimeOut": "1000",
"showEasing": "swing",
"hideEasing": "linear",
"showMethod": "fadeIn",
"hideMethod": "fadeOut"
};
})();

View File

@@ -0,0 +1,670 @@
(function(){// Collections
Blockchain = new Mongo.Collection('blockchain', {connection: null});
Nodes = new Mongo.Collection('nodes', {connection: null});
Map = new Mongo.Collection('map', {connection: null});
/* Controllers */
var MAX_BINS = 40;
// Main Stats init
// ---------------
Blockchain.insert({
_id: 'meta',
frontierHash: '0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa',
nodesTotal: 0,
nodesActive: 0,
bestBlock: 0,
lastBlock: 0,
lastDifficulty: 0,
upTimeTotal: 0,
avgBlockTime: 0,
blockPropagationAvg: 0,
avgHashrate: 0,
uncleCount: 0,
bestStats: {},
lastBlocksTime: _.fill(Array(MAX_BINS), 2),
difficultyChart: _.fill(Array(MAX_BINS), 2),
transactionDensity: _.fill(Array(MAX_BINS), 2),
gasSpending: _.fill(Array(MAX_BINS), 2),
miners: [],
map: [],
blockPropagationChart: [],
uncleCountChart: _.fill(Array(MAX_BINS), 2),
coinbases: [],
latency: 0,
currentApiVersion: "0.0.16",
predicate: localStorage.predicate || ['-pinned', '-stats.active', '-stats.block.number', 'stats.block.propagation'],
reverse: localStorage.reverse || false,
pinned: localStorage.pinned || [],
prefixPredicate: ['-pinned', '-stats.active'],
originalPredicate: ['-stats.block.number', 'stats.block.propagation']
});
// $scope.orderTable = function(predicate, reverse)
// {
// if(!_.isEqual(predicate, $scope.originalPredicate))
// {
// $scope.reverse = reverse;
// $scope.originalPredicate = predicate;
// $scope.predicate = _.union($scope.prefixPredicate, predicate);
// }
// else
// {
// $scope.reverse = !$scope.reverse;
// if($scope.reverse === true){
// _.forEach(predicate, function (value, key) {
// predicate[key] = (value[0] === '-' ? value.replace('-', '') : '-' + value);
// });
// }
// $scope.predicate = _.union($scope.prefixPredicate, predicate);
// }
// localStorage.predicate = $scope.predicate;
// localStorage.reverse = $scope.reverse;
// }
// $scope.pinNode = function(id)
// {
// index = findIndex({id: id});
// if( !_.isUndefined($scope.nodes[index]) )
// {
// $scope.nodes[index].pinned = !$scope.nodes[index].pinned;
// if($scope.nodes[index].pinned)
// {
// $scope.pinned.push(id);
// }
// else
// {
// $scope.pinned.splice($scope.pinned.indexOf(id), 1);
// }
// }
// localStorage.pinned = $scope.pinned;
// }
// var timeout = setInterval(function ()
// {
// $scope.$apply();
// }, 300);
// $scope.getNumber = function (num) {
// return new Array(num);
// }
// Socket listeners
// ----------------
socket.on('open', function open() {
socket.emit('ready');
console.log('The connection has been opened.');
})
.on('end', function end() {
console.log('Socket connection ended.')
})
.on('error', function error(err) {
console.log(err);
})
.on('reconnecting', function reconnecting(opts) {
console.log('We are scheduling a reconnect operation', opts);
})
.on('data', function incoming(data) {
socketAction(data.action, data.data);
});
socket.on('init', function(data)
{
_.each(data.nodes, function(node){
Nodes.upsert(node.id, socketAction('init', node));
addToMap(node);
});
});
socket.on('client-latency', function(data)
{
Blockchain.update('meta', {$set: {
latency: data.latency
}});
})
function socketAction(action, data)
{
// console.log('Action: ', action);
// console.log('Data: ', data);
switch(action)
{
case "init":
var node = data;
// Init hashrate
if( _.isUndefined(node.stats.hashrate) )
node.stats.hashrate = 0;
// Init latency
latencyFilter(node);
// Init history
if( _.isUndefined(data.history) )
{
data.history = new Array(40);
_.fill(data.history, -1);
}
// Init or recover pin
node.pinned = (Blockchain.findOne().pinned.indexOf(node.id) >= 0 ? true : false);
if( Nodes.find().count() > 0 )
{
toastr['success']("Got nodes list", "Got nodes!");
updateActiveNodes();
}
return node;
case "add":
if( addNewNode(data) )
toastr['success']("New node "+ Nodes.findOne(data.id).info.name +" connected!", "New node!");
else
toastr['info']("Node "+ Nodes.findOne(data.id).info.name +" reconnected!", "Node is back!");
break;
// TODO: Remove when everybody updates api client to 0.0.12
case "update":
var foundNode = Nodes.findOne(data.id);
if( foundNode && !_.isUndefined(foundNode.stats) )
{
if( !_.isUndefined(foundNode.stats.latency) )
data.stats.latency = foundNode.stats.latency;
if( _.isUndefined(data.stats.hashrate) )
data.stats.hashrate = 0;
if( foundNode.stats.block.number < data.stats.block.number )
{
var best = Nodes.findOne({},{sort: {'stats.block.number': -1}});
if(best) {
if (data.block.number > best.stats.block.number) {
data.block.arrived = _.now();
} else {
data.block.arrived = best.stats.block.arrived;
}
}
foundNode.history = data.history;
}
foundNode.stats = data.stats;
foundNode.stats.block = data.block; // necessary?
if( !_.isUndefined(data.stats.latency) && _.get(foundNode, 'stats.latency', 0) !== data.stats.latency )
{
foundNode.stats.latency = data.stats.latency;
latencyFilter(foundNode);
}
Nodes.update(data.id, foundNode);
updateBestBlock();
}
break;
case "block":
var foundNode = Nodes.findOne(data.id);
if( foundNode && foundNode.stats )
{
var set = {};
if( foundNode.stats.block.number < data.block.number )
{
var best = Nodes.findOne({},{sort: {'stats.block.number': -1}});
if(best) {
if (data.block.number > best.stats.block.number) {
data.block.arrived = _.now();
} else {
data.block.arrived = best.stats.block.arrived;
}
}
set.history = data.history;
}
set['stats.block'] = data.block;
set['stats.propagationAvg'] = data.propagationAvg;
Nodes.update('meta', {$set: set});
updateBestBlock();
}
break;
case "pending":
var foundNode = Nodes.findOne(data.id);
if( !_.isUndefined(data.id) && foundNode )
{
if( !_.isUndefined(foundNode) && !_.isUndefined(foundNode.stats.pending) && !_.isUndefined(data.pending) )
Nodes.update(data.id, {$set: {
'stats.pending': data.pending
}});
}
break;
case "stats":
var foundNode = Nodes.findOne(data.id);
if( !_.isUndefined(data.id) && foundNode )
{
if( !_.isUndefined(foundNode) && !_.isUndefined(foundNode.stats) )
{
Nodes.update(foundNode._id, {$set:{
'stats.active': data.stats.active,
'stats.mining': data.stats.mining,
'stats.hashrate': data.stats.hashrate,
'stats.peers': data.stats.peers,
'stats.gasPrice': data.stats.gasPrice,
'stats.uptime': data.stats.uptime
}});
if( !_.isUndefined(data.stats.latency) && _.get(foundNode, 'stats.latency', 0) !== data.stats.latency )
{
Nodes.update(foundNode._id, {$set:{
'stats.latency': data.stats.latency
}});
latencyFilter(foundNode);
}
updateActiveNodes();
}
}
break;
case "info":
var foundNode = Nodes.findOne(data.id);
if( foundNode )
{
var set = {};
set.info = data.info;
if( _.isUndefined(foundNode.pinned) )
set.pinned = false;
Nodes.update(data.id, {$set: set});
// Init latency
latencyFilter(foundNode);
updateActiveNodes();
}
break;
case "blockPropagationChart":
Blockchain.update('meta', {$set:{
blockPropagationChart: data.histogram,
blockPropagationAvg: data.avg
}});
break;
case "uncleCount":
Blockchain.update('meta', {$set:{
uncleCount: data[0] + data[1],
uncleCountChart: (function(){
data.reverse();
return data;
})()
}});
break;
case "charts":
var meta = Blockchain.findOne('meta');
if( !_.isEqual(meta.avgBlockTime, data.avgBlocktime) )
meta.avgBlockTime = data.avgBlocktime;
if( !_.isEqual(meta.avgHashrate, data.avgHashrate) )
meta.avgHashrate = data.avgHashrate;
if( !_.isEqual(meta.lastBlocksTime, data.blocktime) && data.blocktime.length >= MAX_BINS )
meta.lastBlocksTime = data.blocktime;
if( !_.isEqual(meta.difficultyChart, data.difficulty) && data.difficulty.length >= MAX_BINS )
meta.difficultyChart = data.difficulty;
if( !_.isEqual(meta.blockPropagationChart, data.propagation.histogram) ) {
meta.blockPropagationChart = data.propagation.histogram;
meta.blockPropagationAvg = data.propagation.avg;
}
data.uncleCount.reverse();
if( !_.isEqual(meta.uncleCountChart, data.uncleCount) && data.uncleCount.length >= MAX_BINS ) {
meta.uncleCount = data.uncleCount[data.uncleCount.length-2] + data.uncleCount[data.uncleCount.length-1];
meta.uncleCountChart = data.uncleCount;
}
if( !_.isEqual(meta.transactionDensity, data.transactions) && data.transactions.length >= MAX_BINS )
meta.transactionDensity = data.transactions;
if( !_.isEqual(meta.gasSpending, data.gasSpending) && data.gasSpending.length >= MAX_BINS )
meta.gasSpending = data.gasSpending;
if( !_.isEqual(meta.miners, data.miners) ) {
meta.miners = data.miners;
getMinersNames(meta);
}
// update
delete meta._id;
Blockchain.update('meta', {$set: meta});
break;
case "inactive":
var foundNode = Nodes.findOne(data.id);
if( foundNode )
{
if( !_.isUndefined(data.stats) ) {
Nodes.update(data.id, {$set: {
stats: data.stats
}});
}
toastr['error']("Node "+ foundNode.info.name +" went away!", "Node connection was lost!");
updateActiveNodes();
}
break;
case "latency":
if( !_.isUndefined(data.id) && !_.isUndefined(data.latency) )
{
var foundNode = Nodes.findOne(data.id);
if( foundNode )
{
if( !_.isUndefined(foundNode) && !_.isUndefined(foundNode.stats) && !_.isUndefined(foundNode.stats.latency) && foundNode.stats.latency !== data.latency )
{
Nodes.update(data.id, {$set: {
'stats.latency': data.latency
}});
latencyFilter(foundNode);
}
}
}
break;
case "client-ping":
socket.emit('client-pong', {
serverTime: data.serverTime,
clientTime: _.now()
});
break;
}
// $scope.$apply();
}
function getMinersNames(meta)
{
if( meta.miners.length > 0 )
{
_.forIn(meta.miners, function (value, key)
{
if(value.name !== false)
return;
if(value.miner === "0x0000000000000000000000000000000000000000")
return;
if(miner = Nodes.findOne({'info.coinbase': value.miner}))
var name = miner.info.name;
if( !_.isUndefined(name) ) {
meta.miners[key].name = name;
}
});
}
return meta;
}
function addNewNode(data)
{
var foundNode = Nodes.findOne(data.id);
if( _.isUndefined(data.history) )
{
data.history = new Array(40);
_.fill(data.history, -1);
}
data.pinned = ( !_.isUndefined(foundNode.pinned) ? foundNode.pinned : false);
if( !_.isUndefined(foundNode.history) )
{
data.history = foundNode.history;
}
// update node
Nodes.upsert(data.id, {$set: data});
addToMap(data);
updateActiveNodes();
return false;
}
function addToMap(data) {
// add to map
var bestblock = Blockchain.findOne().bestBlock;
if(!Map.findOne(data.id) && data.geo != null)
Map.insert({
_id: data.id,
radius: 3,
latitude: data.geo.ll[0],
longitude: data.geo.ll[1],
nodeName: data.info.name,
fillClass: mainClass(data.stats, bestblock),
fillKey: mainClass(data.stats, bestblock).replace('text-', ''),
});
}
function updateActiveNodes()
{
updateBestBlock();
var nodesTotal = Nodes.find().count(),
nodesActive = 0,
upTimeTotal = 0;
// iterate over all nodes to get the correct data
_.each(Nodes.find().fetch(), function(node){
if(node.stats) {
if(node.stats.active)
nodesActive++
upTimeTotal += node.stats.uptime;
}
});
Blockchain.update('meta', {$set: {
nodesTotal: nodesTotal,
nodesActive: nodesActive,
upTimeTotal: upTimeTotal / nodesTotal
}});
}
function updateBestBlock()
{
if( Nodes.find().count() )
{
// var chains = {};
// var maxScore = 0;
// _($scope.nodes)
// .map(function (item)
// {
// maxScore += (item.trusted ? 50 : 1);
// if( _.isUndefined(chains[item.stats.block.number]) )
// chains[item.stats.block.number] = [];
// if( _.isUndefined(chains[item.stats.block.number][item.stats.block.fork]) )
// chains[item.stats.block.number][item.stats.block.fork] = {
// fork: item.stats.block.fork,
// count: 0,
// trusted: 0,
// score: 0
// };
// if(item.stats.block.trusted)
// chains[item.stats.block.number][item.stats.block.fork].trusted++;
// else
// chains[item.stats.block.number][item.stats.block.fork].count++;
// chains[item.stats.block.number][item.stats.block.fork].score = chains[item.stats.block.number][item.stats.block.fork].trusted * 50 + chains[item.stats.block.number][item.stats.block.fork].count;
// })
// .value();
// $scope.maxScore = maxScore;
// $scope.chains = _.reduce(chains, function (result, item, key)
// {
// result[key] = _.max(item, 'score');
// return result;
// }, {});
var bestBlock = Nodes.findOne({'stats.block.number': {$exists: true}},{sort: {'stats.block.number': -1}});
if( bestBlock && bestBlock.stats.block.number !== Blockchain.findOne().bestBlock )
{
console.log('bestblock', bestBlock.stats.block.number);
Blockchain.update('meta', {$set: {
bestBlock: bestBlock.stats.block.number,
bestStats: bestBlock.stats,
lastBlock: bestBlock.stats.block.arrived,
lastDifficulty: bestBlock.stats.block.difficulty
}});
}
}
}
// function forkFilter(node)
// {
// if( _.isUndefined(node.readable) )
// node.readable = {};
// node.readable.forkClass = 'hidden';
// node.readable.forkMessage = '';
// return true;
// if( $scope.chains[node.stats.block.number].fork === node.stats.block.fork && $scope.chains[node.stats.block.number].score / $scope.maxScore >= 0.5 )
// {
// node.readable.forkClass = 'hidden';
// node.readable.forkMessage = '';
// return true;
// }
// if( $scope.chains[node.stats.block.number].fork !== node.stats.block.fork )
// {
// node.readable.forkClass = 'text-danger';
// node.readable.forkMessage = 'Wrong chain.<br/>This chain is a fork.';
// return false;
// }
// if( $scope.chains[node.stats.block.number].score / $scope.maxScore < 0.5)
// {
// node.readable.forkClass = 'text-warning';
// node.readable.forkMessage = 'May not be main chain.<br/>Waiting for more confirmations.';
// return false;
// }
// }
function latencyFilter(node)
{
// var set = {};
// if( _.isUndefined(node.readable) )
// set['node.readable'] = {};
// if( _.isUndefined(node.stats) ) {
// set['readable.latencyClass'] = 'text-danger';
// set['readable.latency'] = 'offline';
// }
// if (node.stats.active === false)
// {
// set['readable.latencyClass'] = 'text-danger';
// set['readable.latency'] = 'offline';
// }
// else
// {
// if (node.stats.latency <= 100)
// set['readable.latencyClass'] = 'text-success';
// if (node.stats.latency > 100 && node.stats.latency <= 1000)
// set['readable.latencyClass'] = 'text-warning';
// if (node.stats.latency > 1000)
// set['readable.latencyClass'] = 'text-danger';
// set['readable.latency'] = node.stats.latency + ' ms';
// }
// // update node
// Nodes.upsert(node.id, {$set: set});
}
})();

View File

@@ -0,0 +1,24 @@
(function(){mainClass = function(node, bestBlock)
{
if(!node)
return;
if( ! node.active)
return 'text-gray';
if(node.peers === 0)
return 'text-danger';
return peerClass(node.peers, node.active);
}
peerClass = function(peers, active)
{
if( ! active)
return 'text-gray';
return (peers <= 1 ? 'text-danger' : (peers > 1 && peers < 4 ? 'text-warning' : 'text-success'));
}
})();

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,3 @@
(function(){d3.tip=function(){function t(t){v=d(t),w=v.createSVGPoint(),document.body.appendChild(x)}function e(){return"n"}function n(){return[0,0]}function r(){return" "}function o(){var t=y();return{top:t.n.y-x.offsetHeight,left:t.n.x-x.offsetWidth/2}}function l(){var t=y();return{top:t.s.y,left:t.s.x-x.offsetWidth/2}}function s(){var t=y();return{top:t.e.y-x.offsetHeight/2,left:t.e.x}}function f(){var t=y();return{top:t.w.y-x.offsetHeight/2,left:t.w.x-x.offsetWidth}}function i(){var t=y();return{top:t.nw.y-x.offsetHeight,left:t.nw.x-x.offsetWidth}}function u(){var t=y();return{top:t.ne.y-x.offsetHeight,left:t.ne.x}}function a(){var t=y();return{top:t.sw.y,left:t.sw.x-x.offsetWidth}}function c(){var t=y();return{top:t.se.y,left:t.e.x}}function p(){var t=d3.select(document.createElement("div"));return t.style({position:"absolute",opacity:0,pointerEvents:"none",boxSizing:"border-box"}),t.node()}function d(t){return t=t.node(),"svg"==t.tagName.toLowerCase()?t:t.ownerSVGElement}function y(){var t=T||d3.event.target,e={},n=t.getScreenCTM(),r=t.getBBox(),o=r.width,l=r.height,s=r.x,f=r.y,i=document.documentElement.scrollTop||document.body.scrollTop,u=document.documentElement.scrollLeft||document.body.scrollLeft;return w.x=s+u,w.y=f+i,e.nw=w.matrixTransform(n),w.x+=o,e.ne=w.matrixTransform(n),w.y+=l,e.se=w.matrixTransform(n),w.x-=o,e.sw=w.matrixTransform(n),w.y-=l/2,e.w=w.matrixTransform(n),w.x+=o,e.e=w.matrixTransform(n),w.x-=o/2,w.y-=l/2,e.n=w.matrixTransform(n),w.y+=l,e.s=w.matrixTransform(n),e}var m=e,g=n,h=r,x=p(),v=null,w=null,T=null;t.show=function(){var e=Array.prototype.slice.call(arguments);e[e.length-1]instanceof SVGElement&&(T=e.pop());var n,r=h.apply(this,e),o=g.apply(this,e),l=m.apply(this,e),s=d3.select(x),f=0;for(s.html(r).style({opacity:1,"pointer-events":"all"});f--;)s.classed(E[f],!1);return n=b.get(l).apply(this),s.classed(l,!0).style({top:n.top+o[0]+"px",left:n.left+o[1]+"px"}),t},t.hide=function(){return nodel=d3.select(x),nodel.style({opacity:0,"pointer-events":"none"}),t},t.attr=function(e){if(arguments.length<2&&"string"==typeof e)return d3.select(x).attr(e);var n=Array.prototype.slice.call(arguments);return d3.selection.prototype.attr.apply(d3.select(x),n),t},t.style=function(e){if(arguments.length<2&&"string"==typeof e)return d3.select(x).style(e);var n=Array.prototype.slice.call(arguments);return d3.selection.prototype.style.apply(d3.select(x),n),t},t.direction=function(e){return arguments.length?(m=null==e?e:d3.functor(e),t):m},t.offset=function(e){return arguments.length?(g=null==e?e:d3.functor(e),t):g},t.html=function(e){return arguments.length?(h=null==e?e:d3.functor(e),t):h};var b=d3.map({n:o,s:l,e:s,w:f,nw:i,ne:u,sw:a,se:c}),E=b.keys();return t};
})();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,3 @@
(function(){!function(e){"function"==typeof define&&define.amd?define(["moment"],e):"object"==typeof exports?module.exports=e(require("../moment")):e(("undefined"!=typeof global?global:this).moment)}(function(e){return e.defineLocale("en-gb",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY LT",LLLL:"dddd, D MMMM YYYY LT"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few sec",m:"1 min",mm:"%d min",h:"1 h",hh:"%d h",d:"a day",dd:"%d days",M:"a month",MM:"%d mon",y:"a year",yy:"%d years"},ordinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var a=e%10,d=1===~~(e%100/10)?"th":1===a?"st":2===a?"nd":3===a?"rd":"th";return e+d},week:{dow:1,doy:4}})});
})();

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,3 @@
(function(){!function(e){e(["jquery"],function(e){return function(){function t(e,t,n){return f({type:O.error,iconClass:g().iconClasses.error,message:e,optionsOverride:n,title:t})}function n(t,n){return t||(t=g()),v=e("#"+t.containerId),v.length?v:(n&&(v=c(t)),v)}function i(e,t,n){return f({type:O.info,iconClass:g().iconClasses.info,message:e,optionsOverride:n,title:t})}function o(e){w=e}function s(e,t,n){return f({type:O.success,iconClass:g().iconClasses.success,message:e,optionsOverride:n,title:t})}function a(e,t,n){return f({type:O.warning,iconClass:g().iconClasses.warning,message:e,optionsOverride:n,title:t})}function r(e){var t=g();v||n(t),l(e,t)||u(t)}function d(t){var i=g();return v||n(i),t&&0===e(":focus",t).length?void h(t):void(v.children().length&&v.remove())}function u(t){for(var n=v.children(),i=n.length-1;i>=0;i--)l(e(n[i]),t)}function l(t,n){return t&&0===e(":focus",t).length?(t[n.hideMethod]({duration:n.hideDuration,easing:n.hideEasing,complete:function(){h(t)}}),!0):!1}function c(t){return v=e("<div/>").attr("id",t.containerId).addClass(t.positionClass).attr("aria-live","polite").attr("role","alert"),v.appendTo(e(t.target)),v}function p(){return{tapToDismiss:!0,toastClass:"toast",containerId:"toast-container",debug:!1,showMethod:"fadeIn",showDuration:300,showEasing:"swing",onShown:void 0,hideMethod:"fadeOut",hideDuration:1e3,hideEasing:"swing",onHidden:void 0,extendedTimeOut:1e3,iconClasses:{error:"toast-error",info:"toast-info",success:"toast-success",warning:"toast-warning"},iconClass:"toast-info",positionClass:"toast-top-right",timeOut:5e3,titleClass:"toast-title",messageClass:"toast-message",target:"body",closeHtml:"<button>&times;</button>",newestOnTop:!0,preventDuplicates:!1,progressBar:!1}}function m(e){w&&w(e)}function f(t){function i(t){return!e(":focus",l).length||t?(clearTimeout(O.intervalId),l[r.hideMethod]({duration:r.hideDuration,easing:r.hideEasing,complete:function(){h(l),r.onHidden&&"hidden"!==b.state&&r.onHidden(),b.state="hidden",b.endTime=new Date,m(b)}})):void 0}function o(){(r.timeOut>0||r.extendedTimeOut>0)&&(u=setTimeout(i,r.extendedTimeOut),O.maxHideTime=parseFloat(r.extendedTimeOut),O.hideEta=(new Date).getTime()+O.maxHideTime)}function s(){clearTimeout(u),O.hideEta=0,l.stop(!0,!0)[r.showMethod]({duration:r.showDuration,easing:r.showEasing})}function a(){var e=(O.hideEta-(new Date).getTime())/O.maxHideTime*100;f.width(e+"%")}var r=g(),d=t.iconClass||r.iconClass;if(r.preventDuplicates){if(t.message===C)return;C=t.message}"undefined"!=typeof t.optionsOverride&&(r=e.extend(r,t.optionsOverride),d=t.optionsOverride.iconClass||d),T++,v=n(r,!0);var u=null,l=e("<div/>"),c=e("<div/>"),p=e("<div/>"),f=e("<div/>"),w=e(r.closeHtml),O={intervalId:null,hideEta:null,maxHideTime:null},b={toastId:T,state:"visible",startTime:new Date,options:r,map:t};return t.iconClass&&l.addClass(r.toastClass).addClass(d),t.title&&(c.append(t.title).addClass(r.titleClass),l.append(c)),t.message&&(p.append(t.message).addClass(r.messageClass),l.append(p)),r.closeButton&&(w.addClass("toast-close-button").attr("role","button"),l.prepend(w)),r.progressBar&&(f.addClass("toast-progress"),l.prepend(f)),l.hide(),r.newestOnTop?v.prepend(l):v.append(l),l[r.showMethod]({duration:r.showDuration,easing:r.showEasing,complete:r.onShown}),r.timeOut>0&&(u=setTimeout(i,r.timeOut),O.maxHideTime=parseFloat(r.timeOut),O.hideEta=(new Date).getTime()+O.maxHideTime,r.progressBar&&(O.intervalId=setInterval(a,10))),l.hover(s,o),!r.onclick&&r.tapToDismiss&&l.click(i),r.closeButton&&w&&w.click(function(e){e.stopPropagation?e.stopPropagation():void 0!==e.cancelBubble&&e.cancelBubble!==!0&&(e.cancelBubble=!0),i(!0)}),r.onclick&&l.click(function(){r.onclick(),i()}),m(b),r.debug&&console&&console.log(b),l}function g(){return e.extend({},p(),b.options)}function h(e){v||(v=n()),e.is(":visible")||(e.remove(),e=null,0===v.children().length&&v.remove())}var v,w,C,T=0,O={error:"error",info:"info",success:"success",warning:"warning"},b={clear:r,remove:d,error:t,getContainer:n,info:i,options:{},subscribe:o,success:s,version:"2.1.0",warning:a};return b}()})}("function"==typeof define&&define.amd?define:function(e,t){"undefined"!=typeof module&&module.exports?module.exports=t(require("jquery")):window.toastr=t(window.jQuery)});
})();

View File

@@ -0,0 +1,38 @@
(function(){(function() {
$('body').on('mouseenter', '[data-toggle="tooltip"]', function( event ) {
$(this).tooltip('show');
}).on('mouseleave', '[data-toggle="tooltip"]', function( event ) {
$(this).tooltip('hide');
});
$.fn.sparkline.defaults.bar.height = 63;
$.fn.sparkline.defaults.bar.barWidth = 6;
$.fn.sparkline.defaults.bar.barSpacing = 1;
$.fn.sparkline.defaults.bar.tooltipClassname = 'jqstooltip';
$.fn.sparkline.defaults.bar.tooltipOffsetX = 0;
$.fn.sparkline.defaults.bar.tooltipFormat = $.spformat('<div class="tooltip-arrow"></div><div class="tooltip-inner">{{prefix}}{{value}} {{suffix}}</div>');
$.fn.sparkline.defaults.bar.colorMap = $.range_map({
'0:6': '#10a0de',
'6:13': '#7bcc3a',
'13:20': '#FFD162',
'20:30': '#ff8a00',
'30:': '#F74B4B'
});
moment.relativeTimeThreshold('s', 60);
moment.relativeTimeThreshold('m', 60);
moment.relativeTimeThreshold('h', 24);
moment.relativeTimeThreshold('d', 28);
moment.relativeTimeThreshold('M', 12);
})();
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-63657296-1', 'auto');
ga('send', 'pageview');
})();

View File

@@ -0,0 +1,649 @@
(function(){
function blockTimeClass(diff)
{
if(diff <= 13)
return 'text-success';
if(diff <= 20)
return 'text-warning';
if(diff <= 30)
return 'text-orange';
return 'text-danger'
}
function timeClass(timestamp)
{
var diff = ((new Date()).getTime() - timestamp)/1000;
return blockTimeClass(diff);
}
function compareVersions(v1, comparator, v2)
{
comparator = comparator == '=' ? '==' : comparator;
var v1parts = v1.split('.'), v2parts = v2.split('.');
var maxLen = Math.max(v1parts.length, v2parts.length);
var part1, part2;
var cmp = 0;
for(var i = 0; i < maxLen && !cmp; i++)
{
part1 = parseInt(v1parts[i], 10) || 0;
part2 = parseInt(v2parts[i], 10) || 0;
if(part1 < part2)
cmp = 1;
if(part1 > part2)
cmp = -1;
}
return eval('0' + comparator + cmp);
}
function mainClass(node, bestBlock)
{
if(!node)
return;
if( ! node.active)
return 'text-gray';
if(node.peers === 0)
return 'text-danger';
return peerClass(node.peers, node.active);
}
function peerClass(peers, active)
{
if( ! active)
return 'text-gray';
return (peers <= 1 ? 'text-danger' : (peers > 1 && peers < 4 ? 'text-warning' : 'text-success'));
}
function blockTimeClass(diff)
{
if(diff <= 13)
return 'text-success';
if(diff <= 20)
return 'text-warning';
if(diff <= 30)
return 'text-orange';
return 'text-danger'
}
// global template helpers
Template.registerHelper('Blockchain', function(){
return Blockchain.findOne('meta');
});
Template.registerHelper('nodes', function(uptime) {
return Nodes.find({},{sort: {'stats.block.number': -1, 'stats.active': -1}});
});
Template.registerHelper('number', function(number){
return numeral(number).format('0,0');
});
Template.registerHelper('avgTimeClass', function(time){
return blockTimeClass(time);
});
Template.registerHelper('blockTimeFilter', function(timestamp){
if(timestamp === 0)
return '∞';
// var time = Math.floor((new Date()).getTime() / 1000);
var time = (new Date()).getTime();
var diff = Math.floor((time - timestamp)/1000);
if(diff < 60)
return Math.round(diff) + ' s ago';
return moment.duration(Math.round(diff), 's').humanize() + ' ago';
});
Template.registerHelper('timeClass', function(timestamp, active){
if( _.isBoolean(active) && ! active)
return 'text-gray';
return timeClass(timestamp);
});
Template.registerHelper('avgTimeFilter', function(time){
if(time < 60)
return parseFloat(time).toFixed(2) + ' s';
return moment.duration(Math.round(time), 's').humanize();
});
Template.registerHelper('networkHashrateFilter', function(hashes, isMining){
if(hashes === null)
hashes = 0;
var result = 0;
var unit = 'K';
if(hashes !== 0 && hashes < 1000) {
result = hashes;
unit = '';
}
if(hashes >= 1000 && hashes < Math.pow(1000, 2)) {
result = hashes / 1000;
unit = 'K';
}
if(hashes >= Math.pow(1000, 2) && hashes < Math.pow(1000, 3)) {
result = hashes / Math.pow(1000, 2);
unit = 'M';
}
if(hashes >= Math.pow(1000, 3) && hashes < Math.pow(1000, 4)) {
result = hashes / Math.pow(1000, 3);
unit = 'G';
}
if(hashes >= Math.pow(1000, 4) && hashes < Math.pow(1000, 5)) {
result = hashes / Math.pow(1000, 4);
unit = 'T';
}
if( !isMining )
return new Spacebars.SafeString(result.toFixed(1) + ' <span class="small-hash">' + unit + 'H/s</span>');
return new Spacebars.SafeString('? <span class="small-hash">' + unit + 'KH/s</span>');
});
Template.registerHelper('nodesActiveClass', function(active, total) {
var ratio = active/total;
if(ratio >= 0.9)
return 'text-success';
if(ratio >= 0.75)
return 'text-info';
if(ratio >= 0.5)
return 'text-warning';
return 'text-danger';
});
Template.registerHelper('gasPriceFilter', function(price) {
if(typeof price === 'undefined')
return "0 wei";
if(price.length < 4)
return numeral(price).format('0,0') + " wei";
if(price.length < 7)
return numeral(price/1000).format('0,0') + " kwei";
if(price.length < 10)
return numeral(price/1000000).format('0,0') + " mwei";
if(price.length < 13)
return numeral(price/1000000000).format('0,0') + " gwei";
if(price.length < 16)
return numeral(price/1000000000000).format('0,0') + " szabo";
if(price.length < 19)
return numeral(price.substr(0, price.length - 15)).format('0,0') + " finney";
return numeral(price.substr(0, price.length - 18)).format('0,0') + " ether";
});
Template.registerHelper('upTimeFilter', function(uptime) {
return Math.round(uptime) + '%';
});
Template.registerHelper('propagationAvgTimeClass', function(propagationAvg, active) {
if( ! active)
return 'text-gray';
if(propagationAvg == 0)
return 'text-info';
if(propagationAvg < 1000)
return 'text-success';
if(propagationAvg < 3000)
return 'text-warning';
if(propagationAvg < 7000)
return 'text-orange';
return 'text-danger'
});
Template.registerHelper('minerBlocksClass', function(blocks, prefix) {
if(typeof prefix === 'undefined')
prefix = 'bg-';
if(blocks <= 6)
return prefix + 'success';
if(blocks <= 12)
return prefix + 'info';
if(blocks <= 18)
return prefix + 'warning';
return prefix + 'danger';
});
Template.registerHelper('latencyClass', function(active, latency) {
if(active === false)
return 'text-danger';
if(latency <= 100)
return 'text-success';
if(latency <= 1000)
return 'text-warning';
return 'text-danger'
});
Template.registerHelper('upTimeClass', function(uptime, active) {
if( active === false )
return 'text-gray';
if(uptime >= 90)
return 'text-success';
if(uptime >= 75)
return 'text-warning';
return 'text-danger';
});
Template.registerHelper('nodePinClass', function(pinned) {
if(pinned)
return 'icon-check-o';
return 'icon-loader';
});
Template.registerHelper('mainClass', function(node, bestBlock) {
return mainClass(node, bestBlock);
});
Template.registerHelper('peerClass', function(peers, active) {
return peerClass(peers, active);
});
Template.registerHelper('miningClass', function(mining, active) {
if(! active)
return 'text-gray';
return (! mining ? 'text-danger' : 'text-success');
});
Template.registerHelper('miningIconClass', function(mining) {
return (! mining ? 'icon-cancel' : 'icon-check');
});
Template.registerHelper('hashrateClass', function(mining, active) {
if(! mining || ! active)
return 'text-gray';
return 'text-success';
});
Template.registerHelper('nodeClientClass', function(info, current) {
if(typeof info === 'undefined' || typeof info.client === 'undefined' || typeof info.client === '')
return 'text-danger';
if(compareVersions(info.client, '<', current))
return 'text-danger';
return 'hidden';
})
Template.registerHelper('consensusClass', function(nodes, bestBlock) {
var status = 'success';
var now = _.now();
for(var x = 0; x < nodes.length; x++)
{
if(nodes[x].stats.block.number === bestBlock.number && nodes[x].stats.block.hash !== bestBlock.hash)
return 'danger';
if((bestBlock.number - nodes[x].stats.block.number) > 1 && (now - bestBlock.received) >= 20*1000)
status = 'orange';
if((bestBlock.number - nodes[x].stats.block.number) === 1 && (now - bestBlock.received) >= 10*1000 && status !== 'orange')
status = 'warning';
}
return status;
});
Template.registerHelper('consensusFilter', function(nodes, bestBlock) {
var cnt = 0;
for(var x = 0; x < nodes.length; x++)
{
if(nodes[x].stats.block.number === bestBlock.number && nodes[x].stats.block.hash === bestBlock.hash)
cnt++;
}
return cnt + '/' + nodes.length;
});
Template.registerHelper('geoTooltip', function(node) {
var tooltip = [];
var string = '';
if(!node.info)
return;
if(node.info.node !== '' && typeof node.info.node !== 'undefined') {
var eth_version = node.info.node.split('/');
if(eth_version[1][0] !== 'v' && eth_version[1][2] !== '.')
{
eth_version.splice(1,1);
}
string = "<b>" + node.info.node + "</b>";
tooltip.push(string);
string = "Version: <b>" + (eth_version[1]) + "</b>";
tooltip.push(string);
}
if(node.info.net !== '') {
string = "Network: <b>" + (typeof node.info.net !== 'undefined' ? node.info.net : '-') + "</b>";
tooltip.push(string);
}
if(node.info.protocol !== '') {
string = "Protocol: <b>" + (typeof node.info.protocol !== 'undefined' ? node.info.protocol : '-') + "</b>";
tooltip.push(string);
}
if(node.info.port !== '') {
string = "Port: <b>" + (typeof node.info.port !== 'undefined' ? node.info.port : '30303') + "</b>";
tooltip.push(string);
}
if(node.info.api !== '') {
string = "Web3: <b>" + node.info.api + "</b>";
tooltip.push(string);
}
if(node.info.client !== '') {
string = "API: <b>" + (typeof node.info.client !== 'undefined' ? node.info.client : '<= 0.0.3') + "</b>";
tooltip.push(string);
}
if(node.info.os !== '') {
string = "OS: <b>" + (typeof node.info.os !== 'undefined' ? node.info.os + ' ' + node.info.os_v : '?') + "</b>";
tooltip.push(string);
}
if(node.geo !== null)
{
string = "Location: <b>";
if(node.geo.city !== '')
string += node.geo.city + ", ";
string += node.geo.country + "</b>";
tooltip.push(string);
}
if(node.info.contact !== '') {
string = "Contact: <b>" + (typeof node.info.contact !== 'undefined' ? node.info.contact : '-') + "</b>";
tooltip.push(string);
}
return tooltip.join("<br>");
});
Template.registerHelper('bubbleClass', function(node, bestBlock) {
return mainClass(node, bestBlock).replace('text-', '');
});
Template.registerHelper('minerNameFilter', function(address, name) {
if(typeof name !== 'undefined' && name !== false && name.length > 0)
return name;
return address.replace('0x', '');
});
Template.registerHelper('blockPropagationFilter', function(ms, prefix) {
if(!prefix)
prefix = '+';
var result = 0;
if(ms < 1000) {
return (ms === 0 ? "" : prefix) + ms + " ms";
}
if(ms < 1000*60) {
result = ms/1000;
return prefix + result.toFixed(1) + " s";
}
if(ms < 1000*60*60) {
result = ms/1000/60;
return prefix + Math.round(result) + " min";
}
if(ms < 1000*60*60*24) {
result = ms/1000/60/60;
return prefix + Math.round(result) + " h";
}
result = ms/1000/60/60/24;
return prefix + Math.round(result) + " days";
});
Template.registerHelper('blockPropagationAvgFilter', function(stats, bestBlock) {
if(!stats)
return;
var ms = stats.propagationAvg;
if(bestBlock - stats.block.number > 40)
return "∞";
//ms = _.now() - stats.block.received;
prefix = '';
var result = 0;
if(ms < 1000) {
return (ms === 0 ? "" : prefix) + ms + " ms";
}
if(ms < 1000*60) {
result = ms/1000;
return prefix + result.toFixed(1) + " s";
}
if(ms < 1000*60*60) {
result = ms/1000/60;
return prefix + Math.round(result) + " min";
}
if(ms < 1000*60*60*24) {
result = ms/1000/60/60;
return prefix + Math.round(result) + " h";
}
result = ms/1000/60/60/24;
return prefix + Math.round(result) + " days";
});
Template.registerHelper('propagationTimeClass', function(stats, bestBlock) {
if( ! stats.active)
return 'text-gray';
if(stats.block.number < bestBlock)
return 'text-gray';
if(stats.block.propagation == 0)
return 'text-info';
if(stats.block.propagation < 1000)
return 'text-success';
if(stats.block.propagation < 3000)
return 'text-warning';
if(stats.block.propagation < 7000)
return 'text-orange';
return 'text-danger'
});
Template.registerHelper('propagationNodeAvgTimeClass', function(stats, bestBlock) {
if(!stats)
return;
if( ! stats.active)
return 'text-gray';
if(stats.block.number < bestBlock)
return 'text-gray';
if(stats.propagationAvg == 0)
return 'text-info';
if(stats.propagationAvg < 1000)
return 'text-success';
if(stats.propagationAvg < 3000)
return 'text-warning';
if(stats.propagationAvg < 7000)
return 'text-orange';
return 'text-danger'
});
Template.registerHelper('hashrateFilter', function(hashes, isMining) {
var result = 0;
var unit = 'K';
if( !isMining )
return new Spacebars.SafeString('<i class="icon-cancel"></i>');
if(hashes !== 0 && hashes < 1000) {
result = hashes;
unit = '';
}
if(hashes >= 1000 && hashes < Math.pow(1000, 2)) {
result = hashes / 1000;
unit = 'K';
}
if(hashes >= Math.pow(1000, 2) && hashes < Math.pow(1000, 3)) {
result = hashes / Math.pow(1000, 2);
unit = 'M';
}
if(hashes >= Math.pow(1000, 3) && hashes < Math.pow(1000, 4)) {
result = hashes / Math.pow(1000, 3);
unit = 'G';
}
if(hashes >= Math.pow(1000, 4) && hashes < Math.pow(1000, 5)) {
result = hashes / Math.pow(1000, 4);
unit = 'T';
}
return new Spacebars.SafeString('<span class="small">' + numeral(result).format('0,0') + ' <span class="small-hash">' + unit + 'H/s</span></span>');
});
Template.registerHelper('nodeVersion', function(version) {
if(typeof version !== 'undefined')
{
var tmp = version.split('/');
tmp[0] = tmp[0].replace('Ethereum(++)', 'Eth');
if(tmp[0].indexOf('pyethapp') === 0)
{
tmp[0] = 'pyeth';
}
if(tmp[1][0] !== 'v' && tmp[1][2] !== '.')
{
tmp.splice(1,1);
}
if(tmp[2] === 'Release'){
tmp.splice(2,1);
}
if(tmp[2].indexOf('Linux') === 0)
tmp[2] = 'linux';
if(tmp[2].indexOf('Darwin') === 0)
tmp[2] = 'darwin';
return new Spacebars.SafeString(tmp.join('/'));
}
return '';
});
Template.registerHelper('blockClass', function(current, best) {
if(!current)
return;
if( ! current.active)
return 'text-gray';
return (best - current.block.number < 1 ? 'text-success' : (best - current.block.number === 1 ? 'text-warning' : (best - current.block.number > 1 && best - current.block.number < 4 ? 'text-orange' : 'text-danger')));
});
Template.registerHelper('gasFilter', function(gas) {
return (typeof gas !== 'undefined' ? parseInt(gas) : '?');
});
Template.registerHelper('hashFilter', function(hash) {
if(typeof hash === 'undefined')
return "?";
if(hash.substr(0,2) === '0x')
hash = hash.substr(2,64);
return hash.substr(0, 8) + '...' + hash.substr(56, 8);
});
})();

View File

@@ -0,0 +1,14 @@
(function(){
Template.__checkName("error");
Template["error"] = new Template("Template.error", (function() {
var view = this;
return [ HTML.H1(Blaze.View("lookup:message", function() {
return Spacebars.mustache(view.lookup("message"));
})), HTML.H2(Blaze.View("lookup:error.status", function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("error"), "status"));
})), HTML.PRE(Blaze.View("lookup:error.stack", function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("error"), "stack"));
})) ];
}));
})();

View File

@@ -0,0 +1,515 @@
(function(){
Template.__checkName("index");
Template["index"] = new Template("Template.index", (function() {
var view = this;
return HTML.DIV({
"class": "container-fluid",
"ng-controller": "StatsCtrl"
}, HTML.DIV({
"class": "row"
}, HTML.DIV({
"class": [ "col-xs-2", " ", "stat-holder" ]
}, HTML.DIV({
"class": [ "big-info", " ", "bestblock", " ", "text-info" ]
}, HTML.Raw('<div class="pull-left icon-full-width"><i class="icon-block"></i></div>'), "\n", HTML.DIV({
"class": "big-details-holder"
}, HTML.Raw('<span class="small-title">best block</span>'), "\n", HTML.SPAN({
"class": "big-details"
}, Blaze.View("lookup:number", function() {
return Spacebars.mustache(view.lookup("number"), Spacebars.dot(view.lookup("Blockchain"), "bestBlock"));
}))), "\n", HTML.Raw('<div class="clearfix"></div>'))), "\n", HTML.DIV({
"class": [ "col-xs-2", " ", "stat-holder" ]
}, HTML.DIV({
"class": [ "big-info", " ", "uncleCount", " ", "text-info" ]
}, HTML.Raw('<div class="pull-left icon-full-width"><i class="icon-uncle"></i></div>'), "\n", HTML.DIV({
"class": "big-details-holder"
}, HTML.Raw('<span class="small-title">uncles&nbsp;\n<span class="small">(current / last 50)</span></span>'), "\n", HTML.SPAN({
"class": "big-details"
}, Blaze.View("lookup:Blockchain.bestStats.block.uncles.length", function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("Blockchain"), "bestStats", "block", "uncles", "length"));
}), "/", Blaze.View("lookup:Blockchain.uncleCount", function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("Blockchain"), "uncleCount"));
}))), "\n", HTML.Raw('<div class="clearfix"></div>'))), "\n", HTML.DIV({
"class": [ "col-xs-2", " ", "stat-holder" ]
}, HTML.DIV({
"class": function() {
return [ "big-info", " ", "blocktime", " ", Spacebars.mustache(view.lookup("timeClass"), view.lookup("lastBlock"), true) ];
}
}, HTML.Raw('<div class="pull-left icon-full-width"><i class="icon-time"></i></div>'), "\n", HTML.DIV({
"class": "big-details-holder"
}, HTML.Raw('<span class="small-title">last block</span>'), "\n", HTML.SPAN({
"class": "big-details"
}, Blaze.View("lookup:blockTimeFilter", function() {
return Spacebars.mustache(view.lookup("blockTimeFilter"), Spacebars.dot(view.lookup("Blockchain"), "lastBlock"));
})), "\n", ""), "\n", HTML.Raw('<div class="clearfix"></div>'))), "\n", HTML.DIV({
"class": [ "col-xs-2", " ", "stat-holder" ]
}, HTML.DIV({
"class": function() {
return [ "big-info", " ", "avgblocktime", " ", Spacebars.mustache(view.lookup("avgTimeClass"), view.lookup("avgBlockTime")) ];
}
}, HTML.Raw('<div class="pull-left icon-full-width"><i class="icon-gas"></i></div>'), "\n", HTML.DIV({
"class": "big-details-holder"
}, HTML.Raw('<span class="small-title">avg block time</span>'), "\n", HTML.SPAN({
"class": "big-details"
}, Blaze.View("lookup:avgTimeFilter", function() {
return Spacebars.mustache(view.lookup("avgTimeFilter"), Spacebars.dot(view.lookup("Blockchain"), "avgBlockTime"));
}))), "\n", HTML.Raw('<div class="clearfix"></div>'))), "\n", HTML.DIV({
"class": [ "col-xs-2", " ", "stat-holder" ]
}, HTML.DIV({
"class": [ "big-info", " ", "difficulty", " ", "text-orange" ]
}, HTML.Raw('<div class="pull-left icon-full-width"><i class="icon-hashrate"></i></div>'), "\n", HTML.DIV({
"class": "big-details-holder"
}, HTML.Raw('<span class="small-title">avg network hashrate</span>'), "\n", HTML.SPAN({
"class": "big-details"
}, Blaze.View("lookup:networkHashrateFilter", function() {
return Spacebars.mustache(view.lookup("networkHashrateFilter"), Spacebars.dot(view.lookup("Blockchain"), "avgHashrate"), false);
}))), "\n", HTML.Raw('<div class="clearfix"></div>'))), "\n", HTML.DIV({
"class": [ "col-xs-2", " ", "stat-holder" ]
}, HTML.DIV({
"class": [ "big-info", " ", "difficulty", " ", "text-danger" ]
}, HTML.Raw('<div class="pull-left icon-full-width"><i class="icon-difficulty"></i></div>'), "\n", HTML.DIV({
"class": "big-details-holder"
}, HTML.Raw('<span class="small-title">difficulty</span>'), "\n", HTML.SPAN({
"class": "big-details"
}, HTML.SPAN({
"class": "small-hash"
}, Blaze.View("lookup:number", function() {
return Spacebars.mustache(view.lookup("number"), Spacebars.dot(view.lookup("Blockchain"), "lastDifficulty"));
})))), "\n", HTML.Raw('<div class="clearfix"></div>'))), "\n", HTML.Raw('<div class="clearfix"></div>')), "\n", HTML.DIV({
"class": "row"
}, HTML.DIV({
"class": [ "col-xs-8", " ", "stats-boxes" ],
style: "padding-top: 0px;"
}, HTML.DIV({
"class": [ "row", " ", "second-row" ]
}, HTML.DIV({
"class": [ "col-xs-3", " ", "stat-holder", " ", "box" ]
}, HTML.DIV({
"class": function() {
return [ "active-nodes", " ", Spacebars.mustache(view.lookup("nodesActiveClass"), Spacebars.dot(view.lookup("Blockchain"), "nodesActive"), Spacebars.dot(view.lookup("Blockchain"), "nodesTotal")) ];
}
}, HTML.Raw('<i class="icon-node"></i>'), "\n", HTML.Raw('<span class="small-title">active nodes</span>'), "\n", HTML.SPAN({
"class": "small-value"
}, Blaze.View("lookup:Blockchain.nodesActive", function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("Blockchain"), "nodesActive"));
}), "/", Blaze.View("lookup:Blockchain.nodesTotal", function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("Blockchain"), "nodesTotal"));
})))), "\n", "", "\n", "", "\n", "", "\n", "", "\n", "", "\n", HTML.DIV({
"class": [ "col-xs-3", " ", "stat-holder", " ", "box" ]
}, HTML.DIV({
"class": [ "gasprice", " ", "text-info" ]
}, HTML.Raw('<i class="icon-gasprice"></i>'), "\n", HTML.Raw('<span class="small-title">gas price</span>'), "\n", HTML.SPAN({
"class": "small-value"
}, Blaze.View("lookup:gasPriceFilter", function() {
return Spacebars.mustache(view.lookup("gasPriceFilter"), Spacebars.dot(view.lookup("Blockchain"), "bestStats", "gasPrice", "toString"));
})))), "\n", HTML.DIV({
"class": [ "col-xs-3", " ", "stat-holder", " ", "box" ]
}, HTML.DIV({
"class": function() {
return [ "page-latency", " ", Spacebars.mustache(view.lookup("latencyClass"), true, Spacebars.dot(view.lookup("Blockchain"), "latency")) ];
}
}, HTML.Raw('<i class="icon-clock"></i>'), "\n", HTML.Raw('<span class="small-title">page latency</span>'), "\n", HTML.SPAN({
"class": "small-value"
}, Blaze.View("lookup:Blockchain.latency", function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("Blockchain"), "latency"));
}), " ms"))), "\n", HTML.DIV({
"class": [ "col-xs-3", " ", "stat-holder", " ", "box" ]
}, HTML.DIV({
"class": function() {
return [ "uptime", " ", Spacebars.mustache(view.lookup("upTimeClass"), view.lookup("upTimeTotal"), true) ];
}
}, HTML.Raw('<i class="icon-bulb"></i>'), "\n", HTML.Raw('<span class="small-title">uptime</span>'), "\n", HTML.SPAN({
"class": "small-value"
}, Blaze.View("lookup:upTimeFilter", function() {
return Spacebars.mustache(view.lookup("upTimeFilter"), Spacebars.dot(view.lookup("Blockchain"), "upTimeTotal"));
}))))), "\n", HTML.DIV({
"class": "row"
}, HTML.DIV({
"class": [ "col-xs-3", " ", "stat-holder" ]
}, HTML.DIV({
"class": function() {
return [ "big-info", " ", "chart", " ", Spacebars.mustache(view.lookup("avgTimeClass"), Spacebars.dot(view.lookup("Blockchain"), "avgBlockTime")) ];
}
}, "", "\n", HTML.Raw('<span class="small-title">block time</span>'), "\n", "", "\n", HTML.getTag("sparkchart")({
"class": [ "big-details", " ", "spark-blocktimes" ],
data: function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("Blockchain"), "lastBlocksTime", "join"));
},
tooltipsuffix: "s"
}))), "\n", HTML.DIV({
"class": [ "col-xs-3", " ", "stat-holder" ]
}, HTML.DIV({
"class": [ "big-info", " ", "chart", " ", "text-info" ]
}, "", "\n", HTML.Raw('<span class="small-title">difficulty</span>'), "\n", "", "\n", HTML.getTag("sparkchart")({
"class": [ "big-details", " ", "spark-difficulty" ],
data: function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("Blockchain"), "difficultyChart", "join"));
}
}))), "\n", HTML.DIV({
"class": [ "col-xs-3", " ", "stat-holder", " ", "xpull-right" ]
}, HTML.DIV({
"class": function() {
return [ "big-info", " ", "chart", " ", "xdouble-chart", " ", Spacebars.mustache(view.lookup("propagationAvgTimeClass"), Spacebars.dot(view.lookup("Blockchain"), "blockPropagationAvg"), true) ];
}
}, "", "\n", HTML.Raw('<span class="small-title">block propagation</span>'), "\n", "", "\n", HTML.getTag("histogram")({
"class": [ "big-details", " ", "d3-blockpropagation" ],
data: "blockPropagationChart"
}))), "\n", HTML.DIV({
"class": [ "col-xs-3", " ", "stat-holder", " ", "pull-right" ]
}, HTML.DIV({
"class": [ "big-info", " ", "chart", " ", "double-chart" ]
}, HTML.Raw('<span class="small-title">last blocks miners</span>'), "\n", HTML.DIV({
"class": "blocks-holder",
"ng-repeat": "miner in miners track by miner.miner",
"data-toggle": "tooltip",
"data-placement": "right",
"data-original-title": function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("Blockchain"), "miner", "blocks"));
}
}, HTML.DIV({
"class": function() {
return [ "block-count", " ", Spacebars.mustache(view.lookup("minerBlocksClass"), Spacebars.dot(view.lookup("Blockchain"), "miner", "blocks"), "text-") ];
}
}, Blaze.View("lookup:miner.blocks", function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("miner"), "blocks"));
})), "\n", "", "\n", HTML.DIV({
"class": "small-title-miner"
}, Blaze.View("lookup:miner.miner", function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("miner"), "miner"));
})), "\n", HTML.getTag("minerblock")({
blocks: function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("Blockchain"), "miner", "blocks"));
}
}), "\n", HTML.Raw('<div class="clearfix"></div>')))), "\n", HTML.DIV({
"class": [ "col-xs-3", " ", "stat-holder" ]
}, HTML.DIV({
"class": [ "big-info", " ", "chart", " ", "text-info" ]
}, "", "\n", HTML.Raw('<span class="small-title">uncle count&nbsp;\n<span class="small">(25 blocks per bar)</span></span>'), "\n", "", "\n", HTML.getTag("sparkchart")({
"class": [ "big-details", " ", "spark-uncles" ],
data: function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("Blockchain"), "uncleCountChart", "join"));
}
}))), "\n", HTML.DIV({
"class": [ "col-xs-3", " ", "stat-holder" ]
}, HTML.DIV({
"class": [ "big-info", " ", "chart", " ", "text-info" ]
}, "", "\n", HTML.Raw('<span class="small-title">transactions</span>'), "\n", HTML.getTag("sparkchart")({
"class": [ "big-details", " ", "spark-transactions" ],
data: function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("Blockchain"), "transactionDensity"));
}
}))), "\n", HTML.DIV({
"class": [ "col-xs-3", " ", "stat-holder" ]
}, HTML.DIV({
"class": [ "big-info", " ", "chart", " ", "text-info" ]
}, "", "\n", HTML.Raw('<span class="small-title">gas spending</span>'), "\n", HTML.getTag("sparkchart")({
"class": [ "big-details", " ", "spark-gasspending" ],
data: function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("Blockchain"), "gasSpending", "join"));
}
}))))), "\n", HTML.DIV({
"class": [ "col-xs-4", " ", "stat-holder", " ", "map-holder" ]
}, "", "\n", HTML.getTag("nodemap")({
id: "mapHolder",
data: "map"
})), "\n", HTML.DIV({
"class": [ "col-xs-12", " ", "stats-boxes" ]
}, HTML.DIV({
"class": [ "row", " ", "second-row" ]
}, HTML.DIV({
"class": [ "col-xs-12", " ", "stat-holder", " ", "box" ]
}, HTML.DIV({
"class": [ "active-nodes", " ", "text-orange" ]
}, HTML.Raw('<i class="icon-hashrate"></i>'), "\n", HTML.Raw('<span class="small-title">Block #1028201 hash</span>'), "\n", HTML.SPAN({
"class": "small-value"
}, Blaze.View("lookup:Blockchain.frontierHash", function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("Blockchain"), "frontierHash"));
})))))), "\n", HTML.Raw('<div class="clearfix"></div>')), "\n", HTML.DIV({
"class": "row",
style: "padding-top: 10px"
}, HTML.TABLE({
"class": [ "table", " ", "table-striped" ]
}, HTML.THEAD(HTML.TR({
"class": "text-info"
}, HTML.TH({
"class": "th-nodecheck"
}, HTML.I({
"class": "icon-check-o",
"data-toggle": "tooltip",
"data-placement": "top",
title: "Pin nodes to display first",
"ng-click": "orderTable(['-stats.block.number', 'stats.block.propagation'], false)"
})), "\n", HTML.TH({
"class": "th-nodename"
}, HTML.I({
"class": "icon-node",
"data-toggle": "tooltip",
"data-placement": "top",
title: "Node name",
"ng-click": "orderTable(['info.name'], false)"
})), "\n", HTML.TH({
"class": "th-nodetype"
}, HTML.I({
"class": "icon-laptop",
"data-toggle": "tooltip",
"data-placement": "top",
title: "Node type",
"ng-click": "orderTable(['info.node'], false)"
})), "\n", HTML.TH({
"class": "th-latency"
}, HTML.I({
"class": "icon-clock",
"data-toggle": "tooltip",
"data-placement": "top",
title: "Node latency",
"ng-click": "orderTable(['stats.latency'], false)"
})), "\n", HTML.TH(HTML.I({
"class": "icon-mining",
"data-toggle": "tooltip",
"data-placement": "top",
title: "Is mining",
"ng-click": "orderTable(['-stats.hashrate'], false)"
})), "\n", HTML.TH(HTML.I({
"class": "icon-group",
"data-toggle": "tooltip",
"data-placement": "top",
title: "Peers",
"ng-click": "orderTable(['-stats.peers'], false)"
})), "\n", HTML.TH(HTML.I({
"class": "icon-network",
"data-toggle": "tooltip",
"data-placement": "top",
title: "Pending transactions",
"ng-click": "orderTable(['-stats.pending'], false)"
})), "\n", HTML.TH(HTML.I({
"class": "icon-block",
"data-toggle": "tooltip",
"data-placement": "top",
title: "Last block",
"ng-click": "orderTable(['-stats.block.number', 'stats.block.propagation'], false)"
})), "\n", HTML.TH({
"class": "th-blockhash"
}, HTML.CharRef({
html: "&nbsp;",
str: " "
})), "\n", HTML.TH({
"class": "th-blockhash"
}, HTML.I({
"class": "icon-difficulty",
"data-toggle": "tooltip",
"data-placement": "top",
title: "Total difficulty",
"ng-click": "orderTable(['-stats.block.totalDifficulty'], false)"
})), "\n", HTML.TH(HTML.I({
"class": "icon-check-o",
"data-toggle": "tooltip",
"data-placement": "top",
title: "Block transactions",
"ng-click": "orderTable(['-stats.block.transactions.length'], false)"
})), "\n", HTML.TH(HTML.I({
"class": "icon-uncle",
"data-toggle": "tooltip",
"data-placement": "top",
title: "Uncles",
"ng-click": "orderTable(['-stats.block.uncles.length'], false)"
})), "\n", HTML.TH({
"class": "th-blocktime"
}, HTML.I({
"class": "icon-time",
"data-toggle": "tooltip",
"data-placement": "top",
title: "Last block time",
"ng-click": "orderTable(['-stats.block.received'], false)"
})), "\n", HTML.TH({
"class": "th-peerPropagationTime"
}, HTML.I({
"class": "icon-gas",
"data-toggle": "tooltip",
"data-placement": "top",
title: "Propagation time",
"ng-click": "orderTable(['-stats.block.number', 'stats.block.propagation'], false)"
})), "\n", HTML.TH({
"class": "th-peerPropagationChart"
}), "\n", HTML.TH({
"class": "th-peerPropagationAvg"
}, HTML.I({
"class": "icon-gas",
"data-toggle": "tooltip",
"data-placement": "top",
title: "Average propagation time",
"ng-click": "orderTable(['stats.propagationAvg'], false)"
})), "\n", HTML.TH(HTML.I({
"class": "icon-bulb",
"data-toggle": "tooltip",
"data-placement": "top",
title: "Up-time",
"ng-click": "orderTable(['-stats.uptime'], false)"
})))), "\n", HTML.TBODY(Blaze.Each(function() {
return Spacebars.call(view.lookup("nodes"));
}, function() {
return HTML.TR({
"ng-repeat": "node in nodes | orderBy:predicate track by node.id",
"class": function() {
return Spacebars.mustache(view.lookup("mainClass"), view.lookup("stats"), Spacebars.dot(view.lookup("Blockchain"), "bestBlock"));
},
id: function() {
return [ "node_", Spacebars.mustache(view.lookup("id")) ];
}
}, HTML.TD({
"class": "td-nodecheck"
}, HTML.I({
"ng-click": "pinNode(id)",
"class": function() {
return Spacebars.mustache(view.lookup("nodePinClass"), view.lookup("pinned"));
},
"data-toggle": "tooltip",
"data-placement": "right",
"data-original-title": function() {
return [ "Click to ", Blaze.If(function() {
return Spacebars.call(view.lookup("pinned"));
}, function() {
return "'un'";
}, function() {
return "''";
}), "pin" ];
}
})), "\n", HTML.TD({
"class": "nodeInfo",
rel: function() {
return Spacebars.mustache(view.lookup("id"));
}
}, HTML.SPAN({
"class": "small",
"data-toggle": "tooltip",
"data-placement": "top",
"data-html": "true",
"data-original-title": function() {
return Spacebars.mustache(view.lookup("geoTooltip"), view.lookup("."));
}
}, Blaze.View("lookup:info.name", function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("info"), "name"));
})), "\n", HTML.SPAN({
"class": "small"
}, HTML.CharRef({
html: "&nbsp;",
str: " "
}), "(", Blaze.View("lookup:info.ip", function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("info"), "ip"));
}), ")"), "\n", HTML.A({
"class": function() {
return [ "small", " ", Spacebars.mustache(view.lookup("nodeClientClass"), view.lookup("info"), Spacebars.dot(view.lookup("Blockchain"), "currentApiVersion")) ];
},
href: "https://github.com/ethereum/wiki/wiki/Network-Status#updating",
target: "_blank",
"data-toggle": "tooltip",
"data-placement": "top",
"data-html": "true",
"data-original-title": "Netstats client needs update.<br>Click this icon for instructions."
}, HTML.I({
"class": "icon-warning-o"
}))), "\n", HTML.TD(HTML.DIV({
"class": "small"
}, Blaze.View("lookup:nodeVersion", function() {
return Spacebars.mustache(view.lookup("nodeVersion"), Spacebars.dot(view.lookup("info"), "node"));
}))), "\n", HTML.TD({
"class": function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("readable"), "latencyClass"));
}
}, HTML.SPAN({
"class": "small"
}, Blaze.View("lookup:readable.latency", function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("readable"), "latency"));
}))), "\n", HTML.TD({
"class": function() {
return Spacebars.mustache(view.lookup("hashrateClass"), Spacebars.dot(view.lookup("stats"), "mining"), Spacebars.dot(view.lookup("stats"), "active"));
}
}, Blaze.View("lookup:hashrateFilter", function() {
return Spacebars.mustache(view.lookup("hashrateFilter"), Spacebars.dot(view.lookup("stats"), "hashrate"), Spacebars.dot(view.lookup("stats"), "mining"));
})), "\n", HTML.TD({
"class": function() {
return Spacebars.mustache(view.lookup("peerClass"), Spacebars.dot(view.lookup("stats"), "peers"), Spacebars.dot(view.lookup("stats"), "active"));
},
style: "padding-left: 11px;"
}, Blaze.View("lookup:stats.peers", function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("stats"), "peers"));
})), "\n", HTML.TD({
style: "padding-left: 15px;"
}, Blaze.View("lookup:stats.pending", function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("stats"), "pending"));
})), "\n", HTML.TD({
"class": function() {
return Spacebars.mustache(view.lookup("blockClass"), view.lookup("stats"), Spacebars.dot(view.lookup("Blockchain"), "bestBlock"));
}
}, HTML.SPAN({
"class": function() {
return Blaze.If(function() {
return Spacebars.call(Spacebars.dot(view.lookup("readable"), "forkMessage"));
}, function() {
return [ " ", Blaze.View("lookup:readable.forkClass", function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("readable"), "forkClass"));
}), " " ];
}, function() {
return " '' ";
});
}
}, Blaze.View("lookup:number", function() {
return Spacebars.mustache(view.lookup("number"), Spacebars.dot(view.lookup("stats"), "block", "number"));
})), "\n", null), "\n", HTML.TD({
"class": function() {
return Spacebars.mustache(view.lookup("blockClass"), view.lookup("stats"), Spacebars.dot(view.lookup("Blockchain"), "bestBlock"));
}
}, HTML.SPAN({
"class": "small"
}, Blaze.View("lookup:hashFilter", function() {
return Spacebars.mustache(view.lookup("hashFilter"), Spacebars.dot(view.lookup("stats"), "block", "hash"));
}))), "\n", HTML.TD({
"class": function() {
return Spacebars.mustache(view.lookup("blockClass"), view.lookup("stats"), Spacebars.dot(view.lookup("Blockchain"), "bestBlock"));
}
}, HTML.SPAN({
"class": "small"
}, Blaze.View("lookup:number", function() {
return Spacebars.mustache(view.lookup("number"), Spacebars.dot(view.lookup("stats"), "block", "totalDifficulty"));
}))), "\n", HTML.TD({
style: "padding-left: 14px;"
}, Blaze.View("lookup:stats.block.transactions.length", function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("stats"), "block", "transactions", "length"));
})), "\n", HTML.TD({
style: "padding-left: 14px;"
}, Blaze.View("lookup:stats.block.uncles.length", function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("stats"), "block", "uncles", "length"));
})), "\n", HTML.TD({
"class": function() {
return Spacebars.mustache(view.lookup("timeClass"), Spacebars.dot(view.lookup("stats"), "block", "received"), Spacebars.dot(view.lookup("stats"), "active"));
}
}, Blaze.View("lookup:blockTimeFilter", function() {
return Spacebars.mustache(view.lookup("blockTimeFilter"), Spacebars.dot(view.lookup("stats"), "block", "received"));
})), "\n", HTML.TD({
"class": function() {
return Spacebars.mustache(view.lookup("propagationTimeClass"), view.lookup("stats"), Spacebars.dot(view.lookup("Blockchain"), "bestBlock"));
}
}, HTML.DIV({
"class": "propagationBox"
}), "\n", HTML.SPAN(Blaze.View("lookup:blockPropagationFilter", function() {
return Spacebars.mustache(view.lookup("blockPropagationFilter"), Spacebars.dot(view.lookup("stats"), "block", "propagation"), false);
}))), "\n", HTML.TD({
"class": function() {
return [ "peerPropagationChart", " ", Spacebars.mustache(view.lookup("id")) ];
}
}), "\n", HTML.TD({
"class": function() {
return Spacebars.mustache(view.lookup("propagationNodeAvgTimeClass"), view.lookup("stats"), Spacebars.dot(view.lookup("Blockchain"), "bestBlock"));
}
}, Blaze.View("lookup:blockPropagationAvgFilter", function() {
return Spacebars.mustache(view.lookup("blockPropagationAvgFilter"), view.lookup("stats"), Spacebars.dot(view.lookup("Blockchain"), "bestBlock"));
})), "\n", HTML.TD({
"class": function() {
return Spacebars.mustache(view.lookup("upTimeClass"), Spacebars.dot(view.lookup("stats"), "uptime"), Spacebars.dot(view.lookup("stats"), "active"));
}
}, Blaze.View("lookup:upTimeFilter", function() {
return Spacebars.mustache(view.lookup("upTimeFilter"), Spacebars.dot(view.lookup("stats"), "uptime"));
})));
})))));
}));
})();

View File

@@ -0,0 +1,331 @@
(function(){
/**
Update the spark chart
@method sparkChart
@param {String} property the property name with the chart data
@param {String} className the class name of the sparkchart element
*/
var sparkChart = function(template, property, className){
var fields = {};
fields[property] = 1;
var meta = Blockchain.findOne('meta', fields);
var element = template.$('sparkchart.'+ className);
element.html(meta[property].join(','));
element.addClass("big-details");
element.sparkline('html', {
type: 'bar',
tooltipSuffix: (element.attr('tooltipsuffix') || '')
});
};
Template['indexMeteor'].onRendered(function(){
var template = this;
// map
this.autorun(function(){
var data = Map.find({}).fetch();
var element = template.$('#mapHolder');
var scope = {};
if(data.length === 0)
return;
var bubbleConfig = {
borderWidth: 0,
highlightOnHover: false,
popupOnHover: true,
popupTemplate: function(geo, data) {
return ['<div class="tooltip-arrow"></div>',
'<div class="hoverinfo ' + data.fillClass + '">',
'<div class="propagationBox"></div>',
'<strong>',
data.nodeName,
'</strong>',
'</div>'].join('');
}
};
element.empty();
var width = 628,
height = 244;
var map = new Datamap({
element: element[0],
scope: 'world',
width: width,
height: 300,
fills: {
success: '#7BCC3A',
info: '#10A0DE',
warning: '#FFD162',
orange: '#FF8A00',
danger: '#F74B4B',
defaultFill: '#282828'
},
geographyConfig: {
borderWidth: 0,
borderColor: '#000',
highlightOnHover: false,
popupOnHover: false
},
bubblesConfig: {
borderWidth: 0,
highlightOnHover: false,
popupOnHover: true
},
done: function(datamap) {
var ev;
var zoomListener = d3.behavior.zoom()
.size([width, height])
.scaleExtent([1, 3])
.on("zoom", redraw)
.on("zoomend", animadraw);
function redraw() {
datamap.svg.select(".datamaps-subunits").attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
datamap.svg.select(".bubbles").selectAll("circle")
.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")")
.attr("r", 3/d3.event.scale);
ev = d3.event;
}
zoomListener(datamap.svg);
function animadraw() {
var x = Math.min(0, Math.max(ev.translate[0], (-1) * width * (ev.scale-1)));
var y = Math.min(0, Math.max(ev.translate[1], (-1) * height * (ev.scale-1)));
datamap.svg.select(".datamaps-subunits")
.transition()
.delay(150)
.duration(750)
.attr("transform", "translate(" + x + "," + y + ")scale(" + ev.scale + ")");
datamap.svg.select(".bubbles").selectAll("circle")
.transition()
.delay(150)
.duration(750)
.attr("transform", "translate(" + x + "," + y + ")scale(" + ev.scale + ")")
.attr("r", 3/ev.scale);
zoomListener.translate([x,y]);
}
}
});
map.bubbles(data, bubbleConfig);
});
// block propagation times chart
this.autorun(function(){
var element = template.$('histogram.d3-blockpropagation');
var margin = {top: 0, right: 0, bottom: 0, left: 0};
var width = 280 - margin.left - margin.right,
height = 63 - margin.top - margin.bottom;
var TICKS = 40;
var x = d3.scale.linear()
.domain([0, 10000])
.rangeRound([0, width])
.interpolate(d3.interpolateRound);
var y = d3.scale.linear()
.range([height, 0])
.interpolate(d3.interpolateRound);
var color = d3.scale.linear()
.domain([1000, 3000, 7000, 10000])
.range(["#7bcc3a", "#FFD162", "#ff8a00", "#F74B4B"]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(4, ",.1s")
.tickFormat(function(t){ return t/1000 + "s"});
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(3)
.tickFormat(d3.format("%"));
var line = d3.svg.line()
.x(function(d) { return x(d.x + d.dx/2) - 1; })
.y(function(d) { return y(d.y) - 2; })
.interpolate('basis');
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([10, 0])
.direction('s')
.html(function(d) {
return '<div class="tooltip-arrow"></div><div class="tooltip-inner"><b>' + (d.x/1000) + 's - ' + ((d.x + d.dx)/1000) + 's</b><div class="small">Percent: <b>' + Math.round(d.y * 100) + '%</b>' + '<br>Frequency: <b>' + d.frequency + '</b><br>Cumulative: <b>' + Math.round(d.cumpercent*100) + '%</b></div></div>';
})
var data = Blockchain.findOne('meta', {fields: {blockPropagationChart: 1}}).blockPropagationChart;
if(data.length === 0)
return;
// Adjust y axis
y.domain([0, d3.max(data, function(d) { return d.y; })]);
// Delete previous histogram
element.empty();
/* Start drawing */
var svg = d3.select(".d3-blockpropagation").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.call(tip);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.attr("y", 6);
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + width + ", 0)")
.call(yAxis);
var bar = svg.append("g")
.attr("class", "bars")
.selectAll("g")
.data(data)
.enter().append("g")
.attr("transform", function(d) { return "translate(" + x(d.x) + ",0)"; })
.on('mouseover', function(d) { tip.show(d, d3.select(this).select('.bar').node()); })
.on('mouseout', tip.hide);
bar.insert("rect")
.attr("class", "handle")
.attr("y", 0)
.attr("width", x(data[0].dx + data[0].x) - x(data[0].x))
.attr("height", function(d) { return height; });
bar.insert("rect")
.attr("class", "bar")
.attr("y", function(d) { return y(d.y); })
.attr("rx", 1)
.attr("ry", 1)
.attr("fill", function(d) { return color(d.x); })
.attr("width", x(data[0].dx + data[0].x) - x(data[0].x) - 1)
.attr("height", function(d) { return height - y(d.y) + 1; });
bar.insert("rect")
.attr("class", "highlight")
.attr("y", function(d) { return y(d.y); })
.attr("fill", function(d) { return d3.rgb(color(d.x)).brighter(.7).toString(); })
.attr("rx", 1)
.attr("ry", 1)
.attr("width", x(data[0].dx + data[0].x) - x(data[0].x) - 1)
.attr("height", function(d) { return height - y(d.y) + 1; });
svg.append("path")
.attr("class", "line")
.attr("d", line(data));
});
// blocktimes chart
this.autorun(function(){
sparkChart(template, 'lastBlocksTime', 'spark-blocktimes');
});
// difficulty chart
this.autorun(function(){
sparkChart(template, 'difficultyChart', 'spark-difficulty');
});
// uncles chart
this.autorun(function(){
sparkChart(template, 'uncleCountChart', 'spark-uncles');
});
// transactions chart
this.autorun(function(){
sparkChart(template, 'transactionDensity', 'spark-transactions');
});
// gasspending chart
this.autorun(function(){
sparkChart(template, 'gasSpending', 'spark-gasspending');
});
});
Template['indexMeteor'].helpers({
'Blockchain': function(){
return Blockchain.findOne('meta');
},
'nodes': function(uptime) {
return Nodes.find({stats: {$exists: true}},{limit: 10, sort: {'stats.block.number': -1, 'info.name': 1, 'stats.active': -1}});
},
'blockTimeFilter': function() {
var timestamp = this.lastBlock;
if(timestamp === 0)
return '∞';
// var time = Math.floor((new Date()).getTime() / 1000);
var time = (new Date()).getTime();
var diff = Math.floor((time - timestamp)/1000);
if(diff < 60)
return Math.round(diff) + ' s ago';
return moment.duration(Math.round(diff), 's').humanize() + ' ago';
},
'avgTimeFilter': function() {
var time = this.avgBlockTime;
if(time < 60)
return parseFloat(time).toFixed(2) + ' s';
return moment.duration(Math.round(time), 's').humanize();
},
'minerBlocks': function(){
var array = [];
for (var i = 1; i <= this.blocks; i++) {
array.push('');
};
return array;
},
'minerBlockClass': function (value) {
if(value <= 6)
return 'success';
if(value <= 12)
return 'info';
if(value <= 18)
return 'warning';
if(value <= 24)
return 'orange';
return 'danger';
}
});
})();

View File

@@ -0,0 +1,603 @@
(function(){
Template.__checkName("indexMeteor");
Template["indexMeteor"] = new Template("Template.indexMeteor", (function() {
var view = this;
return [ Spacebars.With(function() {
return Spacebars.call(view.lookup("Blockchain"));
}, function() {
return [ "\n ", HTML.DIV({
"class": "container-fluid"
}, "\n ", HTML.DIV({
"class": "row"
}, "\n ", HTML.DIV({
"class": "col-xs-2 stat-holder"
}, "\n ", HTML.DIV({
"class": "big-info bestblock text-info"
}, "\n ", HTML.DIV({
"class": "pull-left icon-full-width"
}, HTML.I({
"class": "icon-block"
})), "\n ", HTML.DIV({
"class": "big-details-holder"
}, HTML.SPAN({
"class": "small-title"
}, "best block"), HTML.SPAN({
"class": "big-details"
}, Blaze.View("lookup:number", function() {
return Spacebars.mustache(view.lookup("number"), view.lookup("bestBlock"));
}))), "\n ", HTML.DIV({
"class": "clearfix"
}), "\n "), "\n "), "\n ", HTML.DIV({
"class": "col-xs-2 stat-holder"
}, "\n ", HTML.DIV({
"class": "big-info uncleCount text-info"
}, "\n ", HTML.DIV({
"class": "pull-left icon-full-width"
}, HTML.I({
"class": "icon-uncle"
})), "\n ", HTML.DIV({
"class": "big-details-holder"
}, HTML.SPAN({
"class": "small-title"
}, "uncles", HTML.CharRef({
html: "&nbsp;",
str: " "
}), HTML.SPAN({
"class": "small"
}, "(current / last 50)")), HTML.SPAN({
"class": "big-details"
}, Blaze.View("lookup:bestStats.block.uncles.length", function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("bestStats"), "block", "uncles", "length"));
}), "/", Blaze.View("lookup:uncleCount", function() {
return Spacebars.mustache(view.lookup("uncleCount"));
}))), "\n ", HTML.DIV({
"class": "clearfix"
}), "\n "), "\n "), "\n ", HTML.DIV({
"class": "col-xs-2 stat-holder"
}, "\n ", HTML.DIV({
"class": function() {
return [ "big-info blocktime ", Spacebars.mustache(view.lookup("timeClass"), view.lookup("lastBlock"), true) ];
}
}, "\n ", HTML.DIV({
"class": "pull-left icon-full-width"
}, HTML.I({
"class": "icon-time"
})), "\n ", HTML.DIV({
"class": "big-details-holder"
}, HTML.SPAN({
"class": "small-title"
}, "last block"), HTML.SPAN({
"class": "big-details"
}, Blaze.View("lookup:blockTimeFilter", function() {
return Spacebars.mustache(view.lookup("blockTimeFilter"));
})), "\n "), "\n ", HTML.DIV({
"class": "clearfix"
}), "\n "), "\n "), "\n ", HTML.DIV({
"class": "col-xs-2 stat-holder"
}, "\n ", HTML.DIV({
"class": function() {
return [ "big-info avgblocktime ", Spacebars.mustache(view.lookup("avgTimeClass"), view.lookup("avgBlockTime")) ];
}
}, "\n ", HTML.DIV({
"class": "pull-left icon-full-width"
}, HTML.I({
"class": "icon-gas"
})), "\n ", HTML.DIV({
"class": "big-details-holder"
}, HTML.SPAN({
"class": "small-title"
}, "avg block time"), HTML.SPAN({
"class": "big-details"
}, Blaze.View("lookup:avgTimeFilter", function() {
return Spacebars.mustache(view.lookup("avgTimeFilter"));
}))), "\n ", HTML.DIV({
"class": "clearfix"
}), "\n "), "\n "), "\n ", HTML.DIV({
"class": "col-xs-2 stat-holder"
}, "\n ", HTML.DIV({
"class": "big-info difficulty text-orange"
}, "\n ", HTML.DIV({
"class": "pull-left icon-full-width"
}, HTML.I({
"class": "icon-hashrate"
})), "\n ", HTML.DIV({
"class": "big-details-holder"
}, HTML.SPAN({
"class": "small-title"
}, "avg network hashrate"), HTML.SPAN({
"class": "big-details"
}, Blaze.View("lookup:networkHashrateFilter", function() {
return Spacebars.mustache(view.lookup("networkHashrateFilter"), view.lookup("avgHashrate"), false);
}))), "\n ", HTML.DIV({
"class": "clearfix"
}), "\n "), "\n "), "\n ", HTML.DIV({
"class": "col-xs-2 stat-holder"
}, "\n ", HTML.DIV({
"class": "big-info difficulty text-danger"
}, "\n ", HTML.DIV({
"class": "pull-left icon-full-width"
}, HTML.I({
"class": "icon-difficulty"
})), "\n ", HTML.DIV({
"class": "big-details-holder"
}, HTML.SPAN({
"class": "small-title"
}, "difficulty"), HTML.SPAN({
"class": "big-details"
}, HTML.SPAN({
"class": "small-hash"
}, Blaze.View("lookup:number", function() {
return Spacebars.mustache(view.lookup("number"), view.lookup("lastDifficulty"));
})))), "\n ", HTML.DIV({
"class": "clearfix"
}), "\n "), "\n "), "\n\n ", HTML.DIV({
"class": "clearfix"
}), "\n "), "\n\n ", HTML.DIV({
"class": "row"
}, "\n ", HTML.DIV({
style: "padding-top: 0px;",
"class": "col-xs-8 stats-boxes"
}, "\n ", HTML.DIV({
"class": "row second-row"
}, "\n ", HTML.DIV({
"class": "col-xs-3 stat-holder box"
}, "\n ", HTML.DIV({
"class": function() {
return [ "active-nodes ", Spacebars.mustache(view.lookup("nodesActiveClass"), view.lookup("nodesActive"), view.lookup("nodesTotal")) ];
}
}, HTML.I({
"class": "icon-node"
}), HTML.SPAN({
"class": "small-title"
}, "active nodes"), HTML.SPAN({
"class": "small-value"
}, Blaze.View("lookup:nodesActive", function() {
return Spacebars.mustache(view.lookup("nodesActive"));
}), "/", Blaze.View("lookup:nodesTotal", function() {
return Spacebars.mustache(view.lookup("nodesTotal"));
}))), "\n "), "\n ", HTML.DIV({
"class": "col-xs-3 stat-holder box"
}, "\n ", HTML.DIV({
"class": "gasprice text-info"
}, HTML.I({
"class": "icon-gasprice"
}), HTML.SPAN({
"class": "small-title"
}, "gas price"), HTML.SPAN({
"class": "small-value"
}, Blaze.View("lookup:gasPriceFilter", function() {
return Spacebars.mustache(view.lookup("gasPriceFilter"), Spacebars.dot(view.lookup("bestStats"), "gasPrice", "toString"));
}))), "\n "), "\n ", HTML.DIV({
"class": "col-xs-3 stat-holder box"
}, "\n ", HTML.DIV({
"class": function() {
return [ "page-latency ", Spacebars.mustache(view.lookup("latencyClass"), true, view.lookup("latency")) ];
}
}, HTML.I({
"class": "icon-clock"
}), HTML.SPAN({
"class": "small-title"
}, "page latency"), HTML.SPAN({
"class": "small-value"
}, Blaze.View("lookup:latency", function() {
return Spacebars.mustache(view.lookup("latency"));
}), " ms")), "\n "), "\n ", HTML.DIV({
"class": "col-xs-3 stat-holder box"
}, "\n ", HTML.DIV({
"class": function() {
return [ "uptime ", Spacebars.mustache(view.lookup("upTimeClass"), view.lookup("upTimeTotal"), true) ];
}
}, HTML.I({
"class": "icon-bulb"
}), HTML.SPAN({
"class": "small-title"
}, "uptime"), HTML.SPAN({
"class": "small-value"
}, Blaze.View("lookup:upTimeFilter", function() {
return Spacebars.mustache(view.lookup("upTimeFilter"), view.lookup("upTimeTotal"));
}))), "\n "), "\n "), "\n ", HTML.DIV({
"class": "row"
}, "\n ", HTML.DIV({
"class": "col-xs-3 stat-holder"
}, "\n ", HTML.DIV({
"class": function() {
return [ "big-info chart ", Spacebars.mustache(view.lookup("avgTimeClass"), view.lookup("avgBlockTime")) ];
}
}, HTML.SPAN({
"class": "small-title"
}, "block time"), "\n ", HTML.getTag("sparkchart")({
tooltipsuffix: "s",
"class": "big-details spark-blocktimes"
}), "\n "), "\n "), "\n ", HTML.DIV({
"class": "col-xs-3 stat-holder"
}, "\n ", HTML.DIV({
"class": "big-info chart text-info"
}, HTML.SPAN({
"class": "small-title"
}, "difficulty"), "\n ", HTML.getTag("sparkchart")({
"class": "big-details spark-difficulty"
}), "\n "), "\n "), "\n ", HTML.DIV({
"class": "col-xs-3 stat-holder xpull-right"
}, "\n ", HTML.DIV({
"class": function() {
return [ "big-info chart xdouble-chart ", Spacebars.mustache(view.lookup("propagationAvgTimeClass"), view.lookup("blockPropagationAvg"), true) ];
}
}, HTML.SPAN({
"class": "small-title"
}, "block propagation"), "\n ", HTML.getTag("histogram")({
"class": "big-details d3-blockpropagation"
}), "\n "), "\n "), "\n ", HTML.DIV({
"class": "col-xs-3 stat-holder pull-right"
}, "\n ", HTML.DIV({
"class": "big-info chart double-chart"
}, HTML.SPAN({
"class": "small-title"
}, "last blocks miners"), "\n ", HTML.DIV({
"data-toggle": "tooltip",
"data-placement": "right",
"data-original-title": function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("miner"), "blocks"));
},
"class": "blocks-holder"
}, "\n ", Blaze.Each(function() {
return Spacebars.call(view.lookup("miners"));
}, function() {
return [ "\n ", HTML.DIV({
"class": function() {
return [ "block-count ", Spacebars.mustache(view.lookup("minerBlocksClass"), view.lookup("blocks"), "text-") ];
}
}, Blaze.View("lookup:blocks", function() {
return Spacebars.mustache(view.lookup("blocks"));
})), "\n ", HTML.DIV({
"class": "small-title-miner"
}, Blaze.View("lookup:miner", function() {
return Spacebars.mustache(view.lookup("miner"));
})), "\n \n ", HTML.Comment(' <div class="block {{minerBlockClass ../blocks}}"></div> '), "\n \n ", HTML.DIV({
"class": "clearfix"
}), "\n " ];
}), "\n "), "\n "), "\n "), "\n ", HTML.DIV({
"class": "col-xs-3 stat-holder"
}, "\n ", HTML.DIV({
"class": "big-info chart text-info"
}, HTML.SPAN({
"class": "small-title"
}, "uncle count", HTML.CharRef({
html: "&nbsp;",
str: " "
}), HTML.SPAN({
"class": "small"
}, "(25 blocks per bar)")), "\n ", HTML.getTag("sparkchart")({
"class": "big-details spark-uncles"
}), "\n "), "\n "), "\n ", HTML.DIV({
"class": "col-xs-3 stat-holder"
}, "\n ", HTML.DIV({
"class": "big-info chart text-info"
}, HTML.SPAN({
"class": "small-title"
}, "transactions"), "\n ", HTML.getTag("sparkchart")({
"class": "big-details spark-transactions"
}), "\n "), "\n "), "\n ", HTML.DIV({
"class": "col-xs-3 stat-holder"
}, "\n ", HTML.DIV({
"class": "big-info chart text-info"
}, HTML.SPAN({
"class": "small-title"
}, "gas spending"), "\n ", HTML.getTag("sparkchart")({
"class": "big-details spark-gasspending"
}), "\n "), "\n "), "\n "), "\n "), "\n ", HTML.DIV({
"class": "col-xs-4 stat-holder map-holder"
}, "\n ", HTML.getTag("nodemap")({
id: "mapHolder"
}), "\n "), "\n\n ", HTML.DIV({
"class": "col-xs-12 stats-boxes"
}, "\n ", HTML.DIV({
"class": "row second-row"
}, "\n ", HTML.DIV({
"class": "col-xs-12 stat-holder box"
}, "\n ", HTML.DIV({
"class": "active-nodes text-orange"
}, HTML.I({
"class": "icon-hashrate"
}), HTML.SPAN({
"class": "small-title"
}, "Block #1028201 hash"), HTML.SPAN({
"class": "small-value"
}, Blaze.View("lookup:frontierHash", function() {
return Spacebars.mustache(view.lookup("frontierHash"));
}))), "\n "), "\n "), "\n "), "\n\n ", HTML.DIV({
"class": "clearfix"
}), "\n "), "\n "), "\n " ];
}), "\n\n ", HTML.DIV({
style: "padding-top: 10px",
"class": "row"
}, "\n ", HTML.TABLE({
"class": "table table-striped"
}, "\n ", HTML.THEAD("\n ", HTML.TR({
"class": "text-info"
}, "\n ", HTML.TH({
"class": "th-nodecheck"
}, HTML.I({
"data-toggle": "tooltip",
"data-placement": "top",
title: "Pin nodes to display first",
"ng-click": "orderTable(['-stats.block.number', 'stats.block.propagation'], false)",
"class": "icon-check-o"
})), "\n ", HTML.TH({
"class": "th-nodename"
}, HTML.I({
"data-toggle": "tooltip",
"data-placement": "top",
title: "Node name",
"ng-click": "orderTable(['info.name'], false)",
"class": "icon-node"
})), "\n ", HTML.TH({
"class": "th-nodetype"
}, HTML.I({
"data-toggle": "tooltip",
"data-placement": "top",
title: "Node type",
"ng-click": "orderTable(['info.node'], false)",
"class": "icon-laptop"
})), "\n ", HTML.TH({
"class": "th-latency"
}, HTML.I({
"data-toggle": "tooltip",
"data-placement": "top",
title: "Node latency",
"ng-click": "orderTable(['stats.latency'], false)",
"class": "icon-clock"
})), "\n ", HTML.TH(HTML.I({
"data-toggle": "tooltip",
"data-placement": "top",
title: "Is mining",
"ng-click": "orderTable(['-stats.hashrate'], false)",
"class": "icon-mining"
})), "\n ", HTML.TH(HTML.I({
"data-toggle": "tooltip",
"data-placement": "top",
title: "Peers",
"ng-click": "orderTable(['-stats.peers'], false)",
"class": "icon-group"
})), "\n ", HTML.TH(HTML.I({
"data-toggle": "tooltip",
"data-placement": "top",
title: "Pending transactions",
"ng-click": "orderTable(['-stats.pending'], false)",
"class": "icon-network"
})), "\n ", HTML.TH(HTML.I({
"data-toggle": "tooltip",
"data-placement": "top",
title: "Last block",
"ng-click": "orderTable(['-stats.block.number', 'stats.block.propagation'], false)",
"class": "icon-block"
})), "\n ", HTML.TH({
"class": "th-blockhash"
}, HTML.CharRef({
html: "&nbsp;",
str: " "
})), "\n ", HTML.TH({
"class": "th-blockhash"
}, HTML.I({
"data-toggle": "tooltip",
"data-placement": "top",
title: "Total difficulty",
"ng-click": "orderTable(['-stats.block.totalDifficulty'], false)",
"class": "icon-difficulty"
})), "\n ", HTML.TH(HTML.I({
"data-toggle": "tooltip",
"data-placement": "top",
title: "Block transactions",
"ng-click": "orderTable(['-stats.block.transactions.length'], false)",
"class": "icon-check-o"
})), "\n ", HTML.TH(HTML.I({
"data-toggle": "tooltip",
"data-placement": "top",
title: "Uncles",
"ng-click": "orderTable(['-stats.block.uncles.length'], false)",
"class": "icon-uncle"
})), "\n ", HTML.TH({
"class": "th-blocktime"
}, HTML.I({
"data-toggle": "tooltip",
"data-placement": "top",
title: "Last block time",
"ng-click": "orderTable(['-stats.block.received'], false)",
"class": "icon-time"
})), "\n ", HTML.TH({
"class": "th-peerPropagationTime"
}, HTML.I({
"data-toggle": "tooltip",
"data-placement": "top",
title: "Propagation time",
"ng-click": "orderTable(['-stats.block.number', 'stats.block.propagation'], false)",
"class": "icon-gas"
})), "\n ", HTML.TH({
"class": "th-peerPropagationChart"
}), "\n ", HTML.TH({
"class": "th-peerPropagationAvg"
}, HTML.I({
"data-toggle": "tooltip",
"data-placement": "top",
title: "Average propagation time",
"ng-click": "orderTable(['stats.propagationAvg'], false)",
"class": "icon-gas"
})), "\n ", HTML.TH(HTML.I({
"data-toggle": "tooltip",
"data-placement": "top",
title: "Up-time",
"ng-click": "orderTable(['-stats.uptime'], false)",
"class": "icon-bulb"
})), "\n "), "\n "), "\n ", HTML.TBODY("\n ", Blaze.Each(function() {
return Spacebars.call(view.lookup("nodes"));
}, function() {
return [ "\n ", HTML.TR({
"class": function() {
return Spacebars.mustache(view.lookup("mainClass"), view.lookup("stats"), Spacebars.dot(view.lookup("Blockchain"), "bestBlock"));
},
id: function() {
return [ "node_", Spacebars.mustache(view.lookup("id")) ];
}
}, "\n ", HTML.TD({
"class": "td-nodecheck"
}, HTML.I({
"ng-click": "pinNode(id)",
"data-toggle": "tooltip",
"data-placement": "right",
"data-original-title": function() {
return [ "Click to ", Blaze.If(function() {
return Spacebars.call(view.lookup("pinned"));
}, function() {
return "'un'";
}, function() {
return "''";
}), "pin" ];
},
"class": function() {
return Spacebars.mustache(view.lookup("nodePinClass"), view.lookup("pinned"));
}
})), "\n ", HTML.TD({
rel: function() {
return Spacebars.mustache(view.lookup("id"));
},
"class": "nodeInfo"
}, HTML.SPAN({
"data-toggle": "tooltip",
"data-placement": "top",
"data-html": "true",
"data-original-title": function() {
return Spacebars.mustache(view.lookup("geoTooltip"), view.lookup("."));
},
"class": "small"
}, Blaze.View("lookup:info.name", function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("info"), "name"));
})), HTML.SPAN({
"class": "small"
}, HTML.CharRef({
html: "&nbsp;",
str: " "
}), "(", Blaze.View("lookup:info.ip", function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("info"), "ip"));
}), ")"), HTML.A({
href: "https://github.com/ethereum/wiki/wiki/Network-Status#updating",
target: "_blank",
"data-toggle": "tooltip",
"data-placement": "top",
"data-html": "true",
"data-original-title": [ "Netstats client needs update.", HTML.CharRef({
html: "&lt;",
str: "<"
}), "br", HTML.CharRef({
html: "&gt;",
str: ">"
}), "Click this icon for instructions." ],
"class": function() {
return [ "small ", Spacebars.mustache(view.lookup("nodeClientClass"), view.lookup("info"), Spacebars.dot(view.lookup("Blockchain"), "currentApiVersion")) ];
}
}, HTML.I({
"class": "icon-warning-o"
}))), "\n ", HTML.TD("\n ", HTML.DIV({
"class": "small"
}, Blaze.View("lookup:nodeVersion", function() {
return Spacebars.mustache(view.lookup("nodeVersion"), Spacebars.dot(view.lookup("info"), "node"));
})), "\n "), "\n ", HTML.TD({
"class": function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("readable"), "latencyClass"));
}
}, HTML.SPAN({
"class": "small"
}, Blaze.View("lookup:readable.latency", function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("readable"), "latency"));
}))), "\n ", HTML.TD({
"class": function() {
return Spacebars.mustache(view.lookup("hashrateClass"), Spacebars.dot(view.lookup("stats"), "mining"), Spacebars.dot(view.lookup("stats"), "active"));
}
}, Blaze.View("lookup:hashrateFilter", function() {
return Spacebars.mustache(view.lookup("hashrateFilter"), Spacebars.dot(view.lookup("stats"), "hashrate"), Spacebars.dot(view.lookup("stats"), "mining"));
})), "\n ", HTML.TD({
style: "padding-left: 11px;",
"class": function() {
return Spacebars.mustache(view.lookup("peerClass"), Spacebars.dot(view.lookup("stats"), "peers"), Spacebars.dot(view.lookup("stats"), "active"));
}
}, Blaze.View("lookup:stats.peers", function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("stats"), "peers"));
})), "\n ", HTML.TD({
style: "padding-left: 15px;"
}, Blaze.View("lookup:stats.pending", function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("stats"), "pending"));
})), "\n ", HTML.TD({
"class": function() {
return Spacebars.mustache(view.lookup("blockClass"), view.lookup("stats"), Spacebars.dot(view.lookup("Blockchain"), "bestBlock"));
}
}, HTML.SPAN({
"class": function() {
return Blaze.If(function() {
return Spacebars.call(Spacebars.dot(view.lookup("readable"), "forkMessage"));
}, function() {
return [ " ", Blaze.View("lookup:readable.forkClass", function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("readable"), "forkClass"));
}), " " ];
}, function() {
return " '' ";
});
}
}, Blaze.View("lookup:number", function() {
return Spacebars.mustache(view.lookup("number"), Spacebars.dot(view.lookup("stats"), "block", "number"));
})), "\n "), "\n ", HTML.TD({
"class": function() {
return Spacebars.mustache(view.lookup("blockClass"), view.lookup("stats"), Spacebars.dot(view.lookup("Blockchain"), "bestBlock"));
}
}, HTML.SPAN({
"class": "small"
}, Blaze.View("lookup:hashFilter", function() {
return Spacebars.mustache(view.lookup("hashFilter"), Spacebars.dot(view.lookup("stats"), "block", "hash"));
}))), "\n ", HTML.TD({
"class": function() {
return Spacebars.mustache(view.lookup("blockClass"), view.lookup("stats"), Spacebars.dot(view.lookup("Blockchain"), "bestBlock"));
}
}, HTML.SPAN({
"class": "small"
}, Blaze.View("lookup:number", function() {
return Spacebars.mustache(view.lookup("number"), Spacebars.dot(view.lookup("stats"), "block", "totalDifficulty"));
}))), "\n ", HTML.TD({
style: "padding-left: 14px;"
}, Blaze.View("lookup:stats.block.transactions.length", function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("stats"), "block", "transactions", "length"));
})), "\n ", HTML.TD({
style: "padding-left: 14px;"
}, Blaze.View("lookup:stats.block.uncles.length", function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("stats"), "block", "uncles", "length"));
})), "\n ", HTML.TD({
"class": function() {
return Spacebars.mustache(view.lookup("timeClass"), Spacebars.dot(view.lookup("stats"), "block", "received"), Spacebars.dot(view.lookup("stats"), "active"));
}
}, Blaze.View("lookup:blockTimeFilter", function() {
return Spacebars.mustache(view.lookup("blockTimeFilter"), Spacebars.dot(view.lookup("stats"), "block", "received"));
})), "\n ", HTML.TD({
"class": function() {
return Spacebars.mustache(view.lookup("propagationTimeClass"), view.lookup("stats"), Spacebars.dot(view.lookup("Blockchain"), "bestBlock"));
}
}, "\n ", HTML.DIV({
"class": "propagationBox"
}), HTML.SPAN(Blaze.View("lookup:blockPropagationFilter", function() {
return Spacebars.mustache(view.lookup("blockPropagationFilter"), Spacebars.dot(view.lookup("stats"), "block", "propagation"), false);
})), "\n "), "\n ", HTML.TD({
"class": function() {
return [ "peerPropagationChart ", Spacebars.mustache(view.lookup("id")) ];
}
}, "\n "), "\n ", HTML.TD({
"class": function() {
return Spacebars.mustache(view.lookup("propagationNodeAvgTimeClass"), view.lookup("stats"), Spacebars.dot(view.lookup("Blockchain"), "bestBlock"));
}
}, Blaze.View("lookup:blockPropagationAvgFilter", function() {
return Spacebars.mustache(view.lookup("blockPropagationAvgFilter"), view.lookup("stats"), Spacebars.dot(view.lookup("Blockchain"), "bestBlock"));
})), "\n ", HTML.TD({
"class": function() {
return Spacebars.mustache(view.lookup("upTimeClass"), Spacebars.dot(view.lookup("stats"), "uptime"), Spacebars.dot(view.lookup("stats"), "active"));
}
}, Blaze.View("lookup:upTimeFilter", function() {
return Spacebars.mustache(view.lookup("upTimeFilter"), Spacebars.dot(view.lookup("stats"), "uptime"));
})), "\n "), "\n " ];
}), "\n "), "\n "), "\n ") ];
}));
})();

View File

@@ -0,0 +1,8 @@
(function(){
Template.body.addContent((function() {
var view = this;
return [ "\n ", Spacebars.include(view.lookupTemplate("indexMeteor")), "\n " ];
}));
Meteor.startup(Template.body.renderToDocument);
})();