]> arthur.barton.de Git - netdata.git/blob - web/index.html
Merge pull request #879 from ktsaou/master
[netdata.git] / web / index.html
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4     <title>netdata dashboard</title>
5     <meta name="application-name" content="netdata">
6
7     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
8     <meta charset="utf-8">
9     <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
10     <meta name="viewport" content="width=device-width, initial-scale=1">
11     <meta name="apple-mobile-web-app-capable" content="yes">
12     <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
13     <meta name="author" content="costa@tsaousis.gr">
14
15     <link rel="shortcut icon" href="images/seo-performance-multi-size.ico">
16
17     <link rel="apple-touch-icon" href="images/seo-performance-72.png">
18     <link rel="apple-touch-icon" sizes="72x72" href="images/seo-performance-72.png">
19     <link rel="apple-touch-icon" sizes="114x114" href="images/seo-performance-114.png">
20
21     <link rel="icon" type="image/png" sizes="512x512" href="images/seo-performance-512.png">
22     <link rel="icon" type="image/png" sizes="256x256" href="images/seo-performance-256.png">
23     <link rel="icon" type="image/png" sizes="128x128" href="images/seo-performance-128.png">
24     <link rel="icon" type="image/png" sizes="64x64" href="images/seo-performance-64.png">
25     <link rel="icon" type="image/png" sizes="48x48" href="images/seo-performance-48.png">
26     <link rel="icon" type="image/png" sizes="32x32" href="images/seo-performance-32.png">
27     <link rel="icon" type="image/png" sizes="24x24" href="images/seo-performance-24.png">
28     <link rel="icon" type="image/png" sizes="16x16" href="images/seo-performance-16.png">
29
30     <meta property="og:locale" content="en_US" />
31     <meta property="og:image" content="http://my-netdata.io/images/post.png"/>
32     <meta property="og:url" content="http://my-netdata.io/"/>
33     <meta property="og:type" content="website"/>
34     <meta property="og:site_name" content="netdata"/>
35     <meta property="og:title" content="netdata - real-time performance monitoring, done right!"/>
36     <meta property="og:description" content="Stunning real-time dashboards, blazingly fast and extremely interactive. Zero configuration, zero dependencies, zero maintenance." />
37
38     <style>
39
40     /* prevent body from hiding under the navbar */
41     body {
42         padding-top: 50px;
43     }
44
45     .loadOverlay {
46         position: absolute;
47         top: 0px;
48         left: 0px;
49         width: 100%;
50         height:100%;
51         z-index: 2000;
52         font-size: 10vh;
53         font-family: sans-serif;
54         padding: 40vh 0 40vh 0;
55         font-weight: bold;
56         text-align: center;
57     }
58
59     .modal-wide .modal-dialog {
60         width: 80%;
61     }
62
63     /* fix # anchors scrolling under the navbar
64        https://github.com/twbs/bootstrap/issues/1768#issuecomment-46519033
65      */
66     h1 {
67         position: relative;
68         z-index: -1;
69     }
70     h2 {
71         position: relative;
72         z-index: -2;
73     }
74     h1:before, h2:before {
75         display: block;
76         content: " ";
77         margin-top: -70px;
78         height: 70px;
79         visibility: hidden;
80     }
81
82     .p {
83         display: block;
84         margin-top: 15px;
85     }
86
87     .option-row,
88     .option-control {
89         vertical-align: top;
90         padding: 10px;
91         padding-top: 30px;
92         padding-left: 30px;
93     }
94
95     .option-info {
96         padding: 10px;
97     }
98
99     .chart-message {
100         display: block;
101         margin-top: 10px;
102     }
103
104     .container {
105         width: 90% !important;
106     }
107
108     #masthead h1 {
109         /*font-size: 30px;*/
110         line-height: 1;
111         padding-top: 30px;
112     }
113
114     #masthead .well {
115         margin-top:4%;
116     }
117
118     /* fix the navbar shifting when a modal is open */
119     /* https://github.com/twbs/bootstrap/issues/14040#issuecomment-159891033 */
120     body.modal-open{
121         width: 100% !important;
122         padding-right: 0 !important;
123 /*      overflow-y: scroll !important; */
124 /*      position: fixed !important;*/
125         overflow: visible;
126     }
127
128     /* make accordion use the whole header bar for expand/collapse */
129     .panel-title a {
130         display: block;
131         padding: 10px 15px;
132         margin: -10px -15px;
133     }
134
135     /*
136      * Side navigation
137      *
138      * Scrollspy and affixed enhanced navigation to highlight sections and secondary
139      * sections of docs content.
140      */
141
142     .affix {
143         position: static;
144         top: 70px !important;
145         /*width: 220px;*/
146     }
147
148     .affix-top {
149         /*width: 220px;*/
150     }
151
152     .dashboard-sidebar {
153         max-height: calc(100% - 70px) !important;
154         overflow-y: auto;
155         /*width: 220px !important;*/
156     }
157
158     /* By default it's not affixed in mobile views, so undo that */
159     .dashboard-sidebar.affix {
160         position: static;
161     }
162
163     @media (min-width: 768px) {
164         .dashboard-sidebar {
165             padding-left: 20px;
166         }
167     }
168
169     /* First level of nav */
170     .dashboard-sidenav {
171         margin-top: 20px;
172         margin-bottom: 20px;
173     }
174
175     /* All levels of nav */
176     .dashboard-sidebar .nav > li > a {
177         display: block;
178         padding: 4px 20px;
179         font-size: 13px;
180         font-weight: 500;
181         color: #767676;
182     }
183     .dashboard-sidebar .nav > li > a:hover,
184     .dashboard-sidebar .nav > li > a:focus {
185         padding-left: 19px;
186         color: #563d7c;
187         text-decoration: none;
188         background-color: transparent;
189         border-left: 1px solid #563d7c;
190     }
191     .dashboard-sidebar .nav > .active > a,
192     .dashboard-sidebar .nav > .active:hover > a,
193     .dashboard-sidebar .nav > .active:focus > a {
194         padding-left: 18px;
195         font-weight: bold;
196         color: #563d7c;
197         background-color: transparent;
198         border-left: 2px solid #563d7c;
199     }
200
201     /* Nav: second level (shown on .active) */
202     .dashboard-sidebar .nav .nav {
203         display: none; /* Hide by default, but at >768px, show it */
204         padding-bottom: 10px;
205     }
206     .dashboard-sidebar .nav .nav > li > a {
207         padding-top: 1px;
208         padding-bottom: 1px;
209         padding-left: 30px;
210         font-size: 12px;
211         font-weight: normal;
212     }
213     .dashboard-sidebar .nav .nav > li > a:hover,
214     .dashboard-sidebar .nav .nav > li > a:focus {
215         padding-left: 29px;
216     }
217     .dashboard-sidebar .nav .nav > .active > a,
218     .dashboard-sidebar .nav .nav > .active:hover > a,
219     .dashboard-sidebar .nav .nav > .active:focus > a {
220         padding-left: 28px;
221         font-weight: 500;
222     }
223
224     .dropdown-menu {
225         min-width: 200px;
226     }
227     .dropdown-menu.columns-2 {
228         margin: 0;
229         padding: 0;
230         width: 400px;
231     }
232     .dropdown-menu li a {
233         padding: 5px 15px;
234         font-weight: 300;
235     }
236     .dropdown-menu.multi-column {
237         overflow-x: hidden;
238     }
239     .multi-column-dropdown {
240         list-style: none;
241         padding: 0;
242     }
243     .multi-column-dropdown li a {
244         display: block;
245         clear: both;
246         line-height: 1.428571429;
247         white-space: normal;
248     }
249     .multi-column-dropdown li a:hover {
250         text-decoration: none;
251         color: #f5f5f5;
252         background-color: #262626;
253     }
254     .scrollable-menu {
255         height: auto;
256         max-height: 80vh;
257         overflow-x: hidden;
258     }
259
260     /* Back to top (hidden on mobile) */
261     .back-to-top,
262     .dashboard-theme-toggle {
263         display: none;
264         padding: 4px 10px;
265         margin-top: 10px;
266         margin-left: 10px;
267         font-size: 12px;
268         font-weight: 500;
269         color: #999;
270     }
271     .back-to-top:hover,
272     .dashboard-theme-toggle:hover {
273         color: #563d7c;
274         text-decoration: none;
275     }
276     .dashboard-theme-toggle {
277         margin-top: 0;
278     }
279
280     @media (min-width: 768px) {
281         .back-to-top,
282         .dashboard-theme-toggle {
283             display: block;
284         }
285
286         /* Widen the fixed sidebar */
287         .dashboard-sidebar.affix,
288         .dashboard-sidebar.affix-top,
289         .dashboard-sidebar.affix-bottom {
290             width: 200px !important;
291         }
292
293         .dashboard-sidebar.affix {
294             position: fixed; /* Undo the static from mobile first approach */
295             top: 20px;
296         }
297
298         .dashboard-sidebar.affix-bottom {
299             position: absolute; /* Undo the static from mobile first approach */
300         }
301
302         .dashboard-sidebar.affix-bottom .dashboard-sidenav,
303         .dashboard-sidebar.affix .dashboard-sidenav {
304             margin-top: 0;
305             margin-bottom: 0;
306         }
307     }
308
309     /* Show and affix the side nav when space allows it */
310     @media (min-width: 992px) {
311         .dashboard-sidebar .nav > .active > ul {
312             display: block;
313         }
314
315         /* Widen the fixed sidebar */
316         .dashboard-sidebar.affix,
317         .dashboard-sidebar.affix-top,
318         .dashboard-sidebar.affix-bottom {
319             width: 200px !important;
320         }
321         .dashboard-sidebar.affix {
322             position: fixed; /* Undo the static from mobile first approach */
323             top: 20px;
324         }
325         .dashboard-sidebar.affix-bottom {
326             position: absolute; /* Undo the static from mobile first approach */
327         }
328         .dashboard-sidebar.affix-bottom .dashboard-sidenav,
329         .dashboard-sidebar.affix .dashboard-sidenav {
330             margin-top: 0;
331             margin-bottom: 0;
332         }
333     }
334
335     @media (min-width: 1200px) {
336         /* Widen the fixed sidebar again */
337         .dashboard-sidebar.affix-bottom,
338         .dashboard-sidebar.affix-top,
339         .dashboard-sidebar.affix {
340             width: 263px;
341         }
342     }
343     </style>
344
345     <!-- check which theme to use -->
346     <script type="text/javascript">
347         // --------------------------------------------------------------------
348         // urlOptions
349
350         var urlOptions = {
351             hash: '#',
352             theme: null,
353             help: null,
354             pan_and_zoom: false,
355             after: 0,
356             before: 0,
357             nowelcome: 0,
358             hasProperty: function(property) {
359                 // console.log('checking property ' + property + ' of type ' + typeof(this[property]));
360                 return typeof this[property] !== 'undefined';
361             }
362         };
363
364         function netdataPanAndZoomCallback(status, after, before) {
365             urlOptions.pan_and_zoom = status;
366             urlOptions.after = after;
367             urlOptions.before = before;
368             netdataHashUpdate();
369         }
370
371         function netdataHashUpdate() {
372             history.replaceState(null, '', netdataHash());
373         }
374
375         function netdataHash() {
376             var hash = urlOptions.hash;
377
378             if(urlOptions.pan_and_zoom === true) {
379                 hash += ';after='  + urlOptions.after.toString() +
380                         ';before=' + urlOptions.before.toString();
381             }
382
383             if(urlOptions.theme !== null)
384                 hash += ';theme=' + urlOptions.theme.toString();
385
386             if(urlOptions.help !== null)
387                 hash += ';help=' + urlOptions.help.toString();
388
389             return hash;
390         }
391
392         function netdataHashParse() {
393             var variables = document.location.hash.split(';');
394             var len = variables.length;
395             while(len--) {
396                 if(len !== 0) {
397                     var p = variables[len].split('=');
398                     if(urlOptions.hasProperty(p[0]) && typeof p[1] !== 'undefined')
399                         urlOptions[p[0]] = p[1];
400                 }
401                 else {
402                     if(variables[len].length > 0)
403                         urlOptions.hash = variables[len];
404                 }
405             }
406
407             if(urlOptions.before > 0 && urlOptions.after > 0)
408                 urlOptions.pan_and_zoom = true;
409
410             // console.log(urlOptions);
411         }
412
413         netdataHashParse();
414
415         // --------------------------------------------------------------------
416         // check options that should be processed before loading netdata.js
417         
418         function loadLocalStorage(name) {
419             var ret = null;
420
421             try {
422                 if(typeof Storage !== "undefined" && typeof localStorage === 'object')
423                     ret = localStorage.getItem(name);
424             }
425             catch(error) {
426                 ;
427             }
428
429             if(typeof ret === 'undefined' || ret === null)
430                 return null;
431
432             // console.log('loaded: ' + name.toString() + ' = ' + ret.toString());
433
434             return ret;
435         }
436
437         function saveLocalStorage(name, value) {
438             // console.log('saving: ' + name.toString() + ' = ' + value.toString());
439             try {
440                 if(typeof Storage !== "undefined" && typeof localStorage === 'object') {
441                     localStorage.setItem(name, value.toString());
442                     return true;
443                 }
444             }
445             catch(error) {
446                 ;
447             }
448
449             return false;
450         }
451
452         function getTheme(def) {
453             var ret = loadLocalStorage('netdataTheme');
454             if(typeof ret === 'undefined' || ret === null || ret === 'undefined')
455                 return def;
456             else
457                 return ret;
458         }
459
460         function setTheme(theme) {
461             if(theme === netdataTheme) return false;
462             return saveLocalStorage('netdataTheme', theme);
463         }
464
465         var netdataTheme = getTheme('slate');
466         var netdataShowHelp = true;
467
468         if(urlOptions.theme !== null) {
469             setTheme(urlOptions.theme);
470             netdataTheme = urlOptions.theme;
471         }
472         else
473             urlOptions.theme = netdataTheme;
474
475         if(urlOptions.help !== null) {
476             saveLocalStorage('options.show_help', urlOptions.help);
477             netdataShowHelp = urlOptions.help;
478         }
479         else {
480             urlOptions.help = loadLocalStorage('options.show_help');
481         }
482
483         // --------------------------------------------------------------------
484         // registry call back to render my-netdata menu
485
486         var netdataRegistryCallback = function(machines_array) {
487             var el = '';
488             var a1 = '';
489             var found = 0;
490
491             if(machines_array) {
492                 function name_comparator_desc(a, b) {
493                     if (a.name > b.name) return -1;
494                     if (a.name < b.name) return 1;
495                     return 0;
496                 }
497
498                 var machines = machines_array.sort(name_comparator_desc);
499                 var len = machines.length;
500                 while(len--) {
501                     var u = machines[len];
502                     found++;
503                     el += '<li id="registry_server_' + u.guid + '"><a class="registry_link" href="' + u.url + '" onClick="return gotoServerModalHandler(\'' + u.guid + '\');">' + u.name + '</a></li>';
504                     a1 += '<li id="registry_action_' + u.guid + '"><a href="#" onclick="deleteRegistryModalHandler(\'' + u.guid + '\',\'' + u.name + '\',\'' + u.url + '\'); return false;"><i class="fa fa-trash-o" aria-hidden="true" style="color: #999;"></i></a></li>';
505                 }
506             }
507
508             if(!found) {
509                 if(machines)
510                     el += '<li><a href="https://github.com/firehol/netdata/wiki/mynetdata-menu-item" style="color: #666;" target="_blank">your netdata server list is empty...</a></li>';
511                 else
512                     el += '<li><a href="https://github.com/firehol/netdata/wiki/mynetdata-menu-item" style="color: #666;" target="_blank">failed to contact the registry...</a></li>';
513
514                 a1 += '<li><a href="#" onClick="return false;">&nbsp;</a></li>';
515
516                 el += '<li role="separator" class="divider"></li>' +
517                         '<li><a href="//london.netdata.rocks/default.html">EU - London (DigitalOcean.com)</a></li>' +
518                         '<li><a href="//atlanta.netdata.rocks/default.html">US - Atlanta (CDN77.com)</a></li>' +
519                         '<li><a href="//athens.netdata.rocks/default.html">EU - Athens</a></li>';
520                 a1 += '<li role="separator" class="divider"></li>' +
521                         '<li><a href="#">&nbsp;</a></li>' +
522                         '<li><a href="#">&nbsp;</a></li>'+
523                         '<li><a href="#">&nbsp;</a></li>';
524             }
525
526             el += '<li role="separator" class="divider"></li>';
527             a1 += '<li role="separator" class="divider"></li>';
528
529             el += '<li><a href="https://github.com/firehol/netdata/wiki/mynetdata-menu-item" style="color: #999;" target="_blank">What is this?</a></li>';
530             a1 += '<li><a href="#" style="color: #999;" onclick="switchRegistryModalHandler(); return false;"><i class="fa fa-sliders" aria-hidden="true" style="color: #999;"></i></a></li>'
531
532             document.getElementById('mynetdata_servers').innerHTML = el;
533             document.getElementById('mynetdata_servers2').innerHTML = el;
534             document.getElementById('mynetdata_actions1').innerHTML = a1;
535
536             gotoServerInit();
537         };
538
539     </script>
540
541     <!-- load the dashboard manager - it will do the rest -->
542     <script type="text/javascript" src="dashboard.js?v43"></script>
543 </head>
544 <body data-spy="scroll" data-target="#sidebar">
545     <div id="loadOverlay" class="loadOverlay" style="background-color: #888; color: #888;">
546         netdata<br/><div style="font-size: 3vh;">Real-time performance monitoring, done right!</div>
547     </div>
548     <script type="text/javascript">
549         // change the loadOverlay colors ASAP to match the theme
550         document.getElementById('loadOverlay').style = (urlOptions.theme === 'slate')?"background-color:#272b30; color: #373b40;":"background-color:#fff; color: #ddd;";
551     </script>
552     <nav class="navbar navbar-default navbar-fixed-top" role="banner">
553         <div class="container">
554             <nav id="mynetdata_nav" class="collapse navbar-collapse navbar-left hidden-sm hidden-xs" role="navigation" style="padding-right: 20px;">
555                 <ul class="nav navbar-nav">
556                     <li class="dropdown">
557                         <a href="#" class="dropdown-toggle" data-toggle="dropdown" id="current_view">my-netdata <strong class="caret"></strong></a>
558                         <ul class="dropdown-menu scrollable-menu inpagemenu multi-column columns-2" role="menu">
559                             <div class="row">
560                                 <div class="col-sm-6" style="width: 85%; padding-right: 0;">
561                                     <ul id="mynetdata_servers" class="multi-column-dropdown">
562                                         <li><a href="#" onclick="return false;" style="color: #999;">loading...</a></li>
563                                     </ul>
564                                 </div>
565                                 <div class="col-sm-3 hidden-xs" style="width: 15%; padding-left: 0;">
566                                     <ul id="mynetdata_actions1" class="multi-column-dropdown">
567                                     <li style="color: #999;">&nbsp;</li>
568                                     </ul>
569                                 </div>
570                             </div>
571                         </ul>
572                     </li>
573                 </ul>
574             </nav>
575             <div class="navbar-header">
576                 <button class="navbar-toggle" type="button" data-toggle="collapse" data-target=".navbar-collapse">
577                     <span class="sr-only">Toggle navigation</span>
578                     <span class="icon-bar"></span>
579                     <span class="icon-bar"></span>
580                     <span class="icon-bar"></span>
581                 </button>
582                 <a href="/" class="navbar-brand" id="hostname" title="reload the dashboard">netdata</a>
583             </div>
584             <nav class="collapse navbar-collapse navbar-right" role="navigation">
585                 <ul class="nav navbar-nav">
586                     <li class="hidden-sm"><a href="#" class="btn" data-toggle="modal" data-target="#alarmsModal" title="alarms"><i class="fa fa-bell"></i><span id="alarms_count_badge" class="badge"></span></a></li>
587                     <li class="hidden-sm"><a href="#" class="btn" data-toggle="modal" data-target="#optionsModal" title="dashboard settings"><i class="fa fa-sliders"></i></a></li>
588                     <li class="hidden-sm"><a href="https://github.com/firehol/netdata/wiki" class="btn" target="_blank" title="netdata community"><i class="fa fa-github"></i></a></li>
589                     <li class="hidden-sm" id="updateButton"><a href="#" class="btn" data-toggle="modal" data-target="#updateModal" title="check for update"><i class="fa fa-cloud-download"></i><span id="update_badge" class="badge"></span></a></li>
590                     <li class="hidden-sm"><a href="#" class="btn" data-toggle="modal" data-target="#helpModal" title="dashboard help"><i class="fa fa-question-circle"></i></a></li>
591                     <li class="dropdown hidden-md hidden-lg hidden-xs">
592                         <a href="#" class="dropdown-toggle" data-toggle="dropdown" id="current_view">Menu <strong class="caret"></strong></a>
593                         <ul class="dropdown-menu scrollable-menu inpagemenu" role="menu">
594                             <li><a href="#" class="btn" data-toggle="modal" data-target="#alarmsModal"><i class="fa fa-bell"></i> alarms</a></li>
595                             <li><a href="#" class="btn" data-toggle="modal" data-target="#optionsModal"><i class="fa fa-sliders"></i> settings</a></li>
596                             <li><a href="https://github.com/firehol/netdata/wiki" class="btn" target="_blank"><i class="fa fa-github"></i> community</a></li>
597                             <li><a href="#" class="btn" data-toggle="modal" data-target="#helpModal"><i class="fa fa-question-circle"></i> help</a></li>
598                         </ul>
599                     </li>
600                     <li class="dropdown hidden-sm hidden-md hidden-lg">
601                         <a href="#" class="dropdown-toggle" data-toggle="dropdown" id="current_view">my-netdata <strong class="caret"></strong></a>
602                         <ul id="mynetdata_servers2" class="dropdown-menu scrollable-menu inpagemenu" role="menu">
603                             <li><a href="#" onclick="return false;" style="color: #999;">loading...</a></li>
604                         </ul>
605                     </li>
606                 </ul>
607             </nav>
608     </nav>
609         </div>
610     </nav>
611
612     <div id="masthead" style="display: none;">
613         <div class="container">
614             <div class="row">
615                 <div class="col-md-7">
616                     <h1>Netdata
617                         <p class="lead">Real-time performance monitoring, in the greatest possible detail</p>
618                     </h1>
619                 </div>
620                 <div class="col-md-5">
621                     <div class="well well-lg">
622                         <div class="row">
623                         <div class="col-md-6">
624                             <b>Drag</b> charts to pan.
625                             <b>Shift + wheel</b> on them, to zoom in and out.
626                             <b>Double-click</b> on them, to reset.
627                             <b>Hover</b> on them too!
628                             </div>
629                         <div class="col-md-6">
630                             <div data-netdata="system.intr" data-chart-library="dygraph" data-dygraph-theme="sparkline" data-dygraph-type="line" data-dygraph-strokewidth="3" data-dygraph-smooth="true" data-dygraph-highlightcirclesize="6" data-after="-90" data-height="60px" data-colors="#C66"></div>
631                             </div>
632                         </div>
633                     </div>
634                 </div>
635             </div>
636         </div>
637     </div>
638
639     <div class="container">
640         <div class="row">
641             <div class="col-md-10" role="main">
642                 <div id="charts_div"></div>
643             </div>
644             <div class="col-md-2" role="complementary">
645                 <nav class="dashboard-sidebar hidden-print hidden-xs hidden-sm" id="sidebar" role="menu"></nav>
646             </div>
647         </div>
648     </div>
649
650     <div id="footer" class="container" style="display: none;">
651         <div class="row">
652             <div class="col-md-10" role="main">
653                 <div class="p">
654                     <big><a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata</a></big><br/>
655                     <i class="fa fa-copyright"></i> Copyright 2016, Costa Tsaousis.<br/>
656                     Released under <a href="http://www.gnu.org/licenses/gpl-3.0.en.html" target="_blank">GPL v3 or later</a>.<br/>
657                 </div>
658                 <div class="p">
659                     <small>
660                         <a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata</a> re-distributes these software tools:
661
662                         <i class="fa fa-circle"></i> The excellent <a href="http://dygraphs.com/" target="_blank">Dygraphs.com</a> web chart library,
663                         <i class="fa fa-copyright"></i> Copyright 2009, Dan Vanderkam, <a href="http://dygraphs.com/legal.html" target="_blank">MIT License</a>
664
665                         <i class="fa fa-circle"></i> <a href="http://omnipotent.net/jquery.sparkline/" target="_blank">jQuery Sparklines</a> web chart library,
666                         <i class="fa fa-copyright"></i> Copyright 2009-2012, Splunk Inc., <a href="http://opensource.org/licenses/BSD-3-Clause" target="_blank">New BSD License</a>
667
668                         <i class="fa fa-circle"></i> <a href="http://benpickles.github.io/peity/" target="_blank">Peity</a> web chart library,
669                         <i class="fa fa-copyright"></i> Copyright 2009-2015, Ben Pickles, <a href="https://github.com/benpickles/peity/blob/master/MIT-LICENCE" target="_blank">MIT License</a>
670
671                         <i class="fa fa-circle"></i> <a href="https://rendro.github.io/easy-pie-chart/" target="_blank">Easy Pie Chart</a> web chart library,
672                         <i class="fa fa-copyright"></i> Copyright 2013, Robert Fleischmann, <a href="https://github.com/rendro/easy-pie-chart/blob/master/LICENSE" target="_blank">MIT License</a>
673
674                         <i class="fa fa-circle"></i> <a href="http://bernii.github.io/gauge.js/" target="_blank">Gauge.js</a> web chart library,
675                         <i class="fa fa-copyright"></i> Copyright, Bernard Kobos, <a href="http://bernii.github.io/gauge.js/" target="_blank">MIT License</a>
676
677                         <i class="fa fa-circle"></i> <a href="https://jquery.org/" target="_blank">jQuery</a>,
678                         <i class="fa fa-copyright"></i> Copyright 2015, jQuery Foundation, <a href="https://jquery.org/license/" target="_blank">MIT License</a>
679
680                         <i class="fa fa-circle"></i> <a href="http://getbootstrap.com/getting-started/" target="_blank">Bootstrap</a>,
681                         <i class="fa fa-copyright"></i> Copyright 2015, Twitter, <a href="http://getbootstrap.com/getting-started/#license-faqs" target="_blank">MIT License</a>
682
683                         <i class="fa fa-circle"></i> <a href="http://www.bootstraptoggle.com/" target="_blank">Bootstrap Toggle</a>,
684                         <i class="fa fa-copyright"></i> Copyright (c) 2011-2014 Min Hur, The New York Times Company, <a href="https://github.com/minhur/bootstrap-toggle/blob/master/LICENSE" target="_blank">MIT License</a>
685
686                         <i class="fa fa-circle"></i> <a href="https://jamesflorentino.github.io/nanoScrollerJS/" target="_blank">NanoScroller</a>,
687                         <i class="fa fa-copyright"></i> Copyright 2012, James Florentino, <a href="https://github.com/jamesflorentino/nanoScrollerJS/blob/master/LICENSE" target="_blank">MIT License</a>
688
689                         <i class="fa fa-circle"></i> <a href="https://github.com/marcj/css-element-queries" target="_blank">CSS Element Queries</a>,
690                         <i class="fa fa-copyright"></i> Copyright Marc J. Schmidt, <a href="https://github.com/marcj/css-element-queries/blob/master/LICENSE" target="_blank">MIT License</a>
691
692                         <i class="fa fa-circle"></i> <a href="https://fortawesome.github.io/Font-Awesome/" target="_blank">FontAwesome</a>,
693                         <i class="fa fa-copyright"></i> Created by Dave Gandy, Font: <a href="http://scripts.sil.org/OFL" target="_blank">SIL OFL 1.1 License</a>, CSS: <a href="http://opensource.org/licenses/mit-license.html" target="_blank">MIT License</a>
694
695                         <i class="fa fa-circle"></i> <a href="http://www.iconsdb.com/soylent-red-icons/seo-performance-icon.html" target="_blank">IconsDB.com Icons</a>, Icons provided as CC0 1.0 Universal (CC0 1.0) Public Domain Dedication.
696
697                         <i class="fa fa-circle"></i> <a href="http://morrisjs.github.io/morris.js/" target="_blank">morris.js</a>,
698                         <i class="fa fa-copyright"></i> Copyright 2013, Olly Smith, <a href="http://morrisjs.github.io/morris.js/" target="_blank">Simplified BSD License</a>
699
700                         <i class="fa fa-circle"></i> <a href="http://raphaeljs.com/" target="_blank">Raphaël</a>,
701                         <i class="fa fa-copyright"></i> Copyright 2008, Dmitry Baranovskiy, <a href="http://raphaeljs.com/license.html" target="_blank">MIT License</a>
702
703                         <i class="fa fa-circle"></i> <a href="http://C3js.org/" target="_blank">C3</a>,
704                         <i class="fa fa-copyright"></i> Copyright 2013, Masayuki Tanaka, <a href="https://github.com/masayuki0812/c3/blob/master/LICENSE" target="_blank">MIT License</a>
705
706                         <i class="fa fa-circle"></i> <a href="http://D3js.org/" target="_blank">D3</a>,
707                         <i class="fa fa-copyright"></i> Copyright 2015, Mike Bostock, <a href="http://opensource.org/licenses/BSD-3-Clause" target="_blank">BSD License</a>
708
709                     </small>
710                 </div>
711             </div>
712         </div>
713     </div>
714
715     <div class="modal fade" id="welcomeModal" tabindex="-1" role="dialog" aria-labelledby="welcomeModalLabel">
716         <div class="modal-dialog modal-lg" role="document">
717             <div class="modal-content">
718                 <div class="modal-header">
719                     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
720                     <h4 class="modal-title" id="welcomeModalLabel">Welcome!</h4>
721                 </div>
722                 <div class="modal-body">
723                         <div class="p">
724                         <b><a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata</a></b> is the fastest way to visualize metrics. It is a resource efficient, highly optimized system for collecting and visualizing any type of real-time time series data, from CPU usage, disk activity, SQL queries, API calls, web site visitors, etc.
725                         </div>
726                         <div class="p">
727                         <b><a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata</a></b> tries to visualize the truth of <b>now</b>, in its <b>greatest detail</b>, so that you can get insights of what is happening now and what just happened, on your systems and applications.
728                         </div>
729                         <div class="p">
730                         To make a chart in <b><a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata</a></b>, you just need a <b>number</b>. Just a number you can read somehow. <b><a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata</a></b> will turn this number to a real time, interactive, web chart. For collecting these numbers, it supports <a href="https://github.com/firehol/netdata/wiki/External-Plugins" target="_blank">external plugins</a>, even <a href="https://github.com/firehol/netdata/wiki/General-Info---charts.d" target="_blank">shell</a> or <a href="https://github.com/firehol/netdata/wiki/General-Info---charts.d" target="_blank">node.js</a> plugins. Any computer program, in any language, that can print a few lines of text on its standard output, can be a netdata data collector.
731                         </div>
732                         <div class="p">
733                         <b><a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata</a></b> can embed charts everywhere, like this one <div data-netdata="system.cpu" data-dimensions="system" data-after="-120" data-width="25%" data-height="15px" data-chart-library="dygraph" data-dygraph-theme="sparkline" data-show-value-of-system-at="system.cpu.system.modal.1"></div> (my CPU system usage which is <span id="system.cpu.system.modal.1" style="display: inline-block; width: 40px; text-align: right;"></span>%),
734                         or this one <div data-netdata="ipv4.tcppackets" data-dimensions="received" data-after="-120" data-width="25%" data-height="15px" data-chart-library="dygraph" data-dygraph-theme="sparkline" data-show-value-of-received-at="ipv4.tcppackets.received.modal.1"></div> (my IPv4 received TCP packets, which are <span id="ipv4.tcppackets.received.modal.1" style="display: inline-block; width: 60px; text-align: right;"></span>/second).
735                         </div>
736                         <div class="p">
737                         You can have <b><a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata</a></b> charts on your site too. Just give it a <code>div</code> and a real time chart, zoomable and draggable will appear (try it even on these tiny ones - <b>drag</b> them to pan horizontally, <b>shift + drag</b> to zoom in, on <b>chrome shift + mouse wheel</b> to zoom in/out, <b>double click</b> on them to reset them - don't be afraid of <b><a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata</a></b> performance - <a href="https://github.com/firehol/netdata/wiki/Performance" target="_blank">a raspberry pi 2 can sustain 300 charts updates per second</a>!).
738                         </div>
739                         <div class="p">
740                         For more information please refer to the <b><a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata wiki</a></b>.
741                         </div>
742                 </div>
743                 <div class="modal-footer">
744                     <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
745                 </div>
746             </div>
747         </div>
748     </div>
749
750     <div class="modal fade" id="helpModal" tabindex="-1" role="dialog" aria-labelledby="helpModalLabel">
751         <div class="modal-dialog modal-lg" role="document">
752             <div class="modal-content">
753                 <div class="modal-header">
754                     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
755                     <h4 class="modal-title" id="helpModalLabel">Dashboard Help</h4>
756                 </div>
757                 <div class="modal-body">
758
759                     <h4>Dygraphs (line, area and stacked area charts)</h4>
760
761                     <!-- Nav tabs -->
762                     <ul class="nav nav-tabs" role="tablist">
763                         <li role="presentation" class="active"><a href="#help_mouse" aria-controls="help_mouse" role="tab" data-toggle="tab">Mouse Interface</a></li>
764                         <li role="presentation"><a href="#help_touch" aria-controls="help_touch" role="tab" data-toggle="tab">Touch Interface</a></li>
765                     </ul>
766
767                     <!-- Tab panes -->
768                     <div class="tab-content">
769                         <div role="tabpanel" class="tab-pane active" id="help_mouse">
770                             <div class="p">
771                                 <h4>Mouse Over / Hover</h4>
772                                 Mouse over on a chart to show, at its legend, the values for the timestamp under the mouse (the chart will also highlight the point at the chart).
773                                 <br/>
774                                 All the other visible charts will also show and highlight their values for the same timestamp.
775                             </div>
776                             <hr/>
777                             <div class="p">
778                                 <h4>Drag Chart Contents</h4>
779                                 Drag the contents of a chart to pan it horizontally.
780                                 <br/>
781                                 All the charts will follow soon after you let the chart alone (this little delay is by design: it speeds up your browser and lets you focus on what you are exploring).
782                                 <br/>
783                                 Once a chart is panned, auto refreshing stops for all charts. To enable it again, <b>double click</b> a panned chart.
784                             </div>
785                             <hr/>
786                             <div class="p">
787                                 <h4>Double Click</h4>
788                                 Double Click a chart to reset all the charts to their default auto-refreshing state.
789                             </div>
790                             <hr/>
791                             <div class="p">
792                                 <h4>SHIFT + Drag</h4>
793                                 While pressing the shift key, click on the contents of a chart and move the mouse to select an area, to zoom in. The other charts will follow too. Zooming is performed in two phases:
794                                 <ul>
795                                     <li>The already loaded chart contents are zoomed (low resolution)</li>
796                                     <li>New data are transferred from the netdata server, to refresh the chart with possibly more detail.</li>
797                                 </ul>
798                                 Once a chart is zoomed, auto refreshing stops for all charts. To enable it again, <b>double click</b> a zoomed chart.
799                             </div>
800                             <hr/>
801                             <div class="p">
802                                 <h4>SHIFT + Mouse Wheel <small>(does not work on firefox and IE/Edge)</small></h4>
803                                 While pressing the shift key and the mouse pointer is over the contents of a chart, scroll the mouse wheel to zoom in or out. This kind of zooming is aligned to center below the mouse pointer. The other charts will follow too.
804                                 <br/>
805                                 Once a chart is zoomed, auto refreshing stops for all charts. To enable it again, <b>double click</b> a zoomed chart.
806                             </div>
807                             <hr/>
808                             <div class="p">
809                                 <h4>Legend Operations</h4>
810                                 Click on the label or value of a dimension, will select / un-select this dimension.
811                                 <br/>
812                                 You can press any of the SHIFT or CONTROL keys and then click on legend labels or values, to select / un-select multiple dimensions.
813                             </div>
814                         </div>
815                         <div role="tabpanel" class="tab-pane" id="help_touch">
816                             <div class="p">
817                                 <h4>Single Tap</h4>
818                                 Single Tap on the contents of a chart to show, at its legend, the values for the timestamp tapped (the chart will also highlight the point at the chart).
819                                 <br/>
820                                 All the other visible charts will also show and highlight their values for the same timestamp.
821                             </div>
822                             <hr/>
823                             <div class="p">
824                                 <h4>Drag Chart Contents</h4>
825                                 Touch and Drag the contents of a chart to pan it horizontally.
826                                 <br/>
827                                 All the charts will follow soon after you let the chart alone (this little delay is by design: it speeds up your browser and lets you focus on what you are exploring).
828                                 <br/>
829                                 Once a chart is panned, auto refreshing stops for all charts. To enable it again, <b>double tap</b> a panned chart.
830                             </div>
831                             <hr/>
832                             <div class="p">
833                                 <h4>Double Tap</h4>
834                                 Double tap a chart to reset all the charts to their default auto-refreshing state.
835                             </div>
836                             <hr/>
837                             <div class="p">
838                                 <h4>Zoom <small>(does not work on firefox and IE/Edge)</small></h4>
839                                 With two fingers, zoom in or out.
840                                 <br/>
841                                 Once a chart is zoomed, auto refreshing stops for all charts. To enable it again, <b>double click</b> a zoomed chart.
842                             </div>
843                             <hr/>
844                             <div class="p">
845                                 <h4>Legend Operations</h4>
846                                 Tap on the label or value of a dimension, will select / un-select this dimension.
847                             </div>
848                         </div>
849                     </div>
850                 </div>
851                 <div class="modal-footer">
852                     <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
853                 </div>
854             </div>
855         </div>
856     </div>
857
858     <div class="modal fade" id="alarmsModal" tabindex="-1" role="dialog" aria-labelledby="alarmsModalLabel">
859         <div class="modal-dialog modal-lg" role="document">
860             <div class="modal-content">
861                 <div class="modal-header">
862                     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
863                     <h4 class="modal-title" id="alarmsModalLabel">netdata alarms</h4>
864                 </div>
865                 <div class="modal-body">
866                     <!-- Nav tabs -->
867                     <ul class="nav nav-tabs" role="tablist">
868                         <li role="presentation" class="active"><a href="#alarms_active" aria-controls="alarms_active" role="tab" data-toggle="tab">Active</a></li>
869                         <li role="presentation"><a href="#alarms_all" aria-controls="alarms_all" role="tab" data-toggle="tab">All</a></li>
870                         <li role="presentation"><a href="#alarms_log" aria-controls="alarms_log" role="tab" data-toggle="tab">Log</a></li>
871                     </ul>
872
873                     <!-- Tab panes -->
874                     <div class="tab-content">
875                         <div role="tabpanel" class="tab-pane active" id="alarms_active">
876                             loading...
877                         </div>
878                         <div role="tabpanel" class="tab-pane" id="alarms_all">
879                             loading...
880                         </div>
881                         <div role="tabpanel" class="tab-pane" id="alarms_log">
882                             loading...
883                         </div>
884                     </div>
885                 </div>
886                 <div class="modal-footer">
887                     <!-- <a href="#" onclick="alarmsUpdateModal(); return false;" type="button" class="btn btn-default">Update</a> -->
888                     <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
889                 </div>
890             </div>
891         </div>
892     </div>
893
894     <div class="modal fade" id="optionsModal" tabindex="-1" role="dialog" aria-labelledby="optionsModalLabel">
895         <div class="modal-dialog modal-lg" role="document">
896             <div class="modal-content">
897                 <div class="modal-header">
898                     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
899                     <h4 class="modal-title" id="optionsModalLabel">netdata dashboard options</h4>
900                 </div>
901                 <div class="modal-body">
902                     <center>
903                         <small style="color: #BBBBBB;">These are browser settings. Each viewer has its own. They do not affect the operation of your netdata server.
904                         <br/>
905                         Settings take effect immediately and are saved permanently to browser local storage (except the refresh on focus / always option).
906                         <br/>
907                         To reset all options (including charts sizes) to their defaults, click <a href="#" onclick="resetDashboardOptions(); return false;">here</a>.</small>
908                     </center>
909                     <div style="padding: 10px;"></div>
910
911                     <!-- Nav tabs -->
912                     <ul class="nav nav-tabs" role="tablist">
913                         <li role="presentation" class="active"><a href="#settings_performance" aria-controls="settings_performance" role="tab" data-toggle="tab">Performance</a></li>
914                         <li role="presentation"><a href="#settings_sync" aria-controls="settings_sync" role="tab" data-toggle="tab">Synchronization</a></li>
915                         <li role="presentation"><a href="#settings_visual" aria-controls="settings_visual" role="tab" data-toggle="tab">Visual</a></li>
916                     </ul>
917
918                     <!-- Tab panes -->
919                     <div class="tab-content">
920                         <div role="tabpanel" class="tab-pane active" id="settings_performance">
921                             <form id="optionsForm1" method="get" class="form-horizontal">
922                                 <div class="form-group">
923                                     <table>
924                                     <tr class="option-row">
925                                         <td class="option-control"><input id="stop_updates_when_focus_is_lost" type="checkbox" checked data-toggle="toggle" data-offstyle="danger" data-onstyle="success" data-on="On Focus" data-off="Always" data-width="110px"></td>
926                                         <td class="option-info"><strong>When to refresh the charts?</strong><br/>
927                                             <small>When set to <b>On Focus</b>, the charts will stop being updated if the page / tab does not have the focus of the user. When set to <b>Always</b>, the charts will always be refreshed. Set it to <b>On Focus</b> it to lower the CPU requirements of the browser (and extend the battery of laptops and tablets) when this page does not have your focus. Set to <b>Always</b> to work on another window (i.e. change the settings of something) and have the charts auto-refresh in this window.</small>
928                                         </td>
929                                         </tr>
930                                     <tr class="option-row">
931                                         <td class="option-control">
932                                         <input id="eliminate_zero_dimensions" type="checkbox" checked data-toggle="toggle" data-on="Non Zero" data-off="All" data-width="110px">
933                                         </td>
934                                         <td class="option-info"><strong>Which dimensions to show?</strong><br/>
935                                             <small>When set to <b>Non Zero</b>, dimensions that have all their values (within the current view) set to zero will not be transferred from the netdata server (except if all dimensions of the chart are zero, in which case this setting does nothing - all dimensions are transferred and shown). When set to <b>All</b>, all dimensions will always be shown. Set it to <b>Non Zero</b> to lower the data transferred between netdata and your browser, lower the CPU requirements of your browser (fewer lines to draw) and increase the focus on the legends (fewer entries at the legends).</small>
936                                         </td>
937                                         </tr>
938                                     <tr class="option-row">
939                                         <td class="option-control"><input id="destroy_on_hide" type="checkbox" data-toggle="toggle" data-on="Destroy" data-off="Hide" data-width="110px"></td>
940                                         <td class="option-info"><strong>How to handle hidden charts?</strong><br/>
941                                             <small>When set to <b>Destroy</b>, charts that are not in the current viewport of the browser (are above, or below the visible area of the page), will be destroyed and re-created if and when they become visible again. When set to <b>Hide</b>, the not-visible charts will be just hidden, to simplify the DOM and speed up your browser. Set it to <b>Destroy</b>, to lower the memory requirements of your browser. Set it to <b>Hide</b> for smoother page scrolling.</small>
942                                         </td>
943                                         </tr>
944                                     </table>
945                                 </div>
946                             </form>
947                         </div>
948                         <div role="tabpanel" class="tab-pane" id="settings_sync">
949                             <form id="optionsForm2" method="get" class="form-horizontal">
950                                 <div class="form-group">
951                                     <table>
952                                     <tr class="option-row">
953                                         <td class="option-control"><input id="parallel_refresher" type="checkbox" checked data-toggle="toggle" data-on="Parallel" data-off="Sequential" data-width="110px"></td>
954                                         <td class="option-info"><strong>Which chart refresh policy to use?</strong><br/>
955                                             <small>When set to <b>parallel</b>, visible charts are refreshed in parallel (all queries are sent to netdata server in parallel) and are rendered asynchronously. When set to <b>sequential</b> charts are refreshed one after another. Set it to parallel if your browser can cope with it (most modern browsers do), set it to sequential if you work on an older/slower computer.</small>
956                                         </td>
957                                         </tr>
958                                     <tr class="option-row" id="concurrent_refreshes_row">
959                                         <td class="option-control"></td>
960                                         <td class="option-info">
961                                             <table>
962                                             <tr class="option-row">
963                                             <td class="option-control">
964                                             <input id="concurrent_refreshes" type="checkbox" checked data-toggle="toggle" data-on="Resync" data-off="Best Effort" data-width="110px">
965                                             </td>
966                                             <td class="option-info">
967                                             <strong>Shall we re-sync chart refreshes?</strong><br/>
968                                             <small>When set to <b>Resync</b>, the dashboard will attempt to re-synchronize all the charts so that they are refreshed concurrently. When set to <b>Best Effort</b>, each chart may be refreshed with a little time difference to the others. Normally, the dashboard starts refreshing them in parallel, but depending on the speed of your computer and the network latencies, charts start having a slight time difference. Setting this to <b>Resync</b> will attempt to re-synchronize the charts on every update. Setting it to <b>Best Effort</b> may lower the pressure on your browser and the network.</small>
969                                             </td>
970                                             </tr>
971                                             </table>
972                                         </td>
973                                         </tr>
974                                     <tr class="option-row">
975                                         <td class="option-control"><input id="sync_selection" type="checkbox" checked data-toggle="toggle" data-on="Sync" data-off="Don't Sync" data-onstyle="success" data-offstyle="danger" data-width="110px"></td>
976                                         <td class="option-info"><strong>Sync hover selection on all charts?</strong><br/>
977                                             <small>When enabled, a selection on one chart will automatically select the same time on all other visible charts and the legends of all visible charts will be updated to show the selected values. When disabled, only the chart getting the user's attention will be selected. Enable it to get better insights of the data. Disable it if you are on a very slow computer that cannot actually do it.</small>
978                                         </td>
979                                         </tr>
980                                     <tr class="option-row">
981                                         <td class="option-control"><input id="sync_pan_and_zoom" type="checkbox" checked data-toggle="toggle"  data-on="Sync" data-off="Don't Sync" data-onstyle="success" data-offstyle="danger" data-width="110px"></td>
982                                         <td class="option-info"><strong>Sync pan and zoom on all charts?</strong><br/>
983                                             <small>When enabled, pan and zoom operations on a chart will be replicated to all charts (even the ones that are not currently visible - of course only when they will become visible). When disabled, pan and zoom operations will not be propagated to other charts.</small>
984                                         </td>
985                                         </tr>
986                                     </table>
987                                 </div>
988                             </form>
989                         </div>
990                         <div role="tabpanel" class="tab-pane" id="settings_visual">
991                             <form id="optionsForm3" method="get" class="form-horizontal">
992                                 <div class="form-group">
993                                     <table>
994                                     <tr class="option-row">
995                                         <td class="option-control"><input id="netdata_theme_control" type="checkbox" checked data-toggle="toggle" data-offstyle="danger" data-onstyle="success" data-on="Dark" data-off="White" data-width="110px"></td>
996                                         <td class="option-info"><strong>Which theme to use?</strong><br/>
997                                             <small>Netdata comes with two themes: <b>Dark</b> (the default) and <b>White</b>.
998                                             <br/>
999                                             <b>Switching this will reload the dashboard</b>.
1000                                             </small>
1001                                         </td>
1002                                         </tr>
1003                                     <tr class="option-row">
1004                                         <td class="option-control"><input id="show_help" type="checkbox" checked data-toggle="toggle" data-on="Help Me" data-off="No Help" data-width="110px"></td>
1005                                         <td class="option-info"><strong>Do you need help?</strong><br/>
1006                                             <small>Netdata can show some help in some areas to help you use the dashboard. If all these balloons bother you, disable them using this switch.
1007                                             <br/>
1008                                             <b>Switching this will reload the dashboard</b>.
1009                                             </small>
1010                                         </td>
1011                                         </tr>
1012                                     <tr class="option-row">
1013                                         <td class="option-control"><input id="pan_and_zoom_data_padding" type="checkbox" checked data-toggle="toggle"  data-on="Pad" data-off="Don't Pad" data-width="110px"></td>
1014                                         <td class="option-info"><strong>Enable data padding when panning and zooming?</strong><br/>
1015                                             <small>When set to <b>Pad</b> the charts will be padded with more data, both before and after the visible area, thus giving the impression the whole database is loaded. This padding will happen only after the first pan or zoom operation on the chart (initially all charts have only the visible data). When set to <b>Don't Pad</b> only the visible data will be transfered from the netdata server, even after the first pan and zoom operation.</small>
1016                                         </td>
1017                                         </tr>
1018                                     <tr class="option-row">
1019                                         <td class="option-control"><input id="smooth_plot" type="checkbox" checked data-toggle="toggle"  data-on="Smooth" data-off="Rough" data-width="110px"></td>
1020                                         <td class="option-info"><strong>Enable Bézier lines on charts?</strong><br/>
1021                                             <small>When set to <b>Smooth</b> the charts libraries that support it, will plot smooth curves instead of simple straight lines to connect the points.
1022                                             <br/>
1023                                             Keep in mind <a href="http://dygraphs.com" target="_blank">dygraphs</a>, the main charting library in netdata dashboards, can only smooth line charts. It cannot smooth area or stacked charts. When set to <b>Rough</b>, this setting can lower the CPU resources consumed by your browser.</small>
1024                                         </td>
1025                                         </tr>
1026                                     </table>
1027                                 </div>
1028                             </form>
1029                         </div>
1030                     </div>
1031                 </div>
1032                 <div class="modal-footer">
1033                     <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1034                 </div>
1035             </div>
1036         </div>
1037     </div>
1038
1039
1040     <div class="modal fade" id="updateModal" tabindex="-1" role="dialog" aria-labelledby="updateModalLabel">
1041         <div class="modal-dialog" role="document">
1042             <div class="modal-content">
1043                 <div class="modal-header">
1044                     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
1045                     <h4 class="modal-title" id="updateModalLabel">Update Check</h4>
1046                 </div>
1047                 <div class="modal-body">
1048                     Your netdata version: <b><code><span id="netdataVersion">Unknown</span></code></b>
1049                     <br/>
1050                     <div style="padding: 10px;"></div>
1051                     <div id="versionCheckLog">Not checked yet. Please press the Check Now button.</div>
1052                 </div>
1053                 <div class="modal-footer">
1054                     <a href="#" onclick="notifyForUpdate(true); return false;" type="button" class="btn btn-default">Check Now</a>
1055                     <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1056                 </div>
1057             </div>
1058         </div>
1059     </div>
1060
1061     <div class="modal fade" id="deleteRegistryModal" tabindex="-1" role="dialog" aria-labelledby="deleteRegistryModalLabel">
1062         <div class="modal-dialog" role="document">
1063             <div class="modal-content">
1064                 <div class="modal-header">
1065                     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
1066                     <h4 class="modal-title" id="deleteRegistryModalLabel">Delete <span id="deleteRegistryServerName"></span>?</h4>
1067                 </div>
1068                 <div class="modal-body">
1069                     You are about to delete, from your personal list of netdata servers, the following server:
1070                     <p style="text-align: center; padding-top: 10px; padding-bottom: 10px; line-height: 2;">
1071                     <b><span id="deleteRegistryServerName2"></span></b>
1072                     <br/>
1073                     <b><span id="deleteRegistryServerURL"></span></b>
1074                     </p>
1075                     Are you sure you want to do this?
1076                     <br/>
1077                     <div style="padding: 10px;"></div>
1078                     <small>Keep in mind, this server will be added back if and when you visit it again.</small>
1079                     <br/>
1080                     <div id="deleteRegistryResponse" style="display: block; width: 100%; text-align: center; padding-top: 20px;"></div>
1081                 </div>
1082                 <div class="modal-footer">
1083                     <button type="button" class="btn btn-success" data-dismiss="modal">keep it</button>
1084                     <a href="#" onclick="notifyForDeleteRegistry(true); return false;" type="button" class="btn btn-danger">delete it</a>
1085                 </div>
1086             </div>
1087         </div>
1088     </div>
1089
1090     <div class="modal fade" id="switchRegistryModal" tabindex="-1" role="dialog" aria-labelledby="switchRegistryModalLabel">
1091         <div class="modal-dialog" role="document">
1092             <div class="modal-content">
1093                 <div class="modal-header">
1094                     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
1095                     <h4 class="modal-title" id="switchRegistryModalLabel">Switch Netdata Registry Identity</h4>
1096                 </div>
1097                 <div class="modal-body">
1098                     You can copy and paste the following ID to all your browsers (e.g. work and home).
1099                     <br/>
1100                     All the browsers with the same ID will identify <b>you</b>, so please don't share this with others.
1101                     <p style="text-align: center; padding-top: 10px; padding-bottom: 10px; line-height: 2;">
1102                     <form action="#">
1103                     <input type="text" class="form-control" id="switchRegistryPersonGUID" placeholder="your personal ID" maxlength="36" autocomplete="off" style="text-align: center; font-size: 1.4em;">
1104                     </form>
1105                     </p>
1106                     Either copy this ID and paste it to another browser, or paste here the ID you have taken from another browser.
1107                     <p style="padding-top: 10px;"><small>
1108                         Keep in mind that:
1109                         <ul>
1110                             <li>when you switch ID, your previous ID will be lost forever - this is irreversible.</li>
1111                             <li>both IDs (your old and the new) must list this netdata at their personal lists.</li>
1112                             <li>both IDs have to be known by the registry: <b><span id="switchRegistryURL"></span></b>.</li>
1113                             <li>to get a new ID, just clear your browser cookies.</li>
1114                         </ul>
1115                     </small></p>
1116                     <div id="switchRegistryResponse" style="display: block; width: 100%; text-align: center; padding-top: 20px;"></div>
1117                 </div>
1118                 <div class="modal-footer">
1119                     <button type="button" class="btn btn-success" data-dismiss="modal">cancel</button>
1120                     <a href="#" onclick="notifyForSwitchRegistry(true); return false;" type="button" class="btn btn-danger">impersonate</a>
1121                 </div>
1122             </div>
1123         </div>
1124     </div>
1125
1126     <div class="modal fade" id="gotoServerModal" tabindex="-1" role="dialog" aria-labelledby="gotoServerModalLabel">
1127         <div class="modal-dialog" role="document">
1128             <div class="modal-content">
1129                 <div class="modal-header">
1130                     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
1131                     <h4 class="modal-title" id="gotoServerModalLabel"><span id="gotoServerName"></span></h4>
1132                 </div>
1133                 <div class="modal-body">
1134                     Checking known URLs for this server...
1135                     <div  style="padding-top: 20px;">
1136                         <table id="gotoServerList">
1137                         </table>
1138                     </div>
1139                     <p style="padding-top: 10px;"><small>
1140                         Checks may fail if you are viewing an HTTPS page and the server to be checked is HTTP only.
1141                     </small></p>
1142                     <div id="gotoServerResponse" style="display: block; width: 100%; text-align: center; padding-top: 20px;"></div>
1143                 </div>
1144                 <div class="modal-footer">
1145                     <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1146                 </div>
1147             </div>
1148         </div>
1149     </div>
1150
1151 <script type="text/javascript">
1152 var this_is_demo = null;
1153 function isdemo() {
1154     if(this_is_demo !== null) return this_is_demo;
1155     this_is_demo = false;
1156
1157     try {
1158         if(typeof document.location.hostname === 'string') {
1159             if(document.location.hostname.endsWith('.my-netdata.io') ||
1160                     document.location.hostname.endsWith('.mynetdata.io') ||
1161                     document.location.hostname.endsWith('.netdata.rocks') ||
1162                     document.location.hostname.endsWith('.firehol.org') ||
1163                     document.location.hostname.endsWith('.netdata.online'))
1164                     this_is_demo = true;
1165         }
1166     }
1167     catch(error) {
1168         ;
1169     }
1170
1171     return this_is_demo;
1172 }
1173
1174 if(isdemo()) {
1175     document.getElementById('masthead').style.display = 'block';
1176 }
1177
1178 function netdataURL(url) {
1179     if(typeof url === 'undefined')
1180         url = document.location.toString();
1181
1182     if(url.indexOf('#') !== -1)
1183         url = url.substring(0, url.indexOf('#'));
1184
1185     var hash = netdataHash();
1186
1187     // console.log('netdataURL: ' + url + hash);
1188
1189     return url + hash;
1190 }
1191
1192 function netdataReload(url) {
1193     var t = netdataURL(url);
1194     // console.log('netdataReload: ' + t);
1195     document.location = t;
1196
1197     // since we play with hash
1198     // this is needed to reload the page
1199     location.reload();
1200 }
1201
1202 var gotoServerValidateRemaining = 0;
1203 var gotoServerMiddleClick = false;
1204 var gotoServerStop = false;
1205 function gotoServerValidateUrl(id, guid, url) {
1206     var penaldy = 0;
1207     if(document.location.toString().startsWith('http://') && url.toString().startsWith('https://'))
1208             // we penalize https only if the current url is http
1209             // to allow the user walk through all its servers.
1210             penaldy = 500;
1211
1212     var finalURL = netdataURL(url);
1213
1214     setTimeout(function() {
1215         document.getElementById('gotoServerList').innerHTML += '<tr><td style="padding-left: 20px;"><a href="' + finalURL + '" target="_blank">' + url + '</a></td><td style="padding-left: 30px;"><code id="' + guid + '-' + id + '-status">checking...</code></td></tr>';
1216
1217         NETDATA.registry.hello(url, function(data) {
1218             if (data) {
1219                 // console.log('OK ' + id + ' URL: ' + url);
1220                 document.getElementById(guid + '-' + id + '-status').innerHTML = "OK";
1221
1222                 if(!gotoServerStop) {
1223                     gotoServerStop = true;
1224
1225                     if(gotoServerMiddleClick) {
1226                         window.open(finalURL, '_blank');
1227                         gotoServerMiddleClick = false;
1228                         document.getElementById('gotoServerResponse').innerHTML = '<b>Opening new window to ' + NETDATA.registry.machines[guid].name + '<br/><a href="' + finalURL + '">' + url + '</a></b><br/>(check your pop-up blocker if it fails)';
1229                     }
1230                     else
1231                         document.location = finalURL;
1232                 }
1233             }
1234             else {
1235                 document.getElementById(guid + '-' + id + '-status').innerHTML = "failed!";
1236                 gotoServerValidateRemaining--;
1237                 if(gotoServerValidateRemaining <= 0) {
1238                     gotoServerMiddleClick = false;
1239                     document.getElementById('gotoServerResponse').innerHTML = '<b>Sorry! I cannot find any operational URL for this server</b>';
1240                 }
1241             }
1242         });
1243     }, (id * 50) + penaldy);
1244 }
1245
1246 function gotoServerModalHandler(guid) {
1247     // console.log('goto server: ' + guid);
1248
1249     gotoServerStop = false;
1250     var len = NETDATA.registry.machines[guid].alternate_urls.length;
1251
1252     document.getElementById('gotoServerResponse').innerHTML = '';
1253     document.getElementById('gotoServerList').innerHTML = '';
1254     document.getElementById('gotoServerName').innerHTML = NETDATA.registry.machines[guid].name;
1255     $('#gotoServerModal').modal('show');
1256
1257     gotoServerValidateRemaining = len;
1258     while(len--)
1259         gotoServerValidateUrl(len, guid, NETDATA.registry.machines[guid].alternate_urls[len]);
1260
1261     return false;
1262 }
1263
1264 function gotoServerInit() {
1265     $(".registry_link").on('click', function(e) {
1266         if(e.which === 2) {
1267             e.preventDefault();
1268             gotoServerMiddleClick = true;
1269         }
1270         else {
1271             gotoServerMiddleClick = false;
1272         }
1273
1274         return true;
1275     });
1276 }
1277
1278 function switchRegistryModalHandler() {
1279     document.getElementById('switchRegistryPersonGUID').value = NETDATA.registry.person_guid;
1280     document.getElementById('switchRegistryURL').innerHTML = NETDATA.registry.server;
1281     document.getElementById('switchRegistryResponse').innerHTML = '';
1282     $('#switchRegistryModal').modal('show');
1283 }
1284
1285 function notifyForSwitchRegistry() {
1286     var n = document.getElementById('switchRegistryPersonGUID').value;
1287
1288     if(n !== '' && n.length === 36) {
1289         NETDATA.registry.switch(n, function(result) {
1290             if(result !== null) {
1291                 $('#switchRegistryModal').modal('hide');
1292                 NETDATA.registry.init();
1293             }
1294             else {
1295                 document.getElementById('switchRegistryResponse').innerHTML = "<b>Sorry! The registry rejected your request.</b>";
1296             }
1297         });
1298     }
1299     else
1300         document.getElementById('switchRegistryResponse').innerHTML = "<b>The ID you have entered is not a GUID.</b>";
1301 }
1302
1303 var deleteRegistryUrl = null;
1304 function deleteRegistryModalHandler(guid, name, url) {
1305     deleteRegistryUrl = url;
1306     document.getElementById('deleteRegistryServerName').innerHTML = name;
1307     document.getElementById('deleteRegistryServerName2').innerHTML = name;
1308     document.getElementById('deleteRegistryServerURL').innerHTML = url;
1309     document.getElementById('deleteRegistryResponse').innerHTML = '';
1310     $('#deleteRegistryModal').modal('show');
1311 }
1312
1313 function notifyForDeleteRegistry() {
1314     if(deleteRegistryUrl) {
1315         NETDATA.registry.delete(deleteRegistryUrl, function(result) {
1316             if(result !== null) {
1317                 deleteRegistryUrl = null;
1318                 $('#deleteRegistryModal').modal('hide');
1319                 NETDATA.registry.init();
1320             }
1321             else {
1322                 document.getElementById('deleteRegistryResponse').innerHTML = "<b>Sorry! this command was rejected by the registry server.</b>";
1323             }
1324         });
1325     }
1326 }
1327
1328 var options = {
1329     sparklines_registry: {},
1330     menus: {},
1331     submenu_names: {},
1332     data: null,
1333     hostname: 'netdata_server', // will be overwritten by the netdata server
1334     categories: new Array(),
1335     categories_idx: {},
1336     families: new Array(),
1337     families_idx: {},
1338
1339     chartsPerRow: 0,
1340     chartsMinWidth: 1450,
1341     chartsHeight: 180,
1342     sparklinesHeight: 60,
1343 };
1344
1345 // generate a sparkline
1346 // used in the documentation
1347 function sparkline(chart, dimension, units) {
1348     var key = chart + '.' + dimension;
1349
1350     if(typeof units === 'undefined')
1351         units = '';
1352
1353     if(typeof options.sparklines_registry[key] === 'undefined')
1354         options.sparklines_registry[key] = { count: 1 };
1355     else
1356         options.sparklines_registry[key].count++;
1357
1358     key = key + '.' + options.sparklines_registry[key].count;
1359
1360     var h = '<div data-netdata="' + chart + '" data-after="-120" data-width="25%" data-height="15px" data-chart-library="dygraph" data-dygraph-theme="sparkline" data-dimensions="' + dimension + '" data-show-value-of-' + dimension + '-at="' + key + '"></div> (<span id="' + key + '" style="display: inline-block; min-width: 50px; text-align: right;">X</span>' + units + ')';
1361
1362     return h;
1363 }
1364
1365 function chartsPerRow(total) {
1366     if(options.chartsPerRow === 0) {
1367         width = Math.floor(total / options.chartsMinWidth);
1368         if(width === 0) width = 1;
1369         return width;
1370     }
1371     else return options.chartsPerRow;
1372 }
1373
1374 function prioritySort(a, b) {
1375     if(a.priority < b.priority) return -1;
1376     if(a.priority > b.priority) return 1;
1377     if(a.name < b.name) return -1;
1378     return 1;
1379 }
1380
1381 function sortObjectByPriority(object) {
1382     var idx = {};
1383     var sorted = new Array();
1384
1385     for(var i in object) {
1386         if(typeof idx[i] === 'undefined') {
1387             idx[i] = object[i];
1388             sorted.push(i);
1389         }
1390     }
1391
1392     sorted.sort(function(a, b) {
1393         if(idx[a].priority < idx[b].priority) return -1;
1394         if(idx[a].priority > idx[b].priority) return 1;
1395         if(a < b) return -1;
1396         return 1;
1397     });
1398
1399     return sorted;
1400 }
1401
1402
1403 // ----------------------------------------------------------------------------
1404 // scroll to a section, without changing the browser history
1405
1406 function scrollToId(hash) {
1407     if(hash && hash != '') {
1408         var offset = $('#' + hash).offset();
1409         if(typeof offset !== 'undefined')
1410             $('html, body').animate({ scrollTop: offset.top }, 0);
1411     }
1412
1413     // we must return false to prevent the default action
1414     return false;
1415 }
1416
1417 // ----------------------------------------------------------------------------
1418
1419 function gaugeChart(title, width, dimensions, colors) {
1420     if(typeof colors === 'undefined')
1421         colors = '';
1422
1423     if(typeof dimensions === 'undefined')
1424         dimensions = '';
1425
1426     return '<div data-netdata="CHART_UNIQUE_ID"'
1427                             + ' data-dimensions="' + dimensions + '"'
1428                             + ' data-chart-library="gauge"'
1429                             + ' data-gauge-adjust="width"'
1430                             + ' data-title="' + title + '"'
1431                             + ' data-width="' + width + '"'
1432                             + ' data-before="0"'
1433                             + ' data-after="-CHART_DURATION"'
1434                             + ' data-points="CHART_DURATION"'
1435                             + ' data-colors="' + colors + '"'
1436                             + ' role="application"></div>';
1437 }
1438
1439 // ----------------------------------------------------------------------------
1440
1441 var menuData = {
1442     'system': {
1443         title: 'System Overview',
1444         icon: '<i class="fa fa-bookmark" aria-hidden="true"></i>',
1445         info: 'Overview of the key system metrics.'
1446     },
1447
1448     'ap': {
1449         title: 'Access Points',
1450         icon: '<i class="fa fa-wifi" aria-hidden="true"></i>',
1451         info: undefined
1452     },
1453
1454     'tc': {
1455         title: 'Quality of Service',
1456         icon: '<i class="fa fa-globe" aria-hidden="true"></i>',
1457         info: 'Netdata collects and visualizes tc class utilization using its <a href="https://github.com/firehol/netdata/blob/master/plugins.d/tc-qos-helper.sh" target="_blank">tc-helper plugin</a>. If you also use <a href="http://firehol.org/#fireqos" target="_blank">FireQOS</a> for setting up QoS, netdata automatically collects interface and class names. If your QoS configuration includes overheads calculation, the values shown here will include these overheads (the total bandwidth for the same interface as reported in the Network Interfaces section, will be lower than the total bandwidth reported here). Also, data collection may have a slight time difference compared to the interface (QoS data collection is implemented with a BASH script, so a shift in data collection of a few milliseconds should be justified).'
1458     },
1459
1460     'net': {
1461         title: 'Network Interfaces',
1462         icon: '<i class="fa fa-share-alt" aria-hidden="true"></i>',
1463         info: 'Per network interface statistics collected from <code>/proc/net/dev</code>.'
1464     },
1465
1466     'ipv4': {
1467         title: 'IPv4 Networking',
1468         icon: '<i class="fa fa-cloud" aria-hidden="true"></i>',
1469         info: undefined
1470     },
1471
1472     'ipv6': {
1473         title: 'IPv6 Networking',
1474         icon: '<i class="fa fa-cloud" aria-hidden="true"></i>',
1475         info: undefined
1476     },
1477
1478     'ipvs': {
1479         title: 'IP Virtual Server',
1480         icon: '<i class="fa fa-eye" aria-hidden="true"></i>',
1481         info: undefined
1482     },
1483
1484     'netfilter': {
1485         title: 'Firewall (netfilter)',
1486         icon: '<i class="fa fa-shield" aria-hidden="true"></i>',
1487         info: undefined
1488     },
1489
1490     'cpu': {
1491         title: 'CPUs',
1492         icon: '<i class="fa fa-bolt" aria-hidden="true"></i>',
1493         info: undefined
1494     },
1495
1496     'mem': {
1497         title: 'Memory',
1498         icon: '<i class="fa fa-bolt" aria-hidden="true"></i>',
1499         info: undefined
1500     },
1501
1502     'disk': {
1503         title: 'Disks',
1504         icon: '<i class="fa fa-folder" aria-hidden="true"></i>',
1505         info: 'Charts with performance information for all the system disks. Special care has been given to present disk performance metrics in a way compatible with <code>iostat -x</code>. netdata by default prevents rendering performance charts for individual partitions and unmounted virtual disks. Disabled charts can still be enabled by altering the relative settings in the netdata configuration file.'
1506     },
1507
1508     'sensors': {
1509         title: 'Sensors',
1510         icon: '<i class="fa fa-leaf" aria-hidden="true"></i>',
1511         info: undefined
1512     },
1513
1514     'nfsd': {
1515         title: 'File Server (nfsd)',
1516         icon: '<i class="fa fa-folder-open" aria-hidden="true"></i>',
1517         info: undefined
1518     },
1519
1520     'apps': {
1521         title: 'Applications',
1522         icon: '<i class="fa fa-heartbeat" aria-hidden="true"></i>',
1523         info: 'Per application statistics are collected using netdata\'s <code>apps.plugin</code>. This plugin walks through the entire <code>/proc</code> filesystem and aggregates statistics for applications of interest, defined in <code>/etc/netdata/apps_groups.conf</code> (the default is <a href="https://github.com/firehol/netdata/blob/master/conf.d/apps_groups.conf" target="_blank">here</a>). The plugin internally builds a process tree (much like <code>ps fax</code> does), and groups processes together (evaluating both child and parent processes) so that the result is always a chart with a predefined set of dimensions (of course, only application groups found running are reported). The reported values are compatible with <code>top</code>, although the netdata plugin counts also the resources of exited children (unlike <code>top</code> which shows only the resources of the currently running processes). So for processes like shell scripts, the reported values include the resources used by the commands these scripts run within each timeframe.',
1524         height: 1.5
1525     },
1526
1527     'users': {
1528         title: 'Users',
1529         icon: '<i class="fa fa-user" aria-hidden="true"></i>',
1530         info: 'Per user statistics are collected using netdata\'s <code>apps.plugin</code>. This plugin walks through the entire <code>/proc</code> filesystem and aggregates statistics per user. The reported values are compatible with <code>top</code>, although the netdata plugin counts also the resources of exited children (unlike <code>top</code> which shows only the resources of the currently running processes). So for processes like shell scripts, the reported values include the resources used by the commands these scripts run within each timeframe.',
1531         height: 1.5
1532     },
1533
1534     'groups': {
1535         title: 'User Groups',
1536         icon: '<i class="fa fa-users" aria-hidden="true"></i>',
1537         info: 'Per user group statistics are collected using netdata\'s <code>apps.plugin</code>. This plugin walks through the entire <code>/proc</code> filesystem and aggregates statistics per user group. The reported values are compatible with <code>top</code>, although the netdata plugin counts also the resources of exited children (unlike <code>top</code> which shows only the resources of the currently running processes). So for processes like shell scripts, the reported values include the resources used by the commands these scripts run within each timeframe.',
1538         height: 1.5
1539     },
1540
1541     'netdata': {
1542         title: 'Netdata Monitoring',
1543         icon: '<i class="fa fa-bar-chart" aria-hidden="true"></i>',
1544         info: undefined
1545     },
1546
1547     'example': {
1548         title: 'Example Charts',
1549         info: undefined
1550     },
1551
1552     'cgroup': {
1553         title: '',
1554         icon: '<i class="fa fa-th" aria-hidden="true"></i>',
1555         info: undefined
1556     },
1557
1558     'cgqemu': {
1559         title: '',
1560         icon: '<i class="fa fa-th-large" aria-hidden="true"></i>',
1561         info: undefined
1562     },
1563
1564     'memcached': {
1565         title: 'memcached',
1566         icon: '<i class="fa fa-database" aria-hidden="true"></i>',
1567         info: undefined
1568     },
1569
1570     'mysql': {
1571         title: 'MySQL',
1572         icon: '<i class="fa fa-database" aria-hidden="true"></i>',
1573         info: undefined
1574     },
1575
1576     'redis': {
1577         title: 'Redis',
1578         icon: '<i class="fa fa-database" aria-hidden="true"></i>',
1579         info: undefined
1580     },
1581
1582     'ipfs': {
1583         title: 'IPFS',
1584         icon: '<i class="fa fa-folder-open" aria-hidden="true"></i>',
1585         info: undefined
1586     },
1587
1588     'phpfpm': {
1589         title: 'PHP-FPM',
1590         icon: '<i class="fa fa-eye" aria-hidden="true"></i>',
1591         info: undefined,
1592     },
1593
1594     'postfix': {
1595         title: 'postfix',
1596         icon: '<i class="fa fa-envelope" aria-hidden="true"></i>',
1597         info: undefined,
1598     },
1599
1600     'nginx': {
1601         title: 'nginx',
1602         icon: '<i class="fa fa-eye" aria-hidden="true"></i>',
1603         info: undefined,
1604     },
1605
1606     'apache': {
1607         title: 'Apache',
1608         icon: '<i class="fa fa-eye" aria-hidden="true"></i>',
1609         info: undefined,
1610     },
1611
1612     'named': {
1613         title: 'named',
1614         icon: '<i class="fa fa-tag" aria-hidden="true"></i>',
1615         info: undefined
1616     },
1617
1618     'squid': {
1619         title: 'squid',
1620         icon: '<i class="fa fa-exchange" aria-hidden="true"></i>',
1621         info: undefined
1622     },
1623
1624     'nut': {
1625         title: 'UPS',
1626         icon: '<i class="fa fa-battery-half" aria-hidden="true"></i>',
1627         info: undefined
1628     },
1629
1630     'smawebbox': {
1631         title: 'Solar Power',
1632         icon: '<i class="fa fa-sun-o" aria-hidden="true"></i>',
1633         info: undefined
1634     },
1635
1636     'snmp': {
1637         title: 'SNMP',
1638         icon: '<i class="fa fa-random" aria-hidden="true"></i>',
1639         info: undefined
1640     }
1641 };
1642
1643 var submenuData = {
1644     'mem.ksm': {
1645         title: 'Memory Deduper',
1646         info: 'Kernel Same-page Merging (KSM) performance monitoring, read from several files in <code>/sys/kernel/mm/ksm/</code>. KSM is a memory-saving de-duplication feature in the Linux kernel (since version 2.6.32). The KSM daemon ksmd periodically scans those areas of user memory which have been registered with it, looking for pages of identical content which can be replaced by a single write-protected page (which is automatically copied if a process later wants to update its content). KSM was originally developed for use with KVM (where it was known as Kernel Shared Memory), to fit more virtual machines into physical memory, by sharing the data common between them.  But it can be useful to any application which generates many instances of the same data.'
1647     },
1648
1649     'netfilter.conntrack': {
1650         title: 'Connection Tracker',
1651         info: 'Netfilter Connection Tracker performance monitoring, read from <code>/proc/net/stat/nf_conntrack</code>. The connection tracker keeps track of all connections of the machine, inbound and outbound. It works by keeping a database with all open connections, tracking network and address translation and connection expectations.'
1652     },
1653
1654     'netfilter.nfacct': {
1655         title: 'Bandwidth Accounting',
1656         info: 'The following information is read using the <code>nfacct.plugin</code>.'
1657     },
1658
1659     'netfilter.synproxy': {
1660         title: 'DDoS Protection',
1661         info: 'DDoS Protection performance monitoring read from <code>/proc/net/stat/synproxy</code>. <a href="https://github.com/firehol/firehol/wiki/Working-with-SYNPROXY" target="_blank">SYNPROXY</a> is a TCP SYN packets proxy. It is used to protect any TCP server (like a web server) from SYN floods and similar DDoS attacks. It is a netfilter module, in the Linux kernel (since version 3.12). It is optimized to handle millions of packets per second utilizing all CPUs available without any concurrency locking between the connections. It can be used for any kind of TCP traffic (even encrypted), since it does not interfere with the content itself.'
1662     }
1663 };
1664
1665 //
1666 // chartData works on the context of a chart
1667 // Its purpose is to set:
1668 //
1669 // info: the text above the charts
1670 // heads: the representation of the chart at the top the subsection (second level menu)
1671 // mainheads: the representation of the chart at the top of the section (first level menu)
1672 // colors: the dimension colors of the chart (the default colors are appended)
1673 // height: the ratio of the chart height relative to the default
1674 //
1675 var chartData = {
1676     'system.cpu': {
1677         info: 'Total CPU utilization (all cores). 100% here means there is no CPU idle time at all. You can get per core usage at the <a href="#cpu">CPUs</a> section and per application usage at the <a href="#apps">Applications Monitoring</a> section.<br/>Keep an eye on <b>iowait</b> ' + sparkline('system.cpu', 'iowait', '%') + '. If it is constantly high, your disks are a bottleneck and they slow your system down.<br/>Another important metric worth monitoring, is <b>softirq</b> ' + sparkline('system.cpu', 'softirq', '%') + '. A constantly high percentage of softirq may indicate network drivers issues.'
1678     },
1679
1680     'system.load': {
1681         info: 'Current system load, i.e. the number of processes using CPU or waiting for system resources (usually CPU and disk). The 3 metrics refer to 1, 5 and 15 minute averages. Linux calculates this once every 5 seconds. Netdata reads them from <code>/proc/loadavg</code>. For more information check <a href="https://en.wikipedia.org/wiki/Load_(computing)" target="_blank">this wikipedia article</a>',
1682         height: 0.7
1683     },
1684
1685     'system.io': {
1686         info: 'Total Disk I/O, for all disks, read from <code>/proc/vmstat</code>. You can get detailed information about each disk at the <a href="#disk">Disks</a> section and per application Disk usage at the <a href="#apps">Applications Monitoring</a> section.'
1687     },
1688
1689     'system.swapio': {
1690         info: 'Total Swap I/O, read from <code>/proc/vmstat</code>. (netdata measures both <code>in</code> and <code>out</code>. If either of them is not shown in the chart, it is because it is zero - you can change the page settings to always render all the available dimensions on all charts).'
1691     },
1692
1693     'system.pgfaults': {
1694         info: 'Total page faults, read from <code>/proc/vmstat</code>. <b>Major page faults</b> indicates that the system is using its swap. You can find which applications use the swap at the <a href="#apps">Applications Monitoring</a> section.'
1695     },
1696
1697     'system.entropy': {
1698         colors: '#CC22AA',
1699         info: '<a href="https://en.wikipedia.org/wiki/Entropy_(computing)" target="_blank">Entropy</a>, read from <code>/proc/sys/kernel/random/entropy_avail</code>, is like a pool of random numbers that are mainly used in cryptography. It is advised that the pool remains always <a href="https://blog.cloudflare.com/ensuring-randomness-with-linuxs-random-number-generator/" target="_blank">above 200</a>. If the pool of entropy gets empty, you risk your security to be predictable and you should install a user-space random numbers generating daemon, like <a href="http://www.issihosts.com/haveged/" target="_blank">haveged</a>, to keep the pool in healthy levels.'
1700     },
1701
1702     'system.forks': {
1703         colors: '#5555DD',
1704         info: 'The number of new processes created per second, read from <code>/proc/stat</code>.'
1705     },
1706
1707     'system.intr': {
1708         colors: '#DD5555',
1709         info: 'Total number of CPU interrupts, read from <code>/proc/stat</code>. Check <code>system.interrupts</code> that gives more detail about each interrupt and also the <a href="#cpu">CPUs</a> section where interrupts are analyzed per CPU core.'
1710     },
1711
1712     'system.interrupts': {
1713         info: 'CPU interrupts in detail, read from <code>/proc/interrupts</code>. At the <a href="#cpu">CPUs</a> section, interrupts are analyzed per CPU core.'
1714     },
1715
1716     'system.softirqs': {
1717         info: 'CPU softirqs in detail, read from <code>/proc/softirqs</code>. At the <a href="#cpu">CPUs</a> section, softirqs are analyzed per CPU core.'
1718     },
1719
1720     'system.processes': {
1721         info: 'System processes, read from <code>/proc/stat</code>. <b>Blocked</b> are processes that are willing to execute but they cannot, e.g. because they wait for disk activity.'
1722     },
1723
1724     'system.active_processes': {
1725         info: 'All system active processes, read from <code>/proc/loadavg</code>.'
1726     },
1727
1728     'system.ctxt': {
1729         info: '<a href="https://en.wikipedia.org/wiki/Context_switch" target="_blank">Context Switches</a>, read from <code>/proc/stat</code>, is the switching of the CPU from one process, task or thread to another. If there are many processes or threads willing to execute and very few CPU cores available to handle them, the system is making more context switching to balance the CPU resources among them. The whole process is computationally intensive. The more the context switches, the slower the system gets.'
1730     },
1731
1732     'system.idlejitter': {
1733         colors: '#5555AA',
1734         info: 'Idle jitter is calculated by netdata. A thread is spawned that requests to sleep for a few microseconds. When the system wakes it up, it measures how many microseconds have passed. The difference between the requested and the actual duration of the sleep, is the <b>idle jitter</b>. This number is useful in real-time environments, where CPU jitter can affect the quality of the service (like VoIP media gateways).'
1735     },
1736
1737     'system.ipv4': {
1738         info: 'Total IPv4 Traffic, read from <code>/proc/net/netstat</code>.'
1739     },
1740
1741     'system.ipv6': {
1742         info: 'Total IPv6 Traffic, read from <code>/proc/net/snmp6</code>.'
1743     },
1744
1745     'system.ram': {
1746         info: 'System memory, read from <code>/proc/meminfo</code>.'
1747     },
1748
1749     'system.swap': {
1750         info: 'System swap memory, read from <code>/proc/meminfo</code>.'
1751     },
1752
1753     // ------------------------------------------------------------------------
1754     // MEMORY
1755
1756     'mem.ksm_savings': {
1757         heads: [
1758             gaugeChart('Saved', '12%', 'savings', '#0099CC')
1759         ]
1760     },
1761
1762     'mem.ksm_ratios': {
1763         heads: [
1764             function(id) {
1765                 return  '<div data-netdata="' + id + '"'
1766                     + ' data-gauge-max-value="100"'
1767                     + ' data-chart-library="gauge"'
1768                     + ' data-title="Savings"'
1769                     + ' data-units="percentage %"'
1770                     + ' data-gauge-adjust="width"'
1771                     + ' data-width="12%"'
1772                     + ' data-before="0"'
1773                     + ' data-after="-CHART_DURATION"'
1774                     + ' data-points="CHART_DURATION"'
1775                     + ' role="application"></div>';
1776             }
1777         ]
1778     },
1779
1780     'mem.committed': {
1781         colors: NETDATA.colors[3]
1782     },
1783
1784     // ------------------------------------------------------------------------
1785     // APPS
1786
1787     'apps.cpu': {
1788         height: 2.0
1789     },
1790
1791     'apps.preads': {
1792         height: 2.0
1793     },
1794
1795     'apps.pwrites': {
1796         height: 2.0
1797     },
1798
1799     // ------------------------------------------------------------------------
1800     // USERS
1801
1802     'users.cpu': {
1803         height: 2.0
1804     },
1805
1806     'users.preads': {
1807         height: 2.0
1808     },
1809
1810     'users.pwrites': {
1811         height: 2.0
1812     },
1813
1814     // ------------------------------------------------------------------------
1815     // GROUPS
1816
1817     'groups.cpu': {
1818         height: 2.0
1819     },
1820
1821     'groups.preads': {
1822         height: 2.0
1823     },
1824
1825     'groups.pwrites': {
1826         height: 2.0
1827     },
1828
1829     // ------------------------------------------------------------------------
1830     // NETWORK QoS
1831
1832     'tc.qos': {
1833         heads: [
1834             function(id) {
1835                 if(id.match(/.*-ifb$/))
1836                     return gaugeChart('Inbound', '12%', '', '#5555AA');
1837                 else
1838                     return gaugeChart('Outbound', '12%', '', '#AA9900');
1839             }
1840         ]
1841     },
1842
1843     // ------------------------------------------------------------------------
1844     // NETWORK INTERFACES
1845
1846     'net.net': {
1847         heads: [
1848             gaugeChart('Received', '12%', 'received'),
1849             gaugeChart('Sent', '12%', 'sent')
1850         ]
1851     },
1852
1853     // ------------------------------------------------------------------------
1854     // NETFILTER
1855
1856     'netfilter.sockets': {
1857         colors: '#88AA00',
1858         heads: [
1859             gaugeChart('Active Connections', '12%', '', '#88AA00')
1860         ]
1861     },
1862
1863     'netfilter.new': {
1864         heads: [
1865             gaugeChart('New Connections', '12%', 'new', '#5555AA')
1866         ]
1867     },
1868
1869     // ------------------------------------------------------------------------
1870     // DISKS
1871
1872     'disk.util': {
1873         colors: '#FF5588',
1874         heads: [
1875             gaugeChart('Utilization', '12%', '', '#FF5588')
1876         ],
1877         info: 'Disk Utilization measures the amount of time the disk was busy with something. This is not related to its performance. 100% means that the Linux kernel always had an outstanding operation on the disk. Keep in mind that depending on the underlying technology of the disk, 100% here may or may not be an indication of congestion.'
1878     },
1879
1880     'disk.backlog': {
1881         colors: '#0099CC',
1882         info: 'Backlog is an indication of the duration of pending disk operations. On every I/O event the Linux kernel is multiplying the time spent doing I/O since the last update of this field with the number of pending operations. While not accurate, this metric can provide an indication of the expected completion time of the operations in progress.'
1883     },
1884
1885     'disk.io': {
1886         heads: [
1887             gaugeChart('Read', '12%', 'reads'),
1888             gaugeChart('Write', '12%', 'writes')
1889         ],
1890         info: 'Amount of data transferred to and from disk.'
1891     },
1892
1893     'disk.ops': {
1894         info: 'Completed disk I/O operations. Keep in mind the number of operations requested might be higher, since the Linux kernel is able to merge adjacent to each other (see merged operations chart).'
1895     },
1896
1897     'disk.qops': {
1898         info: 'I/O operations currently in progress. This metric is a snapshot - it is not an average over the last interval.'
1899     },
1900
1901     'disk.iotime': {
1902         height: 0.5,
1903         info: 'The sum of the duration of all completed I/O operations. This number can exceed the interval if the disk is able to execute I/O operations in parallel.'
1904     },
1905     'disk.mops': {
1906         height: 0.5,
1907         info: 'The number of merged disk operations. The Linux kernel is able to merge adjacent I/O operations, for example two 4KB reads can become one 8KB read before given to disk.'
1908     },
1909     'disk.svctm': {
1910         height: 0.5,
1911         info: 'The average service time for completed I/O operations. This metric is calculated using the total busy time of the disk and the number of completed operations. If the disk is able to execute multiple parallel operations the reporting average service time will be misleading.'
1912     },
1913     'disk.avgsz': {
1914         height: 0.5,
1915         info: 'The average I/O operation size.'
1916     },
1917     'disk.await': {
1918         height: 0.5,
1919         info: 'The average time for I/O requests issued to the device to be served. This includes the time spent by the requests in queue and the time spent servicing them.'
1920     },
1921
1922     'disk.space': {
1923         info: 'Disk space utilization. reserved for root is automatically reserved by the system to prevent the root user from getting out of space.'
1924     },
1925     'disk.inodes': {
1926         info: 'inodes (or index nodes) are filesystem objects (e.g. files and directories). On many types of file system implementations, the maximum number of inodes is fixed at filesystem creation, limiting the maximum number of files the filesystem can hold. It is possible for a device to run out of inodes. When this happens, new files cannot be created on the device, even though there may be free space available.'
1927     },
1928
1929     'mysql.net': {
1930         info: 'The amount of data sent to mysql clients (<strong>out</strong>) and received from mysql clients (<strong>in</strong>).'
1931     },
1932
1933     // ------------------------------------------------------------------------
1934     // MYSQL
1935
1936     'mysql.queries': {
1937         info: 'The number of statements executed by the server.<ul>' +
1938         '<li><strong>queries</strong> counts the statements executed within stored SQL programs.</li>' +
1939         '<li><strong>questions</strong> counts the statements sent to the mysql server by mysql clients.</li>' +
1940         '<li><strong>slow queries</strong> counts the number of statements that took more than <a href="http://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_long_query_time" target="_blank">long_query_time</a> seconds to be executed.' +
1941         ' For more information about slow queries check the mysql <a href="http://dev.mysql.com/doc/refman/5.7/en/slow-query-log.html" target="_blank">slow query log</a>.</li>' +
1942         '</ul>'
1943     },
1944
1945     'mysql.handlers': {
1946         info: 'Usage of the internal handlers of mysql. This chart provides very good insights of what the mysql server is actually doing.' +
1947         ' (if the chart is not showing all these dimensions it is because they are zero - set <strong>Which dimensions to show?</strong> to <strong>All</strong> from the dashboard settings, to render even the zero values)<ul>' +
1948         '<li><strong>commit</strong>, the number of internal <a href="http://dev.mysql.com/doc/refman/5.7/en/commit.html" target="_blank">COMMIT</a> statements.</li>' +
1949         '<li><strong>delete</strong>, the number of times that rows have been deleted from tables.</li>' +
1950         '<li><strong>prepare</strong>, a counter for the prepare phase of two-phase commit operations.</li>' +
1951         '<li><strong>read first</strong>, the number of times the first entry in an index was read. A high value suggests that the server is doing a lot of full index scans; e.g. <strong>SELECT col1 FROM foo</strong>, with col1 indexed.</li>' +
1952         '<li><strong>read key</strong>, the number of requests to read a row based on a key. If this value is high, it is a good indication that your tables are properly indexed for your queries.</li>' +
1953         '<li><strong>read next</strong>, the number of requests to read the next row in key order. This value is incremented if you are querying an index column with a range constraint or if you are doing an index scan.</li>' +
1954         '<li><strong>read prev</strong>, the number of requests to read the previous row in key order. This read method is mainly used to optimize <strong>ORDER BY ... DESC</strong>.</li>' +
1955         '<li><strong>read rnd</strong>, the number of requests to read a row based on a fixed position. A high value indicates you are doing a lot of queries that require sorting of the result. You probably have a lot of queries that require MySQL to scan entire tables or you have joins that do not use keys properly.</li>' +
1956         '<li><strong>read rnd next</strong>, the number of requests to read the next row in the data file. This value is high if you are doing a lot of table scans. Generally this suggests that your tables are not properly indexed or that your queries are not written to take advantage of the indexes you have.</li>' +
1957         '<li><strong>rollback</strong>, the number of requests for a storage engine to perform a rollback operation.</li>' +
1958         '<li><strong>savepoint</strong>, the number of requests for a storage engine to place a savepoint.</li>' +
1959         '<li><strong>savepoint rollback</strong>, the number of requests for a storage engine to roll back to a savepoint.</li>' +
1960         '<li><strong>update</strong>, the number of requests to update a row in a table.</li>' +
1961         '<li><strong>write</strong>, the number of requests to insert a row in a table.</li>' +
1962         '</ul>'
1963     },
1964
1965     'mysql.table_locks': {
1966         info: 'MySQL table locks counters: <ul>' +
1967         '<li><strong>immediate</strong>, the number of times that a request for a table lock could be granted immediately.</li>' +
1968         '<li><strong>waited</strong>, the number of times that a request for a table lock could not be granted immediately and a wait was needed. If this is high and you have performance problems, you should first optimize your queries, and then either split your table or tables or use replication.</li>' +
1969         '</ul>'
1970     },
1971
1972     // ------------------------------------------------------------------------
1973     // APACHE
1974
1975     'apache.connections': {
1976         colors: NETDATA.colors[4],
1977         mainheads: [
1978             gaugeChart('Connections', '12%', '', NETDATA.colors[4])
1979         ]
1980     },
1981
1982     'apache.requests': {
1983         colors: NETDATA.colors[0],
1984         mainheads: [
1985             gaugeChart('Requests', '12%', '', NETDATA.colors[0])
1986         ]
1987     },
1988
1989     'apache.net': {
1990         colors: NETDATA.colors[3],
1991         mainheads: [
1992             gaugeChart('Bandwidth', '12%', '', NETDATA.colors[3])
1993         ]
1994     },
1995
1996     'apache.workers': {
1997         mainheads: [
1998             function(id) {
1999                 return  '<div data-netdata="' + id + '"'
2000                     + ' data-dimensions="busy"'
2001                     + ' data-append-options="percentage"'
2002                     + ' data-gauge-max-value="100"'
2003                     + ' data-chart-library="gauge"'
2004                     + ' data-title="Workers Utilization"'
2005                     + ' data-units="percentage %"'
2006                     + ' data-gauge-adjust="width"'
2007                     + ' data-width="12%"'
2008                     + ' data-before="0"'
2009                     + ' data-after="-CHART_DURATION"'
2010                     + ' data-points="CHART_DURATION"'
2011                     + ' role="application"></div>';
2012             }
2013         ]
2014     },
2015
2016     'apache.bytesperreq': {
2017         colors: NETDATA.colors[3],
2018         height: 0.5
2019     },
2020
2021     'apache.reqpersec': {
2022         colors: NETDATA.colors[4],
2023         height: 0.5
2024     },
2025
2026     'apache.bytespersec': {
2027         colors: NETDATA.colors[6],
2028         height: 0.5
2029     },
2030
2031
2032     // ------------------------------------------------------------------------
2033     // NGINX
2034
2035     'nginx.connections': {
2036         colors: NETDATA.colors[4],
2037         mainheads: [
2038             gaugeChart('Connections', '12%', '', NETDATA.colors[4])
2039         ]
2040     },
2041
2042     'nginx.requests': {
2043         colors: NETDATA.colors[0],
2044         mainheads: [
2045             gaugeChart('Requests', '12%', '', NETDATA.colors[0])
2046         ]
2047     },
2048
2049     // ------------------------------------------------------------------------
2050     // NETDATA
2051
2052     'netdata.response_time': {
2053         info: 'The netdata API response time measures the time netdata needed to serve requests. This time includes everything, from the reception of the first byte of a request, to the dispatch of the last byte of its reply, therefore it includes all network latencies involved (i.e. a client over a slow network will influence these metrics).'
2054     }
2055 };
2056
2057 function anyAttribute(obj, attr, key, def) {
2058     if(typeof obj[key] !== 'undefined') {
2059         if(typeof obj[key][attr] !== 'undefined')
2060             return obj[key][attr];
2061     }
2062     return def;
2063 }
2064
2065 function anyAttributeTitle(obj, attr, key, def) {
2066     if(typeof obj[key] !== 'undefined') {
2067         if(typeof obj[key][attr] !== 'undefined')
2068             return obj[key][attr];
2069     }
2070
2071     var r = def.replace(/_/g, ' ');
2072
2073     return r;
2074 }
2075
2076 function menuTitle(chart) {
2077     if(typeof chart.menu_pattern !== 'undefined') {
2078         return anyAttributeTitle(menuData, 'title', chart.menu_pattern, chart.menu_pattern).toString()
2079                 + ' ' + chart.type.slice(-(chart.type.length - chart.menu_pattern.length - 1)).toString();
2080     }
2081
2082     return anyAttributeTitle(menuData, 'title', chart.menu, chart.menu);
2083 }
2084
2085 function menuIcon(chart) {
2086     if(typeof chart.menu_pattern !== 'undefined')
2087         return anyAttribute(menuData, 'icon', chart.menu_pattern, '<i class="fa fa-puzzle-piece" aria-hidden="true"></i>').toString();
2088
2089     return anyAttribute(menuData, 'icon', chart.menu, '<i class="fa fa-puzzle-piece" aria-hidden="true"></i>');
2090 }
2091
2092 function menuInfo(menu) {
2093     return anyAttribute(menuData, 'info', menu, null);
2094 }
2095
2096 function menuHeight(menu, relative) {
2097     return anyAttribute(menuData, 'height', menu, 1.0) * relative;
2098 }
2099
2100 function submenuTitle(menu, submenu) {
2101     var key = menu + '.' + submenu;
2102     var title = anyAttributeTitle(submenuData, 'title', key, submenu);
2103     if(title.length > 30) {
2104         var a = title.substring(0, 13);
2105         var b = title.substring(title.length - 13, title.length);
2106         return a + '...' + b;
2107     }
2108     return title;
2109 }
2110
2111 function submenuInfo(menu, submenu) {
2112     var key = menu + '.' + submenu;
2113     return anyAttribute(submenuData, 'info', key, null);
2114 }
2115
2116 function submenuHeight(menu, submenu, relative) {
2117     var key = menu + '.' + submenu;
2118     return anyAttribute(submenuData, 'height', key, 1.0) * relative;
2119 }
2120
2121
2122 function chartInfo(id) {
2123     if(typeof chartData[id] !== 'undefined' && typeof chartData[id].info !== 'undefined')
2124         return '<div class="chart-message netdata-chart-alignment" role="document">' + chartData[id].info + '</div>';
2125     else
2126         return '';
2127 }
2128
2129 function chartHeight(id, def) {
2130     if(typeof chartData[id] !== 'undefined' && typeof chartData[id].height !== 'undefined')
2131         return def * chartData[id].height;
2132     else
2133         return def;
2134 }
2135
2136
2137 // ----------------------------------------------------------------------------
2138
2139 // enrich the data structure returned by netdata
2140 // to reflect our menu system and content
2141 function enrichChartData(chart) {
2142     var tmp = chart.type.split('_')[0];
2143
2144     switch(tmp) {
2145         case 'ap':
2146         case 'net':
2147         case 'disk':
2148             chart.menu = tmp;
2149             break;
2150
2151         case 'cgroup':
2152             chart.menu = chart.type;
2153             if(chart.id.match(/.*[\._\/-:]qemu[\._\/-:]*/) || chart.id.match(/.*[\._\/-:]kvm[\._\/-:]*/))
2154                 chart.menu_pattern = 'cgqemu';
2155             else
2156                 chart.menu_pattern = 'cgroup';
2157             break;
2158
2159         case 'apache':
2160         case 'exim':
2161         case 'memcached':
2162         case 'mysql':
2163         case 'named':
2164         case 'nginx':
2165         case 'nut':
2166         case 'phpfpm':
2167         case 'postfix':
2168         case 'redis':
2169         case 'ipfs':
2170         case 'smawebbox':
2171         case 'squid':
2172         case 'snmp':
2173         case 'tomcat':
2174             chart.menu = chart.type;
2175             chart.menu_pattern = tmp;
2176             break;
2177
2178         case 'tc':
2179             chart.menu = tmp;
2180
2181             // find a name for this device from fireqos info
2182             // we strip '_(in|out)' or '(in|out)_'
2183             if(typeof options.submenu_names[chart.family] === 'undefined' || options.submenu_names[chart.family] === chart.family) {
2184                 var n = chart.name.split('.')[1];
2185                 if(n.endsWith('_in'))
2186                     options.submenu_names[chart.family] = n.slice(0, n.lastIndexOf('_in'));
2187                 else if(n.endsWith('_out'))
2188                     options.submenu_names[chart.family] = n.slice(0, n.lastIndexOf('_out'));
2189                 else if(n.startsWith('in_'))
2190                     options.submenu_names[chart.family] = n.slice(3, n.length);
2191                 else if(n.startsWith('out_'))
2192                     options.submenu_names[chart.family] = n.slice(4, n.length);
2193             }
2194
2195             // increase the priority of IFB devices
2196             // to have inbound appear before outbound
2197             if(chart.id.match(/.*-ifb$/))
2198                 chart.priority--;
2199
2200             break;
2201
2202         default:
2203             chart.menu = chart.type;
2204             break;
2205     }
2206
2207     chart.submenu = chart.family;
2208 }
2209
2210 // ----------------------------------------------------------------------------
2211
2212 function name2id(s) {
2213     return s
2214         .replace(/ /g, '_')
2215         .replace(/\(/g, '_')
2216         .replace(/\)/g, '_')
2217         .replace(/\./g, '_')
2218         .replace(/\//g, '_');
2219 }
2220
2221 function headMain(charts, duration) {
2222     var head = '';
2223
2224     if(typeof charts['system.swap'] !== 'undefined')
2225         head += '<div style="margin-right: 10px;" data-netdata="system.swap"'
2226         + ' data-dimensions="free"'
2227         + ' data-append-options="percentage"'
2228         + ' data-chart-library="easypiechart"'
2229         + ' data-title="Free Swap"'
2230         + ' data-units="%"'
2231         + ' data-easypiechart-max-value="100"'
2232         + ' data-width="8%"'
2233         + ' data-before="0"'
2234         + ' data-after="-' + duration.toString() + '"'
2235         + ' data-points="' + duration.toString() + '"'
2236         + ' data-colors="#DD4400"'
2237         + ' role="application"></div>';
2238
2239     if(typeof charts['system.io'] !== 'undefined') {
2240         head += '<div style="margin-right: 10px;" data-netdata="system.io"'
2241         + ' data-dimensions="in"'
2242         + ' data-chart-library="easypiechart"'
2243         + ' data-title="Disk Read"'
2244         + ' data-width="10%"'
2245         + ' data-before="0"'
2246         + ' data-after="-' + duration.toString() + '"'
2247         + ' data-points="' + duration.toString() + '"'
2248         + ' role="application"></div>';
2249
2250         head += '<div style="margin-right: 10px;" data-netdata="system.io"'
2251         + ' data-dimensions="out"'
2252         + ' data-chart-library="easypiechart"'
2253         + ' data-title="Disk Write"'
2254         + ' data-width="10%"'
2255         + ' data-before="0"'
2256         + ' data-after="-' + duration.toString() + '"'
2257         + ' data-points="' + duration.toString() + '"'
2258         + ' role="application"></div>';
2259     }
2260
2261     if(typeof charts['system.cpu'] !== 'undefined')
2262         head += '<div data-netdata="system.cpu"'
2263         + ' data-chart-library="gauge"'
2264         + ' data-title="CPU"'
2265         + ' data-units="%"'
2266         + ' data-gauge-max-value="100"'
2267         + ' data-width="18%"'
2268         + ' data-after="-' + duration.toString() + '"'
2269         + ' data-points="' + duration.toString() + '"'
2270         + ' data-colors="' + NETDATA.colors[12] + '"'
2271         + ' role="application"></div>';
2272
2273     if(typeof charts['system.ipv4'] !== 'undefined') {
2274         head += '<div style="margin-right: 10px;" data-netdata="system.ipv4"'
2275         + ' data-dimensions="received"'
2276         + ' data-chart-library="easypiechart"'
2277         + ' data-title="IPv4 Inbound"'
2278         + ' data-width="10%"'
2279         + ' data-before="0"'
2280         + ' data-after="-' + duration.toString() + '"'
2281         + ' data-points="' + duration.toString() + '"'
2282         + ' role="application"></div>';
2283
2284         head += '<div style="margin-right: 10px;" data-netdata="system.ipv4"'
2285         + ' data-dimensions="sent"'
2286         + ' data-chart-library="easypiechart"'
2287         + ' data-title="IPv4 Outbound"'
2288         + ' data-width="10%"'
2289         + ' data-before="0"'
2290         + ' data-after="-' + duration.toString() + '"'
2291         + ' data-points="' + duration.toString() + '"'
2292         + ' role="application"></div>';
2293     }
2294     else if(typeof charts['system.ipv6'] !== 'undefined') {
2295         head += '<div style="margin-right: 10px;" data-netdata="system.ipv6"'
2296         + ' data-dimensions="received"'
2297         + ' data-chart-library="easypiechart"'
2298         + ' data-title="IPv6 Inbound"'
2299         + ' data-units="kbps"'
2300         + ' data-width="10%"'
2301         + ' data-before="0"'
2302         + ' data-after="-' + duration.toString() + '"'
2303         + ' data-points="' + duration.toString() + '"'
2304         + ' role="application"></div>';
2305
2306         head += '<div style="margin-right: 10px;" data-netdata="system.ipv6"'
2307         + ' data-dimensions="sent"'
2308         + ' data-chart-library="easypiechart"'
2309         + ' data-title="IPv6 Outbound"'
2310         + ' data-units="kbps"'
2311         + ' data-width="10%"'
2312         + ' data-before="0"'
2313         + ' data-after="-' + duration.toString() + '"'
2314         + ' data-points="' + duration.toString() + '"'
2315         + ' role="application"></div>';
2316     }
2317
2318     if(typeof charts['system.ram'] !== 'undefined')
2319         head += '<div style="margin-right: 10px;" data-netdata="system.ram"'
2320         + ' data-dimensions="cached|free"'
2321         + ' data-append-options="percentage"'
2322         + ' data-chart-library="easypiechart"'
2323         + ' data-title="Available RAM"'
2324         + ' data-units="%"'
2325         + ' data-easypiechart-max-value="100"'
2326         + ' data-width="8%"'
2327         + ' data-after="-' + duration.toString() + '"'
2328         + ' data-points="' + duration.toString() + '"'
2329         + ' data-colors="' + NETDATA.colors[7] + '"'
2330         + ' role="application"></div>';
2331
2332     return head;
2333 }
2334
2335 function generateHeadCharts(type, chart, duration) {
2336     var head = '';
2337     var hcharts = anyAttribute(chartData, type, chart.context, []);
2338     if(hcharts.length > 0) {
2339         var hi = 0, hlen = hcharts.length;
2340         while(hi < hlen) {
2341             if(typeof hcharts[hi] === 'function')
2342                 head += hcharts[hi](chart.id).replace('CHART_DURATION', duration.toString()).replace('CHART_UNIQUE_ID', chart.id);
2343             else
2344                 head += hcharts[hi].replace('CHART_DURATION', duration.toString()).replace('CHART_UNIQUE_ID', chart.id);
2345             hi++;
2346         }
2347     }
2348     return head;
2349 }
2350
2351 function renderPage(menus, data) {
2352     var div = document.getElementById('charts_div');
2353     var pcent_width = Math.floor(100 / chartsPerRow($(div).width()));
2354
2355     // find the proper duration for per-second updates
2356     var duration = Math.round(($(div).width() * pcent_width / 100 * data.update_every / 3) / 60) * 60;
2357     var html = '';
2358     var sidebar = '<ul class="nav dashboard-sidenav" data-spy="affix" id="sidebar_ul">';
2359     var mainhead = headMain(data.charts, duration);
2360
2361     // sort the menus
2362     var main = sortObjectByPriority(menus);
2363     var i = 0, len = main.length;
2364     while(i < len) {
2365         var menu = main[i++];
2366
2367         // generate an entry at the main menu
2368
2369         var menuid = name2id(menu);
2370         sidebar += '<li class=""><a href="#' + menuid + '" onClick="return scrollToId(\'' + menuid + '\');">' + menus[menu].icon + ' ' + menus[menu].title + '</a><ul class="nav">';
2371         html += '<div role="section"><div role="sectionhead"><h1 id="' + menuid + '" role="heading">' + menus[menu].title + '</h1></div><div id="menu_' + menuid + '" role="document">';
2372
2373         if(menus[menu].info !== null)
2374             html += menus[menu].info;
2375
2376         // console.log(' >> ' + menu + ' (' + menus[menu].priority + '): ' + menus[menu].title);
2377
2378         var shtml = '';
2379         var mhead = '<div class="netdata-chart-row">' + mainhead;
2380         mainhead = '';
2381
2382         // sort the submenus of this menu
2383         var sub = sortObjectByPriority(menus[menu].submenus);
2384         var si = 0, slen = sub.length;
2385         while(si < slen) {
2386             var submenu = sub[si++];
2387
2388             // generate an entry at the submenu
2389             var submenuid = name2id(menu + '_' + submenu);
2390             sidebar += '<li class><a href="#' + submenuid + '" onClick="return scrollToId(\'' + submenuid + '\');">' + menus[menu].submenus[submenu].title + '</a></li>';
2391             shtml += '<div class="netdata-group-container" id="submenu_' + submenuid + '" style="display: inline-block; width: ' + pcent_width.toString() + '%"><h2 id="' + submenuid + '" class="netdata-chart-alignment" role="heading">' + menus[menu].submenus[submenu].title + '</h2>';
2392
2393             if(menus[menu].submenus[submenu].info !== null)
2394                 shtml += '<div class="chart-message netdata-chart-alignment" role="document">' + menus[menu].submenus[submenu].info + '</div>';
2395
2396             var head = '<div class="netdata-chart-row">';
2397             var chtml = '';
2398
2399             // console.log('    \------- ' + submenu + ' (' + menus[menu].submenus[submenu].priority + '): ' + menus[menu].submenus[submenu].title);
2400
2401             // sort the charts in this submenu of this menu
2402             menus[menu].submenus[submenu].charts.sort(prioritySort);
2403             var ci = 0, clen = menus[menu].submenus[submenu].charts.length;
2404             while(ci < clen) {
2405                 var chart = menus[menu].submenus[submenu].charts[ci++];
2406
2407                 // generate the submenu heading charts
2408                 mhead += generateHeadCharts('mainheads', chart, duration);
2409                 head += generateHeadCharts('heads', chart, duration);
2410
2411                 // generate the chart
2412                 chtml += chartInfo(chart.context) + '<div data-netdata="' + chart.id + '"'
2413                     + ' data-width="' + pcent_width.toString() + '%"'
2414                     + ' data-height="' + chartHeight(chart.context, options.chartsHeight).toString() + 'px"'
2415                     + ' data-before="0"'
2416                     + ' data-after="-' + duration.toString() + '"'
2417                     + ' data-id="' + name2id(options.hostname + '/' + chart.id) + '"'
2418                     + ' data-colors="' + anyAttribute(chartData, 'colors', chart.context, '') + '"'
2419                     + ' role="application"></div>';
2420
2421                 // console.log('         \------- ' + chart.id + ' (' + chart.priority + '): ' + chart.context  + ' height: ' + menus[menu].submenus[submenu].height);
2422             }
2423
2424             head += '</div>';
2425             shtml += head + chtml + '</div>';
2426         }
2427
2428         mhead += '</div>';
2429         sidebar += '</ul></li>';
2430         html += mhead + shtml + '</div></div><hr role="separator"/>';
2431     }
2432
2433     sidebar += '</ul>';
2434     div.innerHTML = html;
2435     document.getElementById('sidebar').innerHTML = sidebar;
2436     finalizePage();
2437 }
2438
2439 function renderChartsAndMenu(data) {
2440     var menus = options.menus;
2441     var charts = data.charts;
2442
2443     for(var c in charts) {
2444         enrichChartData(charts[c]);
2445
2446         // create the menu
2447         if(typeof menus[charts[c].menu] === 'undefined') {
2448             menus[charts[c].menu] = {
2449                 priority: charts[c].priority,
2450                 submenus: {},
2451                 title: menuTitle(charts[c]),
2452                 icon: menuIcon(charts[c]),
2453                 info: menuInfo(charts[c].menu),
2454                 height: menuHeight(charts[c].menu, options.chartsHeight)
2455             };
2456         }
2457
2458         if(charts[c].priority < menus[charts[c].menu].priority)
2459             menus[charts[c].menu].priority = charts[c].priority;
2460
2461         // create the submenu
2462         if(typeof menus[charts[c].menu].submenus[charts[c].submenu] === 'undefined') {
2463             menus[charts[c].menu].submenus[charts[c].submenu] = {
2464                 priority: charts[c].priority,
2465                 charts: new Array(),
2466                 title: null,
2467                 info: submenuInfo(charts[c].menu, charts[c].submenu),
2468                 height: submenuHeight(charts[c].menu, charts[c].submenu, menus[charts[c].menu].height)
2469             };
2470         }
2471
2472         if(charts[c].priority < menus[charts[c].menu].submenus[charts[c].submenu].priority)
2473             menus[charts[c].menu].submenus[charts[c].submenu].priority = charts[c].priority;
2474
2475         // index the chart in the menu/submenu
2476         menus[charts[c].menu].submenus[charts[c].submenu].charts.push(charts[c]);
2477     }
2478
2479     // propagate the descriptive subname given to QoS
2480     // to all the other submenus with the same name
2481     for(var m in menus) {
2482         for(var s in menus[m].submenus) {
2483             // set the family using a name
2484             if(typeof options.submenu_names[s] !== 'undefined') {
2485                 menus[m].submenus[s].title = s + ' (' + options.submenu_names[s] + ')';
2486             }
2487             else {
2488                 menus[m].submenus[s].title = submenuTitle(m, s);
2489             }
2490         }
2491     }
2492
2493     renderPage(menus, data);
2494 }
2495
2496 // ----------------------------------------------------------------------------
2497
2498 function alarmsUpdateModal() {
2499     var active = '<h3>Raised Alarms</h3><table class="table">';
2500     var all = '<h3>All Running Alarms</h3><div class="panel-group" id="alarms_all_accordion" role="tablist" aria-multiselectable="true">';
2501     var log = '<h3>Alarm Log</h3><table class="table"><tr><th>When</th><th>Chart</th><th>Alarm</th><th>Status</th>';
2502     var footer = '<hr/><a href="https://github.com/firehol/netdata/wiki/Generating-Badges" target="_blank">netdata badges</a> refresh automatically. Their color indicates the state of the alarm: <span style="color: #e05d44"><b>&nbsp;red&nbsp;</b></span> is critical, <span style="color:#fe7d37"><b>&nbsp;orange&nbsp;</b></span> is warning, <span style="color: #4c1"><b>&nbsp;bright green&nbsp;</b></span> is ok, <span style="color: #9f9f9f"><b>&nbsp;light grey&nbsp;</b></span> is undefined (i.e. no data or no status), <span style="color: #000"><b>&nbsp;black&nbsp;</b></span> is not initialized. You can copy and paste their URLs to embed them in any web page.';
2503
2504     NETDATA.alarms.get('all', function(data) {
2505         options.alarm_families = new Array();
2506
2507         alarmsCallback(data);
2508
2509         if(data === null) {
2510             document.getElementById('alarms_active').innerHTML =
2511                     document.getElementById('alarms_all').innerHTML =
2512                             document.getElementById('alarms_log').innerHTML =
2513                                     'failed to load alarm data!';
2514             return;
2515         }
2516
2517         function frequency_text(seconds, sfx) {
2518             if(seconds === 0)
2519                 return 'now';
2520
2521             var suffix = '';
2522             if(seconds < 0) {
2523                 seconds = -seconds;
2524                 if(sfx) suffix = '&nbsp;ago';
2525             }
2526
2527             var hours = Math.floor(seconds / 3600);
2528             seconds -= (hours * 3600);
2529
2530             var minutes = Math.floor(seconds / 60);
2531             seconds -= (minutes * 60);
2532
2533             var txt = '';
2534             
2535             if(hours > 1) txt += hours.toString() + '&nbsp;hours';
2536             else if(hours === 1) txt += hours.toString() + '&nbsp;hour';
2537
2538             if(hours > 0 && minutes > 0 && seconds == 0)
2539                 txt += '&nbsp;and&nbsp;';
2540             else if(hours > 0 && minutes > 0 && seconds > 0)
2541                 txt += ',&nbsp;';
2542
2543             if(minutes > 1) txt += minutes.toString() + '&nbsp;minutes';
2544             else if(minutes === 1) txt += minutes.toString() + '&nbsp;minute';
2545
2546             if((minutes > 0 || minutes > 0) && seconds > 0)
2547                 txt += '&nbsp;and&nbsp;';
2548
2549             if(seconds > 1) txt += seconds.toString() + '&nbsp;seconds';
2550             else if(seconds === 1) txt += seconds.toString() + '&nbsp;second';
2551
2552             return txt + suffix;
2553         }
2554
2555         function alarm_lookup_explain(alarm, chart) {
2556             var dimensions = ' of all values ';
2557
2558             if(chart.dimensions.length > 1)
2559                 dimensions = ' of the sum of all dimensions ';
2560
2561             if(typeof alarm.lookup_dimensions !== 'undefined') {
2562                 var d = alarm.lookup_dimensions.replace('|', ',');
2563                 var x = d.split(',');
2564                 if(x.length > 1)
2565                     dimensions = 'of the sum of dimensions <code>' + alarm.lookup_dimensions + '</code> ';
2566                 else
2567                     dimensions = 'of all values of dimension <code>' + alarm.lookup_dimensions + '</code> ';
2568             }
2569
2570             return '<code>' + alarm.lookup_method + '</code> '
2571                 + dimensions + ', of chart <code>' + alarm.chart + '</code>'
2572                 + ', starting <code>' + frequency_text(alarm.lookup_after + alarm.lookup_before, true) + '</code> and up to <code>' + frequency_text(alarm.lookup_before, true) + '</code>'
2573                 + ((alarm.lookup_options)?(', with options <code>' + alarm.lookup_options.replace(' ', ',&nbsp;') + '</code>'):'')
2574                 + '.';
2575         }
2576
2577         function alarm_to_html(alarm, full) {
2578             var chart = options.data.charts[alarm.chart];
2579
2580             var html = '<tr><td class="text-center" style="vertical-align:middle" width="40%"><b>' + alarm.chart + '</b><br/>&nbsp;<br/><embed src="' + NETDATA.alarms.server + '/api/v1/badge.svg?chart=' + alarm.chart + '&alarm=' + alarm.name + '&refresh=auto" type="image/svg+xml" height="20" /><br/>&nbsp;<br/><span style="font-size: 18px">' + alarm.info + '</span><br/>&nbsp;<br/>role: <b>' + alarm.recipient + '</b></td>'
2581                 + '<td><table class="table">'
2582                 + ((typeof alarm.warn !== 'undefined')?('<tr><td width="10%" style="text-align:right">warning&nbsp;when</td><td><span style="font-family: monospace; color:#fe7d37; font-weight: bold;">' + alarm.warn + '</span></td></tr>'):'')
2583                 + ((typeof alarm.crit !== 'undefined')?('<tr><td width="10%" style="text-align:right">critical&nbsp;when</td><td><span style="font-family: monospace; color: #e05d44; font-weight: bold;">' + alarm.crit + '</span></td></tr>'):'');
2584
2585             if(full === true) {
2586                     html += ((typeof alarm.lookup_after !== 'undefined')?('<tr><td width="10%" style="text-align:right">db&nbsp;lookup</td><td>' + alarm_lookup_explain(alarm, chart) + '</td></tr>'):'')
2587                     + ((typeof alarm.calc !== 'undefined')?('<tr><td width="10%" style="text-align:right">calculation</td><td><span style="font-family: monospace;">' + alarm.calc + '</span></td></tr>'):'')
2588                     + ((chart.green !== null)?('<tr><td width="10%" style="text-align:right">green&nbsp;threshold</td><td><code>' + chart.green + ' ' + chart.units + '</code></td></tr>'):'')
2589                     + ((chart.red !== null)?('<tr><td width="10%" style="text-align:right">red&nbsp;threshold</td><td><code>' + chart.red + ' ' + chart.units + '</code></td></tr>'):'');
2590             }
2591
2592             html += '<tr><td width="10%" style="text-align:right">check&nbsp;every</td><td>' + frequency_text(alarm.update_every) + '</td></tr>'
2593                 + '<tr><td width="10%" style="text-align:right">execute</td><td><span style="font-family: monospace;">' + alarm.exec + '</span></td></tr>'
2594                 + '<tr><td width="10%" style="text-align:right">source</td><td><span style="font-family: monospace;">' + alarm.source + '</span></td></tr>'
2595                 + '</table></td></tr>';
2596
2597             return html;
2598         }
2599
2600         function alarm_family_show(id) {
2601             var html = '<table class="table">';
2602             var family = options.alarm_families[id];
2603             var len = family.arr.length;
2604             while(len--) {
2605                 var alarm = family.arr[len];
2606                 html += alarm_to_html(alarm, true);
2607             }
2608             html += '</table>';
2609
2610             $('#alarm_all_' + id.toString()).html(html);
2611         }
2612
2613         // find the proper family of each alarm
2614         var now = new Date().getTime();
2615         var x;
2616         var count_active = 0;
2617         var count_all = 0;
2618         var families = {};
2619         var families_sort = new Array();
2620         for(x in data.alarms) {
2621             var alarm = data.alarms[x];
2622             var family = alarm.family;
2623
2624             // find the chart
2625             var chart = options.data.charts[alarm.chart];
2626             if(typeof chart === 'undefined')
2627                 chart = options.data.charts_by_name[alarm.chart];
2628
2629             // not found - this should never happen!
2630             if(typeof chart === 'undefined') {
2631                 console.log('WARNING: alarm ' + x + ' is linked to chart ' + alarm.chart + ', which is not found in the list of chart got from the server.');
2632                 chart = { priority: 9999999 };
2633             }
2634             else if(typeof chart.menu !== 'undefined' && typeof chart.submenu !== 'undefined')
2635                 // the family based on the chart
2636                 family = chart.menu + ' - ' + chart.submenu;
2637
2638             if(typeof families[family] === 'undefined') {
2639                 families[family] = {
2640                     name: family,
2641                     arr: new Array(),
2642                     priority: chart.priority
2643                 };
2644
2645                 families_sort.push(families[family]);
2646             }
2647
2648             if(chart.priority < families[family].priority)
2649                 families[family].priority = chart.priority;
2650
2651             families[family].arr.push(alarm);
2652         }
2653
2654         // sort the families, like the dashboard menu does
2655         var families_sorted = families_sort.sort(function (a, b) {
2656             if (a.priority > b.priority) return -1;
2657             if (a.priority < b.priority) return 1;
2658             if (a.name < b.name) return 1;
2659             if (a.name > b.name) return -1;
2660             return 0;
2661         });
2662
2663         var fc = 0;
2664         var len = families_sorted.length;
2665         while(len--) {
2666             var family = families_sorted[len].name;
2667             var active_family_added = false;
2668             var expanded = 'true';
2669             var collapsed = '';
2670             var cin = 'in';
2671
2672             if(fc !== 0) {
2673                 all += "</table></div></div></div>";
2674                 expanded = 'false';
2675                 collapsed = 'class="collapsed"'
2676                 cin = '';
2677             }
2678
2679             all += '<div class="panel panel-default"><div class="panel-heading" role="tab" id="alarm_all_heading_' + fc.toString() + '"><h4 class="panel-title"><a ' + collapsed + ' role="button" data-toggle="collapse" data-parent="#alarms_all_accordion" href="#alarm_all_' + fc.toString() + '" aria-expanded="' + expanded + '" aria-controls="alarm_all_' + fc.toString() + '">' + family.toString() + '</a></h4></div><div id="alarm_all_' + fc.toString() + '" class="panel-collapse collapse ' + cin + '" role="tabpanel" aria-labelledby="alarm_all_heading_' + fc.toString() + '" data-alarm-id="' + fc.toString() + '"><div class="panel-body" id="alarm_all_body_' + fc.toString() + '">';
2680
2681             options.alarm_families[fc] = families[family];
2682
2683             fc++;
2684
2685             var arr = families[family].arr;
2686             var c = arr.length;
2687             while(c--) {
2688                 var alarm = arr[c];
2689                 if(alarm.status === 'WARNING' || alarm.status === 'CRITICAL') {
2690                     if(!active_family_added) {
2691                         active_family_added = true;
2692                         active += '<tr><th class="text-center" colspan="2"><h4>' + family + '</h4></th></tr>';
2693                     }
2694                     count_active++;
2695                     active += alarm_to_html(alarm, false);
2696                 }
2697
2698                 count_all++;
2699             }
2700         }
2701         active += "</table>";
2702         if(families_sorted.length > 0) all += "</div></div></div>";
2703         all += "</div>";
2704
2705         if(!count_active)
2706             active += "<h4>Everything is normal. No raised alarms.</h4>";
2707         else
2708             active += footer;
2709
2710         if(!count_all)
2711             all += "<h4>No alarms are running in this system.</h4>";
2712         else
2713             all += footer;
2714
2715         document.getElementById('alarms_active').innerHTML = active;
2716         document.getElementById('alarms_all').innerHTML = all;
2717
2718         if(families_sorted.length > 0) alarm_family_show(0);
2719
2720         // register bootstrap events
2721         $('#alarms_all_accordion').on('show.bs.collapse', function (d) {
2722             var target = $(d.target);
2723             var id = $(target).data('alarm-id');
2724             alarm_family_show(id);
2725         });
2726         $('#alarms_all_accordion').on('hidden.bs.collapse', function (d) {
2727             var target = $(d.target);
2728             var id = $(target).data('alarm-id');
2729             $('#alarm_all_' + id.toString()).html('');
2730         });
2731
2732         NETDATA.alarms.get_log(function(data) {
2733             if(data === null) {
2734                 document.getElementById('alarms_log').innerHTML =
2735                         'failed to load alarm data!';
2736                 return;
2737             }
2738
2739             var i = 0;
2740             var len = data.length;
2741             if(len > 50) len = 50;
2742             while(i < len) {
2743                 var time = new Date(data[i].when * 1000);
2744                 log += '<tr><td>' + time.toLocaleDateString() + ' ' + time.toLocaleTimeString() + '</td><td>' + data[i].chart + '</td><td>' + data[i].name + '</td><td>' + data[i].status + '</td></tr>';
2745                 i++;
2746             }
2747             log += "</table>";
2748
2749             if(i == 0)
2750                 log += "<h4>No alarms have been logged in this system.</h4>";
2751
2752             document.getElementById('alarms_log').innerHTML = log;
2753         })
2754     });
2755 }
2756
2757 function alarmsCallback(data) {
2758     var count = 0;
2759     for(x in data.alarms) {
2760         var alarm = data.alarms[x];
2761         if(alarm.status === 'WARNING' || alarm.status === 'CRITICAL')
2762             count++;
2763     }
2764
2765     if(count > 0)
2766         document.getElementById('alarms_count_badge').innerHTML = count.toString();
2767     else
2768         document.getElementById('alarms_count_badge').innerHTML = '';
2769 }
2770
2771 function downloadAllCharts(netdata_url) {
2772     if(typeof netdata_url === 'undefined' || netdata_url === null)
2773         netdata_url = NETDATA.serverDefault;
2774
2775     NETDATA.pause(function() {
2776         $("#loadOverlay").css("display","none");
2777
2778         NETDATA.alarms.callback = alarmsCallback;
2779
2780         // download all the charts the server knows
2781         NETDATA.chartRegistry.downloadAll(netdata_url, function(data) {
2782
2783             if(data !== null) {
2784                 options.hostname = data.hostname;
2785                 options.data = data;
2786
2787                 // create a chart_by_name index
2788                 data.charts_by_name = {};
2789                 var charts = data.charts;
2790                 var x;
2791                 for(x in charts) {
2792                     var chart = charts[x];
2793                     data.charts_by_name[chart.name] = chart;
2794                 }
2795
2796                 // update the dashboard hostname
2797                 document.getElementById('hostname').innerHTML = options.hostname;
2798                 document.getElementById('hostname').href = NETDATA.serverDefault;
2799
2800                 // update the dashboard title
2801                 document.title = options.hostname + ' netdata dashboard';
2802
2803                 // render all charts
2804                 renderChartsAndMenu(data);
2805             }
2806         });
2807     });
2808 }
2809
2810 // ----------------------------------------------------------------------------
2811
2812 function versionLog(msg) {
2813     document.getElementById('versionCheckLog').innerHTML = msg;
2814 }
2815
2816 function getNetdataVersion(callback) {
2817     versionLog('Downloading installed version info from netdata...');
2818
2819     $.ajax({
2820         url: 'version.txt',
2821         async: true,
2822         cache: false
2823     })
2824     .done(function(data) {
2825         data = data.replace(/(\r\n|\n|\r| |\t)/gm,"");
2826         if(data.length !== 40) {
2827             versionLog('Received version string is invalid.');
2828             callback(null);
2829         }
2830         else {
2831             versionLog('Installed version of netdata is ' + data);
2832             document.getElementById('netdataVersion').innerHTML = data;
2833             callback(data);
2834         }
2835     })
2836     .fail(function() {
2837         versionLog('Failed to download installed version info from netdata!');
2838         callback(null);
2839     });
2840 }
2841
2842 function getGithubLatestCommit(callback) {
2843     versionLog('Downloading latest version info from github...');
2844
2845     $.ajax({
2846         url: 'https://api.github.com/repos/firehol/netdata/commits',
2847         async: true,
2848         cache: false
2849     })
2850     .done(function(data) {
2851         versionLog('Latest version info from github is ' + data[0].sha);
2852         callback(data[0].sha);
2853     })
2854     .fail(function() {
2855         versionLog('Failed to download installed version info from github!');
2856         callback(null);
2857     });
2858 }
2859
2860 function checkForUpdate(callback) {
2861     getNetdataVersion(function(sha1) {
2862         if(sha1 === null) callback(null, null);
2863
2864         getGithubLatestCommit(function(sha2) {
2865             callback(sha1, sha2);
2866         });
2867     });
2868
2869     return null;
2870 }
2871
2872 function notifyForUpdate(force) {
2873     versionLog('<p>checking for updates...</p>');
2874
2875     var now = new Date().getTime();
2876
2877     if(typeof force === 'undefined' || force !== true) {
2878         var last = loadLocalStorage('last_update_check');
2879
2880         if(typeof last === 'string')
2881             last = parseInt(last);
2882         else
2883             last = 0;
2884
2885         if(now - last < 3600000 * 8) {
2886             // no need to check it - too soon
2887             return;
2888         }
2889     }
2890
2891     checkForUpdate(function(sha1, sha2) {
2892         var save = false;
2893
2894         if(sha1 === null) {
2895             save = false;
2896             versionLog('<p><big>Failed to get your netdata version!</big></p><p>You can always get the latest version of netdata from <a href="https://github.com/firehol/netdata" target="_blank">its github page</a>.</p>');
2897         }
2898         else if(sha2 === null) {
2899             save = false;
2900             versionLog('<p><big>Failed to get the latest version from github.</big></p><p>You can always get the latest version of netdata from <a href="https://github.com/firehol/netdata" target="_blank">its github page</a>.</p>');
2901         }
2902         else if(sha1 === sha2) {
2903             save = true;
2904             versionLog('<p><big>You already have the latest version of netdata!</big></p><p>No update yet?<br/>Probably, we need some motivation to keep going on!</p><p>If you haven\'t already, <a href="https://github.com/firehol/netdata" target="_blank">give netdata a <b>Star</b> at its github page</a>.</p>');
2905         }
2906         else {
2907             save = true;
2908             var compare = 'https://github.com/firehol/netdata/compare/' + sha1.toString() + '...' + sha2.toString();
2909
2910             versionLog('<p><big><strong>New version of netdata available!</strong></big></p><p>Latest version: ' + sha2.toString() + '</p><p><a href="' + compare + '" target="_blank">Click here for the changes log</a> since your installed version, and<br/><a href="https://github.com/firehol/netdata/wiki/Updating-Netdata" target="_blank">click here for directions on updating</a> your netdata installation.</p><p>We suggest to review the changes log for new features you may be interested, or important bug fixes you may need.<br/>Keeping your netdata updated, is generally a good idea.</p>');
2911
2912             document.getElementById('update_badge').innerHTML = '!';
2913         }
2914
2915         if(save)
2916             saveLocalStorage('last_update_check', now.toString());
2917     });
2918 }
2919
2920 // ----------------------------------------------------------------------------
2921
2922 function finalizePage() {
2923     // resize all charts - without starting the background thread
2924     // this has to be done while NETDATA is paused
2925     // if we ommit this, the affix menu will be wrong, since all
2926     // the Dom elements are initially zero-sized
2927     NETDATA.parseDom();
2928
2929     if(urlOptions.pan_and_zoom === true) {
2930         urlOptions.nowelcome = true;
2931         NETDATA.globalPanAndZoom.setMaster(NETDATA.options.targets[0], urlOptions.after, urlOptions.before);
2932     }
2933
2934     // ------------------------------------------------------------------------
2935     // https://github.com/viralpatel/jquery.shorten/blob/master/src/jquery.shorten.js
2936     $.fn.shorten = function(settings) {
2937         "use strict";
2938
2939         var config = {
2940             showChars: 750,
2941             minHideChars: 10,
2942             ellipsesText: "...",
2943             moreText: '<i class="fa fa-expand" aria-hidden="true"></i> show more information',
2944             lessText: '<i class="fa fa-compress" aria-hidden="true"></i> show less information',
2945             onLess: function() { NETDATA.onscroll(); },
2946             onMore: function() { NETDATA.onscroll(); },
2947             errMsg: null,
2948             force: false
2949         };
2950
2951         if (settings) {
2952             $.extend(config, settings);
2953         }
2954
2955         if ($(this).data('jquery.shorten') && !config.force) {
2956             return false;
2957         }
2958         $(this).data('jquery.shorten', true);
2959
2960         $(document).off("click", '.morelink');
2961
2962         $(document).on({
2963             click: function() {
2964
2965                 var $this = $(this);
2966                 if ($this.hasClass('less')) {
2967                     $this.removeClass('less');
2968                     $this.html(config.moreText);
2969                     $this.parent().prev().animate({'height':'0'+'%'}, 0, function () { $this.parent().prev().prev().show(); }).hide(0, function() {
2970                         config.onLess();
2971                     });
2972
2973                 } else {
2974                     $this.addClass('less');
2975                     $this.html(config.lessText);
2976                     $this.parent().prev().animate({'height':'100'+'%'}, 0, function () { $this.parent().prev().prev().hide(); }).show(0, function() {
2977                         config.onMore();
2978                     });
2979                 }
2980                 return false;
2981             }
2982         }, '.morelink');
2983
2984         return this.each(function() {
2985             var $this = $(this);
2986
2987             var content = $this.html();
2988             var contentlen = $this.text().length;
2989             if (contentlen > config.showChars + config.minHideChars) {
2990                 var c = content.substr(0, config.showChars);
2991                 if (c.indexOf('<') >= 0) // If there's HTML don't want to cut it
2992                 {
2993                     var inTag = false; // I'm in a tag?
2994                     var bag = ''; // Put the characters to be shown here
2995                     var countChars = 0; // Current bag size
2996                     var openTags = []; // Stack for opened tags, so I can close them later
2997                     var tagName = null;
2998
2999                     for (var i = 0, r = 0; r <= config.showChars; i++) {
3000                         if (content[i] == '<' && !inTag) {
3001                             inTag = true;
3002
3003                             // This could be "tag" or "/tag"
3004                             tagName = content.substring(i + 1, content.indexOf('>', i));
3005
3006                             // If its a closing tag
3007                             if (tagName[0] == '/') {
3008
3009
3010                                 if (tagName != '/' + openTags[0]) {
3011                                     config.errMsg = 'ERROR en HTML: the top of the stack should be the tag that closes';
3012                                 } else {
3013                                     openTags.shift(); // Pops the last tag from the open tag stack (the tag is closed in the retult HTML!)
3014                                 }
3015
3016                             } else {
3017                                 // There are some nasty tags that don't have a close tag like <br/>
3018                                 if (tagName.toLowerCase() != 'br') {
3019                                     openTags.unshift(tagName); // Add to start the name of the tag that opens
3020                                 }
3021                             }
3022                         }
3023                         if (inTag && content[i] == '>') {
3024                             inTag = false;
3025                         }
3026
3027                         if (inTag) { bag += content.charAt(i); } // Add tag name chars to the result
3028                         else {
3029                             r++;
3030                             if (countChars <= config.showChars) {
3031                                 bag += content.charAt(i); // Fix to ie 7 not allowing you to reference string characters using the []
3032                                 countChars++;
3033                             } else // Now I have the characters needed
3034                             {
3035                                 if (openTags.length > 0) // I have unclosed tags
3036                                 {
3037                                     //console.log('They were open tags');
3038                                     //console.log(openTags);
3039                                     for (j = 0; j < openTags.length; j++) {
3040                                         //console.log('Cierro tag ' + openTags[j]);
3041                                         bag += '</' + openTags[j] + '>'; // Close all tags that were opened
3042
3043                                         // You could shift the tag from the stack to check if you end with an empty stack, that means you have closed all open tags
3044                                     }
3045                                     break;
3046                                 }
3047                             }
3048                         }
3049                     }
3050                     c = $('<div/>').html(bag + '<span class="ellip">' + config.ellipsesText + '</span>').html();
3051                 }else{
3052                     c+=config.ellipsesText;
3053                 }
3054
3055                 var html = '<div class="shortcontent">' + c +
3056                         '</div><div class="allcontent">' + content +
3057                         '</div><span><a href="javascript://nop/" class="morelink">' + config.moreText + '</a></span>';
3058
3059                 $this.html(html);
3060                 $this.find(".allcontent").hide(); // Hide all text
3061                 $('.shortcontent p:last', $this).css('margin-bottom', 0); //Remove bottom margin on last paragraph as it's likely shortened
3062             }
3063         });
3064
3065     };
3066     $(".chart-message").shorten();
3067     // ------------------------------------------------------------------------
3068
3069     // callback for us to track PanAndZoom operations
3070     NETDATA.globalPanAndZoom.callback = netdataPanAndZoomCallback;
3071
3072     // let it run (update the charts)
3073     NETDATA.unpause();
3074
3075     // check if we have to jump to a specific section
3076     scrollToId(urlOptions.hash.replace('#',''));
3077
3078     /* activate bootstrap sidebar (affix) */
3079     $('#sidebar').affix({
3080         offset: {
3081             top: (isdemo())?150:0,
3082             bottom: 0
3083         }
3084     });
3085
3086     /* fix scrolling of very long affix lists
3087        http://stackoverflow.com/questions/21691585/bootstrap-3-1-0-affix-too-long
3088      */
3089     $('#sidebar').on('affixed.bs.affix', function() {
3090         $(this).removeAttr('style');
3091     });
3092
3093     /* activate bootstrap scrollspy (needed for sidebar) */
3094     $(document.body).scrollspy({
3095         target: '#sidebar',
3096         offset: $(window).height() / 5 // controls the diff of the <hX> element to the top, to select it
3097     });
3098
3099     // change the URL based on the current position of the screen
3100     $('#sidebar').on('activate.bs.scrollspy', function (e) {
3101         var el = $(e.target);
3102         if(el.find('ul').size() == 0) {
3103             var hash = el.find('a').attr('href');
3104             if(typeof hash === 'string' && hash.substring(0, 1) == '#') {
3105                 urlOptions.hash = hash;
3106                 // console.log(urlOptions.hash);
3107                 netdataHashUpdate();
3108             }
3109         }
3110     });
3111
3112     document.getElementById('footer').style.display = 'block';
3113
3114     var update_options_modal = function() {
3115         // console.log('update_options_modal');
3116
3117         var sync_option = function(option) {
3118             var self = $('#' + option);
3119
3120             if(self.prop('checked') !== NETDATA.getOption(option)) {
3121                 // console.log('switching ' + option.toString());
3122                 self.bootstrapToggle(NETDATA.getOption(option)?'on':'off');
3123             }
3124         }
3125
3126         var theme_sync_option = function(option) {
3127             var self = $('#' + option);
3128
3129             self.bootstrapToggle(netdataTheme === 'slate'?'on':'off');
3130         }
3131
3132         sync_option('eliminate_zero_dimensions');
3133         sync_option('destroy_on_hide');
3134         sync_option('parallel_refresher');
3135         sync_option('concurrent_refreshes');
3136         sync_option('sync_selection');
3137         sync_option('sync_pan_and_zoom');
3138         sync_option('stop_updates_when_focus_is_lost');
3139         sync_option('smooth_plot');
3140         sync_option('pan_and_zoom_data_padding');
3141         sync_option('show_help');
3142         theme_sync_option('netdata_theme_control');
3143
3144         if(NETDATA.getOption('parallel_refresher') === false) {
3145             $('#concurrent_refreshes_row').hide();
3146         }
3147         else {
3148             $('#concurrent_refreshes_row').show();
3149         }
3150     };
3151     NETDATA.setOption('setOptionCallback', update_options_modal);
3152
3153     // handle options changes
3154     $('#eliminate_zero_dimensions').change(function()       { NETDATA.setOption('eliminate_zero_dimensions', $(this).prop('checked')); });
3155     $('#destroy_on_hide').change(function()                 { NETDATA.setOption('destroy_on_hide', $(this).prop('checked')); });
3156     $('#parallel_refresher').change(function()              { NETDATA.setOption('parallel_refresher', $(this).prop('checked')); });
3157     $('#concurrent_refreshes').change(function()            { NETDATA.setOption('concurrent_refreshes', $(this).prop('checked')); });
3158     $('#sync_selection').change(function()                  { NETDATA.setOption('sync_selection', $(this).prop('checked')); });
3159     $('#sync_pan_and_zoom').change(function()               { NETDATA.setOption('sync_pan_and_zoom', $(this).prop('checked')); });
3160     $('#stop_updates_when_focus_is_lost').change(function() { NETDATA.setOption('stop_updates_when_focus_is_lost', $(this).prop('checked')); });
3161     $('#smooth_plot').change(function()                     { NETDATA.setOption('smooth_plot', $(this).prop('checked')); });
3162     $('#pan_and_zoom_data_padding').change(function()       { NETDATA.setOption('pan_and_zoom_data_padding', $(this).prop('checked')); });
3163     $('#show_help').change(function()                       {
3164         urlOptions.help = $(this).prop('checked');
3165         NETDATA.setOption('show_help', urlOptions.help);
3166         netdataReload();
3167     });
3168
3169     // this has to be the last
3170     // it reloads the page
3171     $('#netdata_theme_control').change(function() {
3172         urlOptions.theme = $(this).prop('checked')?'slate':'white';
3173         if(setTheme(urlOptions.theme))
3174             netdataReload();
3175     });
3176
3177     $('#updateModal').on('shown.bs.modal', function() {
3178         notifyForUpdate(true);
3179     });
3180
3181     $('#alarmsModal').on('shown.bs.modal', function() {
3182         NETDATA.pause(alarmsUpdateModal);
3183     });
3184
3185     $('#alarmsModal').on('hidden.bs.modal', function() {
3186         NETDATA.unpause();
3187         document.getElementById('alarms_active').innerHTML =
3188                 document.getElementById('alarms_all').innerHTML =
3189                 document.getElementById('alarms_log').innerHTML =
3190                         'loading...';
3191     });
3192
3193     $('#deleteRegistryModal').on('hidden.bs.modal', function() {
3194         deleteRegistryGuid = null;
3195     });
3196
3197     if(isdemo()) {
3198         if(!urlOptions.nowelcome) {
3199             setTimeout(function() {
3200                 $('#welcomeModal').modal();
3201             }, 1000);
3202         }
3203
3204         // google analytics when this is used for the home page of the demo sites
3205         // this does not run on user's installations
3206         setTimeout(function() {
3207             (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
3208             (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
3209             m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
3210             })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
3211
3212             ga('create', 'UA-64295674-3', 'auto');
3213             ga('send', 'pageview');
3214         }, 2000);
3215     }
3216     else notifyForUpdate();
3217 }
3218
3219 function resetDashboardOptions() {
3220     var help = NETDATA.options.current.show_help;
3221
3222     NETDATA.resetOptions();
3223     if(setTheme('slate'))
3224         netdataReload();
3225
3226     if(help !== NETDATA.options.current.show_help)
3227         netdataReload();
3228 }
3229
3230 downloadAllCharts();
3231
3232 </script>
3233
3234 </body>
3235 </html>