Created
October 11, 2015 15:22
-
-
Save matteofigus/61cb3ac662467b9f6076 to your computer and use it in GitHub Desktop.
grunt-api-benchmark output
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<title>Api Benchmark :: report</title> | |
<!--[if lt IE 9]><script src="https://cdnjs.cloudflare.com/ajax/libs/jqPlot/1.0.8/excanvas.min.js"></script><![endif]--> | |
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqPlot/1.0.8/jquery.jqplot.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqPlot/1.0.8/plugins/jqplot.canvasTextRenderer.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqPlot/1.0.8/plugins/jqplot.canvasAxisLabelRenderer.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqPlot/1.0.8/plugins/jqplot.highlighter.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.0/highlight.min.js"></script> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqPlot/1.0.8/jquery.jqplot.min.css" type="text/css" /> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.0/styles/dark.min.css" type="text/css" /> | |
<style type="text/css"> | |
.jqplot-target { | |
color: #F1F1F1; | |
} | |
table.jqplot-table-legend, table.jqplot-cursor-legend { | |
background-color: rgba(101, 0, 253, 0.89) | |
} | |
body { | |
background: #3D3D3D; | |
color: #F1F1F1; | |
} | |
a { | |
color: #6699FF; | |
} | |
#report-details, #charts { | |
width: 100%; | |
float: left; | |
font-family: "Trebuchet MS",Arial,Helvetica,sans-serif; | |
} | |
#report-details { | |
margin-bottom: 20px; | |
text-align: center; | |
} | |
.buttons { | |
width: 100%; | |
border-bottom: 1px solid rgb(75, 72, 72); | |
padding-bottom: 10px; | |
margin-bottom: 10px; | |
text-align: right; | |
} | |
.button { | |
margin-right: 10px; | |
padding: 6px; | |
text-decoration: none; | |
} | |
.button.selected { | |
background-color: rgb(56, 56, 56); | |
} | |
.chart { | |
width: 60%; | |
height: 450px; | |
float: left; | |
} | |
.distchart { | |
width: 96%; | |
height: 450px; | |
float: left; | |
} | |
.panel { | |
height: 450px; | |
overflow-y: auto; | |
} | |
.route { | |
width: 90%; | |
margin: 3%; | |
padding: 2%; | |
float: left; | |
background-color: #000000; | |
border-radius: 15px; | |
} | |
.stats-details { | |
font-family: "Trebuchet MS",Arial,Helvetica,sans-serif; | |
font-size: 15px; | |
float: left; | |
width: 36%; | |
padding: 2%; | |
} | |
.green { | |
color: green; | |
} | |
.red { | |
color: red; | |
} | |
.hide { | |
display:none; | |
} | |
pre code { | |
overflow-x: auto; | |
} | |
</style> | |
</head> | |
<body> | |
<script><!-- | |
var data={"benchmark":{"My api":{"simpleRoute":{"name":"My api/simpleRoute","href":"http://localhost:3006/getJson","stats":{"sample":[0.01357674,0.004451465,0.002704374,0.002977995,0.002877574,0.002325863,0.002939445,0.002130357,0.002745725,0.002537905,0.003596319,0.002679005,0.003646311,0.002892941,0.002814363,0.002955197,0.003061557,0.003011819,0.003146771,0.002653854,0.002262629,0.003445287,0.00242548,0.003503066,0.001852882,0.002635448,0.003164103,0.00287955,0.002953393,0.003300628,0.002467521,0.003496141,0.005711787,0.002572354,0.00274642,0.002592796,0.00405076,0.003749407,0.003154614,0.003250697,0.003303471,0.003078609,0.003487908,0.00347683,0.002904609,0.002312779,0.002572475,0.003625578,0.003314829,0.004698727],"mean":0.003294327159999999,"singleMean":0.003294327159999999,"variance":0.0000026503800015192793,"deviation":0.0016279987719649174,"sem":0.00023023379428395297,"moe":0.0004512582367965478,"rme":13.698039535227824,"p75":0.0034795995,"p95":0.005154603999999996,"p99":0.01357674,"p999":0.01357674},"errors":{},"options":{"method":"get","concurrencyLevel":1,"start":"2015-10-11T15:13:42.005Z","end":"2015-10-11T15:13:42.170Z"},"request":{},"response":{"header":{"x-powered-by":"Express","content-type":"application/json; charset=utf-8","content-length":"27","etag":"\"1930243982\"","date":"Sun, 11 Oct 2015 15:13:42 GMT","connection":"close"},"statusCode":200,"body":"{\n \"message\": \"/getJson\"\n}","type":"application/json"},"hz":303.5521220060002},"secondaryRoute":{"name":"My api/secondaryRoute","href":"http://localhost:3006/getJson2","stats":{"sample":[0.002654189,0.002381642,0.002134532,0.002947698,0.003579008,0.002960868,0.002839665,0.002377134,0.002472979,0.005438477,0.003340719,0.003008837,0.003313665,0.002683624,0.004567821,0.010302359,0.004997022,0.003113254,0.002814524,0.002619174,0.002300552,0.00258412,0.003411082,0.00313257,0.002734786,0.003108364,0.002293127,0.002632554,0.003800198,0.003442057,0.002560258,0.002615407,0.002617405,0.003512938,0.002971256,0.002658991,0.00244818,0.003369597,0.001337099,0.002636872,0.002960341,0.002927998,0.002976053,0.003787202,0.002946055,0.002908672,0.002680191,0.003344324,0.003011174,0.003083977],"mean":0.0031468118199999996,"singleMean":0.0031468118199999996,"variance":0.0000015286028098581915,"deviation":0.001236366778046948,"sem":0.000174848666558152,"moe":0.00034270338645397795,"rme":10.890495080636185,"p75":0.00334162025,"p95":0.0051956767499999985,"p99":0.010302359,"p999":0.010302359},"errors":{},"options":{"method":"get","concurrencyLevel":1,"start":"2015-10-11T15:13:42.173Z","end":"2015-10-11T15:13:42.331Z"},"request":{},"response":{"header":{"x-powered-by":"Express","content-type":"application/json; charset=utf-8","content-length":"28","etag":"\"-251859214\"","date":"Sun, 11 Oct 2015 15:13:42 GMT","connection":"close"},"statusCode":200,"body":"{\n \"message\": \"/getJson2\"\n}","type":"application/json"},"hz":317.781951130462},"postRoute":{"name":"My api/postRoute","href":"http://localhost:3006/postJson","stats":{"sample":[0.004925044,0.002757273,0.002829501,0.002946599,0.00288121,0.002922298,0.001276902,0.002682766,0.001308097,0.002660585,0.002935274,0.002914031,0.002581371,0.003142122,0.002888957,0.003818671,0.002865263,0.002998599,0.002770339,0.002315193,0.002590548,0.002691801,0.002796524,0.00293225,0.005992326,0.003039912,0.004061229,0.003393566,0.003007595,0.002770579,0.003997125,0.009785281,0.003336936,0.002927775,0.003217157,0.002875874,0.002935301,0.003578158,0.00368908,0.002980481,0.002971544,0.002925199,0.002963889,0.003007356,0.003008785,0.002898165,0.002903681,0.002985745,0.002941816,0.004044152],"mean":0.0031933984999999994,"singleMean":0.0031933984999999994,"variance":0.0000014116764484460514,"deviation":0.0011881399111409612,"sem":0.00016802835763323113,"moe":0.00032933558096113303,"rme":10.313012327184756,"p75":0.00316088075,"p95":0.0054053208999999955,"p99":0.009785281,"p999":0.009785281},"errors":{},"options":{"method":"post","concurrencyLevel":1,"start":"2015-10-11T15:13:42.332Z","end":"2015-10-11T15:13:42.493Z"},"request":{"data":{"test":true,"someData":"someStrings"}},"response":{"header":{"x-powered-by":"Express","content-type":"application/json; charset=utf-8","content-length":"28","date":"Sun, 11 Oct 2015 15:13:42 GMT","connection":"close"},"statusCode":200,"body":"{\n \"message\": \"/postJson\"\n}","type":"application/json"},"hz":313.146010433712},"deleteRoute":{"name":"My api/deleteRoute","href":"http://localhost:3006/deleteMe?test=true","stats":{"sample":[0.005121029,0.003111974,0.003223593,0.002957041,0.003105988,0.003047021,0.002998718,0.002291656,0.00258632,0.002789987,0.003061476,0.002633973,0.002867664,0.002704424,0.004195614,0.002841241,0.002816914,0.002984814,0.00306308,0.002988983,0.002994484,0.003017741,0.002997348,0.003002317,0.002942033,0.002925172,0.003279665,0.002967981,0.008361879,0.00273283,0.002807183,0.002975581,0.00309248,0.002989029,0.003031334,0.003246972,0.002994813,0.002954762,0.003490526,0.003793165,0.002747762,0.002666588,0.00152271,0.003380057,0.003179591,0.003566917,0.004632012,0.004006566,0.003297438,0.002669178],"mean":0.00319315248,"singleMean":0.00319315248,"variance":8.527159978142545e-7,"deviation":0.0009234262275971235,"sem":0.00013059218949188763,"moe":0.0002559606914040998,"rme":8.015924482381742,"p75":0.00322943775,"p95":0.004852069649999998,"p99":0.008361879,"p999":0.008361879},"errors":{},"options":{"method":"delete","concurrencyLevel":1,"start":"2015-10-11T15:13:42.494Z","end":"2015-10-11T15:13:42.654Z"},"request":{},"response":{"header":{"x-powered-by":"Express","content-type":"application/json; charset=utf-8","content-length":"28","date":"Sun, 11 Oct 2015 15:13:42 GMT","connection":"close"},"statusCode":200,"body":"{\n \"message\": \"/deleteMe\"\n}","type":"application/json"},"hz":313.17013711791174}}},"info":{"date":"2015-10-11T15:13:42.658Z","apiName":"My api"}}; | |
// --></script> | |
<div id="report"> | |
<div id="report-details"><h1>Api Benchmark report</h1></div> | |
<div id="charts"></div> | |
</div> | |
<div style="text-align: center"> | |
Generated by <a href="https://github.com/matteofigus/api-benchmark" target="_blank">api-benchmark</a><br /><br /> | |
<iframe src="http://ghbtns.com/github-btn.html?user=matteofigus&repo=api-benchmark&type=watch&count=true" allowtransparency="true" frameborder="0" scrolling="0" width="110" height="20"></iframe> | |
</div> | |
<script> | |
var selectors = { | |
charts: '#charts', | |
reportDetails: '#report-details', | |
panel: '.panel', | |
panels: { | |
stats: '.stats', | |
distribution: '.distribution', | |
response: '.response', | |
request: '.request' | |
}, | |
button: '.button', | |
buttons: { | |
stats: '.button-stats', | |
distribution: '.button-distribution', | |
response: '.button-response', | |
request: '.button-request' | |
} | |
}; | |
var formatNumber = function(number) { | |
number = String(number).split('.'); | |
return number[0].replace(/(?=(?:\d{3})+$)(?!\b)/g, ',') + | |
(number[1] ? '.' + number[1] : ''); | |
}; | |
var formatDate = function(date){ | |
return date.replace(/T/g, ' ').replace(/Z/g, ' '); | |
}; | |
var fixNumber = function(number, digits){ | |
return formatNumber(number.toFixed(digits)); | |
}; | |
var decodeHtml = function(text){ | |
return $('<div/>').text(text).html(); | |
}; | |
var templates = { | |
reportDetails: function(info){ | |
var formattedDate = formatDate(info.date); | |
return 'Benchmarked ' + info.apiName + ' on ' + formattedDate; | |
}, | |
route: function(routeData, i){ | |
var errorsCount = 0, | |
errorsDesc = '(', | |
duration = (new Date(routeData.options.end) - new Date(routeData.options.start))/1e3; | |
for(var errorType in routeData.errors){ | |
errorsCount += routeData.errors[errorType].length; | |
errorsDesc += routeData.errors[errorType].length + ' ' + errorType + ','; | |
} | |
if(errorsCount == 0) | |
errorsDesc = ''; | |
else | |
errorsDesc = errorsDesc.substr(0, errorsDesc.length - 1) + ')'; | |
var template = '<div class="route"><div class="buttons">' + | |
'<a href="#stats" class="button button-stats selected">Stats</a>' + | |
'<a href="#distribution" class="button button-distribution">Distribution</a>' + | |
'<a href="#request" class="button button-request">Request details</a>' + | |
'<a href="#response" class="button button-response">Response details</a>' + | |
'</div><div class="stats panel"><div class="chart" id="chart' + i + '"></div>' + | |
'<div class="stats-details"><ul><li>' + routeData.stats.sample.length + ' run' + | |
(routeData.stats.sample.length > 1 ? 's' : '') + ' sampled with concurrency: ' + | |
routeData.options.concurrencyLevel + '</li>'; | |
if(routeData.options.expectedStatusCode) | |
template += '<li>Expected status code: ' + routeData.options.expectedStatusCode + '</li>'; | |
if(routeData.options.maxMean) | |
template += '<li>Expected max mean: ' + routeData.options.maxMean + '</li>'; | |
if(routeData.options.maxSingleMean) | |
template += '<li>(*) Expected max mean across all concurrent requests: ' + routeData.options.maxSingleMean + '</li>'; | |
template += '</ul><ul><li>Started: ' + formatDate(routeData.options.start) + '</li>' + | |
'<li>Ended: ' + formatDate(routeData.options.end) + ' (' + duration + ' seconds)</li>' + | |
'<li>' + fixNumber(routeData.hz, 2) + ' ops/sec \xb1 ' + fixNumber(routeData.stats.rme, 2) + '%</li>' + | |
'<li class="' + (!errorsCount ? 'green' : 'red') + '">' + errorsCount + ' error' + | |
(errorsCount == 1 ? '' : 's') + ' ' + errorsDesc + '</li>' + | |
'<li>Sample arithmetic mean: ' + fixNumber(routeData.stats.mean, 6) + '</li>'; | |
if(routeData.options.concurrencyLevel > 1) | |
template += '<li>Mean across all the concurrent requests: ' + fixNumber(routeData.stats.singleMean, 6) + '</li>'; | |
template += '<li>Sample standard deviation: ' + fixNumber(routeData.stats.deviation, 6) + '</li>' + | |
'<li>Margin of error: ' + fixNumber(routeData.stats.moe, 6) + '</li>' + | |
'<li>The standard error of the mean: ' + fixNumber(routeData.stats.sem, 6) + '</li>' + | |
'<li>The sample variance: ' + fixNumber(routeData.stats.variance, 6) + '</li>' + | |
'</ul><ul><li>75% Percentile: ' + fixNumber(routeData.stats.p75, 6) + '</li>' + | |
'<li>95% Percentile: ' + fixNumber(routeData.stats.p95, 6) + '</li>' + | |
'<li>99% Percentile: ' + fixNumber(routeData.stats.p99, 6) + '</li>' + | |
'<li>99.9% Percentile: ' + fixNumber(routeData.stats.p999, 6) + '</li>' + | |
'</ul></div></div><div class="distribution panel"><div class="distchart" id="distchart' + i + '">' + | |
'</div></div><div class="request panel hide">Request: ' + routeData.options.method.toUpperCase() + | |
' <a href="' + routeData.href + '" target="_blank">' + | |
routeData.href + '</a><br />Concurrency level: ' + routeData.options.concurrencyLevel + '<br />'; | |
if(routeData.options.delay) | |
template += 'Delay between bench cycles: ' + routeData.options.delay + '<br />'; | |
var requestHeaders = 'none', | |
requestData = 'none', | |
requestQuery = 'none'; | |
if(!!routeData.request.headers) | |
requestHeaders = '<br /><pre><code>' + JSON.stringify(routeData.request.headers, undefined, 2) + '</pre></code>'; | |
if(!!routeData.request.data) | |
requestData = '<br /><pre><code>' + JSON.stringify(routeData.request.data, undefined, 2) + '</pre></code>'; | |
if(!!routeData.request.query) | |
requestQuery = '<br /><pre><code>' + JSON.stringify(routeData.request.query, undefined, 2) + '</pre></code>'; | |
template += '<br />Headers sent: ' + requestHeaders + '<br />Data sent: ' + requestData + '<br />Query sent: ' + requestQuery + '<br /></div><div class="response panel hide">Data here refers to the first sampled response.<br /><br />'; | |
var responseHeader = JSON.stringify(routeData.response.header, undefined, 2), | |
responseBody = ''; | |
try { | |
responseBody = JSON.stringify(JSON.parse(decodeHtml(routeData.response.body)), undefined, 2); | |
} catch(e){ | |
responseBody = decodeHtml(routeData.response.body); | |
} | |
template += 'Response status: ' + routeData.response.statusCode + '<br />Response headers:<br />' + | |
'<pre><code>' + responseHeader + '</code></pre>' + | |
'<br />Response body:<br /><pre><code>' + responseBody + '</code></pre><br /></div></div>'; | |
return template; | |
} | |
}; | |
var bindButtons = function(){ | |
var bindButton = function(panelName){ | |
$(selectors.buttons[panelName]).click(function(){ | |
var $sender = $(this), | |
$panelsContainer = $sender.parent().parent(); | |
$panelsContainer.find(selectors.button).removeClass('selected'); | |
$sender.addClass('selected'); | |
$panelsContainer.find(selectors.panel).addClass('hide'); | |
$panelsContainer.find(selectors.panels[panelName]).removeClass('hide'); | |
return false; | |
}); | |
}; | |
bindButton('stats'); | |
bindButton('distribution'); | |
bindButton('response'); | |
bindButton('request'); | |
}; | |
$(function(){ | |
$(selectors.reportDetails).append(templates.reportDetails(data.info)); | |
var counter = 0; | |
for(serviceName in data.benchmark){ | |
for(routeName in data.benchmark[serviceName]){ | |
$(selectors.charts).append(templates.route(data.benchmark[serviceName][routeName], counter)); | |
var samples = data.benchmark[serviceName][routeName]['stats']['sample'], | |
meanArray = [], | |
mean = data.benchmark[serviceName][routeName]['stats']['mean'], | |
singleMeanArray = [], | |
singleMean = data.benchmark[serviceName][routeName]['stats']['singleMean'], | |
maxMeanArray = [], | |
maxMean = data.benchmark[serviceName][routeName].options.maxMean !== undefined, | |
maxSingleMeanArray = [], | |
maxSingleMean = data.benchmark[serviceName][routeName].options.maxSingleMean !== undefined, | |
errorsArray = [], | |
areThereSomeErrors = false; | |
for(var i = 0; i < samples.length; i++){ | |
meanArray.push(mean); | |
singleMeanArray.push(singleMean); | |
errorsArray.push(null); | |
if(maxMean) | |
maxMeanArray.push(data.benchmark[serviceName][routeName].options.maxMean); | |
if(maxSingleMean) | |
maxSingleMeanArray.push(data.benchmark[serviceName][routeName].options.maxSingleMean); | |
} | |
for(var errorType in data.benchmark[serviceName][routeName].errors){ | |
var errorsOfType = data.benchmark[serviceName][routeName]['errors'][errorType]; | |
for(var i = 0; i < errorsOfType.length; i++){ | |
if(errorsOfType[i].pos !== undefined){ | |
errorsArray[errorsOfType[i].pos] = data.benchmark[serviceName][routeName]['stats']['sample'][errorsOfType[i].pos]; | |
areThereSomeErrors = true; | |
} | |
} | |
} | |
var getSeriesOptions = function(label, color){ | |
return { | |
showMarker: false, | |
pointLabels: { show: true }, | |
label: label, | |
color: color | |
}; | |
}; | |
var lines = [samples], | |
series = [getSeriesOptions('Samples', '#6699FF')]; | |
if(maxMean){ | |
lines.push(maxMeanArray); | |
series.push(getSeriesOptions('Max Mean', '#F90')); | |
} | |
lines.push(meanArray); | |
series.push(getSeriesOptions('Mean', '#66FF00')); | |
if(maxSingleMean){ | |
lines.push(maxSingleMeanArray); | |
series.push(getSeriesOptions('Max Single Mean (*)', '#EBFF00')); | |
lines.push(singleMeanArray); | |
series.push(getSeriesOptions('Single mean', '#FC6333')); | |
} | |
if(areThereSomeErrors > 0){ | |
lines.push(errorsArray); | |
series.push({ | |
showLine:false, | |
markerOptions: { size: 7, style:'x' }, | |
label: 'Errors', | |
color: '#FF0000' | |
}); | |
} | |
var options = { | |
title: { | |
text: data.benchmark[serviceName][routeName]['name'], | |
color: '#F1F1F1' | |
}, | |
animate: true, | |
grid: { | |
background: '#000000', textColor: '#F1F1F1' | |
}, | |
seriesDefaults:{ | |
rendererOptions: { | |
showDataLabels: true | |
} | |
}, | |
highlighter: { | |
show: true, | |
sizeAdjust: 7.5 | |
}, | |
legend: { | |
show:true, | |
location: 'se', | |
background: 'rgba(101, 0, 253, 0.89)' | |
}, | |
axesDefaults: { | |
labelRenderer: $.jqplot.CanvasAxisLabelRenderer | |
}, | |
axes: { | |
xaxis: { | |
label: 'Samples', | |
pad: 0 | |
}, | |
yaxis: { | |
label: 'Response time (seconds)', | |
tickOptions: { | |
formatString:'%.6f' | |
} | |
} | |
}, | |
series: series | |
}; | |
$.jqplot('chart' + counter, lines, options); | |
counter++; | |
} | |
} | |
hljs.initHighlightingOnLoad(); | |
bindButtons(); | |
}); | |
$(function(){ | |
var counter = 0; | |
for(serviceName in data.benchmark){ | |
for(routeName in data.benchmark[serviceName]){ | |
var samples = data.benchmark[serviceName][routeName]['stats']['sample']; | |
var buckets = [[0.001, 0], [0.005, 0], [0.01, 0], [0.015, 0], [0.025, 0], [0.05, 0], [0.1, 0], [0.25, 0], [0.333, 0], [0.5, 0], [0.750, 0], [1.5, 0], [3, 0], [6, 0], [12, 0], [50, 0], [100, 0], [300, 0], [1000, 0]]; | |
for(var i = 0; i<samples.length; i++) { | |
for (var j =0; j<buckets.length; j++) { | |
if(buckets[j][0]>= samples[i]){ | |
buckets[j][1] += 100/samples.length; | |
break; | |
} | |
}; | |
} | |
var distribution = []; | |
for(i =0; i<buckets.length; i++) { | |
if(buckets[i][1]){ | |
distribution.push(buckets[i]); | |
} | |
} | |
var lines = [distribution], | |
series = [{ | |
showMarker: false, | |
pointLabels: { show: true }, | |
label: 'Samples', | |
color: '#6699FF' | |
}]; | |
var options = { | |
title: { | |
text: data.benchmark[serviceName][routeName]['name'], | |
color: '#F1F1F1' | |
}, | |
animate: true, | |
grid: { | |
background: '#000000', textColor: '#F1F1F1' | |
}, | |
seriesDefaults:{ | |
rendererOptions: { | |
showDataLabels: true | |
} | |
}, | |
highlighter: { | |
show: true, | |
sizeAdjust: 7.5 | |
}, | |
legend: { | |
show:true, | |
location: 'se', | |
background: 'rgba(101, 0, 253, 0.89)' | |
}, | |
axesDefaults: { | |
labelRenderer: $.jqplot.CanvasAxisLabelRenderer | |
}, | |
axes: { | |
xaxis: { | |
label: 'Response time (seconds)', | |
tickOptions: { | |
formatString:'%.3f' | |
} | |
}, | |
yaxis: { | |
label: 'Percent of responses', | |
tickOptions: { | |
formatString: function(val){ | |
console.log(val); | |
return '%.1f%';}() | |
} | |
} | |
}, | |
series: series | |
}; | |
$.jqplot('distchart' + counter, lines, options); | |
counter++; | |
} | |
} | |
$(".distribution.panel").addClass('hide'); | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment