]> arthur.barton.de Git - netdata.git/blob - web/index.html
added icons to shorten menu descriptions (especially container related); forced max...
[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-cog" 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-cog"></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-cog"></i> alarms</a></li>
595                             <li><a href="#" class="btn" data-toggle="modal" data-target="#optionsModal"><i class="fa fa-cog"></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         info: 'Overview of the key system metrics.'
1445     },
1446
1447     'ap': {
1448         title: '<i class="fa fa-wifi" aria-hidden="true"></i> Access Points',
1449         info: undefined
1450     },
1451
1452     'tc': {
1453         title: '<i class="fa fa-globe" aria-hidden="true"></i> Quality of Service',
1454         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).'
1455     },
1456
1457     'net': {
1458         title: '<i class="fa fa-share-alt" aria-hidden="true"></i> Network Interfaces',
1459         info: 'Per network interface statistics collected from <code>/proc/net/dev</code>.'
1460     },
1461
1462     'ipv4': {
1463         title: '<i class="fa fa-bolt" aria-hidden="true"></i> IPv4 Networking',
1464         info: undefined
1465     },
1466
1467     'ipv6': {
1468         title: '<i class="fa fa-bolt" aria-hidden="true"></i> IPv6 Networking',
1469         info: undefined
1470     },
1471
1472     'ipvs': {
1473         title: 'IP Virtual Server',
1474         info: undefined
1475     },
1476
1477     'netfilter': {
1478         title: '<i class="fa fa-shield" aria-hidden="true"></i> Firewall (netfilter)',
1479         info: undefined
1480     },
1481
1482     'cpu': {
1483         title: 'CPUs',
1484         info: undefined
1485     },
1486
1487     'mem': {
1488         title: 'Memory',
1489         info: undefined
1490     },
1491
1492     'disk': {
1493         title: '<i class="fa fa-folder" aria-hidden="true"></i> Disks',
1494         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.'
1495     },
1496
1497     'sensors': {
1498         title: 'Sensors',
1499         info: undefined
1500     },
1501
1502     'nfsd': {
1503         title: '<i class="fa fa-folder-open" aria-hidden="true"></i> File Server (nfsd)',
1504         info: undefined
1505     },
1506
1507     'apps': {
1508         title: '<i class="fa fa-heartbeat" aria-hidden="true"></i> Applications',
1509         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.',
1510         height: 1.5
1511     },
1512
1513     'users': {
1514         title: '<i class="fa fa-user" aria-hidden="true"></i> Users',
1515         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.',
1516         height: 1.5
1517     },
1518
1519     'groups': {
1520         title: '<i class="fa fa-users" aria-hidden="true"></i> User Groups',
1521         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.',
1522         height: 1.5
1523     },
1524
1525     'netdata': {
1526         title: '<i class="fa fa-bar-chart" aria-hidden="true"></i> Netdata Monitoring',
1527         info: undefined
1528     },
1529
1530     'example': {
1531         title: 'Example Charts',
1532         info: undefined
1533     },
1534
1535     'cgroup': {
1536         title: '<i class="fa fa-th" aria-hidden="true"></i>',
1537         info: undefined
1538     },
1539
1540     'cgqemu': {
1541         title: '<i class="fa fa-th-large" aria-hidden="true"></i>',
1542         info: undefined
1543     },
1544
1545     'memcached': {
1546         title: '<i class="fa fa-database" aria-hidden="true"></i> memcached',
1547         info: undefined
1548     },
1549
1550     'mysql': {
1551         title: '<i class="fa fa-database" aria-hidden="true"></i> MySQL',
1552         info: undefined
1553     },
1554
1555     'redis': {
1556         title: '<i class="fa fa-database" aria-hidden="true"></i> Redis',
1557         info: undefined
1558     },
1559
1560     'ipfs': {
1561         title: '<i class="fa fa-folder-open" aria-hidden="true"></i> IPFS',
1562         info: undefined
1563     },
1564
1565     'phpfpm': {
1566         title: 'PHP-FPM',
1567         info: undefined,
1568     },
1569
1570     'postfix': {
1571         title: '<i class="fa fa-envelope" aria-hidden="true"></i> postfix',
1572         info: undefined,
1573     },
1574
1575     'nginx': {
1576         title: '<i class="fa fa-eye" aria-hidden="true"></i> nginx',
1577         info: undefined,
1578     },
1579
1580     'apache': {
1581         title: '<i class="fa fa-eye" aria-hidden="true"></i> Apache',
1582         info: undefined,
1583     },
1584
1585     'named': {
1586         title: '<i class="fa fa-tag" aria-hidden="true"></i> named',
1587         info: undefined
1588     },
1589
1590     'squid': {
1591         title: '<i class="fa fa-puzzle-piece" aria-hidden="true"></i> squid',
1592         info: undefined
1593     },
1594
1595     'nut': {
1596         title: '<i class="fa fa-battery-half" aria-hidden="true"></i> UPS',
1597         info: undefined
1598     }
1599 };
1600
1601 var submenuData = {
1602     'mem.ksm': {
1603         title: 'Memory Deduper',
1604         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.'
1605     },
1606
1607     'netfilter.conntrack': {
1608         title: 'Connection Tracker',
1609         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.'
1610     },
1611
1612     'netfilter.nfacct': {
1613         title: 'Bandwidth Accounting',
1614         info: 'The following information is read using the <code>nfacct.plugin</code>.'
1615     },
1616
1617     'netfilter.synproxy': {
1618         title: 'DDoS Protection',
1619         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.'
1620     }
1621 };
1622
1623 //
1624 // chartData works on the context of a chart
1625 // Its purpose is to set:
1626 //
1627 // info: the text above the charts
1628 // heads: the representation of the chart at the top the subsection (second level menu)
1629 // mainheads: the representation of the chart at the top of the section (first level menu)
1630 // colors: the dimension colors of the chart (the default colors are appended)
1631 // height: the ratio of the chart height relative to the default
1632 //
1633 var chartData = {
1634     'system.cpu': {
1635         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.'
1636     },
1637
1638     'system.load': {
1639         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>',
1640         height: 0.7
1641     },
1642
1643     'system.io': {
1644         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.'
1645     },
1646
1647     'system.swapio': {
1648         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).'
1649     },
1650
1651     'system.pgfaults': {
1652         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.'
1653     },
1654
1655     'system.entropy': {
1656         colors: '#CC22AA',
1657         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.'
1658     },
1659
1660     'system.forks': {
1661         colors: '#5555DD',
1662         info: 'The number of new processes created per second, read from <code>/proc/stat</code>.'
1663     },
1664
1665     'system.intr': {
1666         colors: '#DD5555',
1667         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.'
1668     },
1669
1670     'system.interrupts': {
1671         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.'
1672     },
1673
1674     'system.softirqs': {
1675         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.'
1676     },
1677
1678     'system.processes': {
1679         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.'
1680     },
1681
1682     'system.active_processes': {
1683         info: 'All system active processes, read from <code>/proc/loadavg</code>.'
1684     },
1685
1686     'system.ctxt': {
1687         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.'
1688     },
1689
1690     'system.idlejitter': {
1691         colors: '#5555AA',
1692         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).'
1693     },
1694
1695     'system.ipv4': {
1696         info: 'Total IPv4 Traffic, read from <code>/proc/net/netstat</code>.'
1697     },
1698
1699     'system.ipv6': {
1700         info: 'Total IPv6 Traffic, read from <code>/proc/net/snmp6</code>.'
1701     },
1702
1703     'system.ram': {
1704         info: 'System memory, read from <code>/proc/meminfo</code>.'
1705     },
1706
1707     'system.swap': {
1708         info: 'System swap memory, read from <code>/proc/meminfo</code>.'
1709     },
1710
1711     // ------------------------------------------------------------------------
1712     // MEMORY
1713
1714     'mem.ksm_savings': {
1715         heads: [
1716             gaugeChart('Saved', '12%', 'savings', '#0099CC')
1717         ]
1718     },
1719
1720     'mem.ksm_ratios': {
1721         heads: [
1722             function(id) {
1723                 return  '<div data-netdata="' + id + '"'
1724                     + ' data-gauge-max-value="100"'
1725                     + ' data-chart-library="gauge"'
1726                     + ' data-title="Savings"'
1727                     + ' data-units="percentage %"'
1728                     + ' data-gauge-adjust="width"'
1729                     + ' data-width="12%"'
1730                     + ' data-before="0"'
1731                     + ' data-after="-CHART_DURATION"'
1732                     + ' data-points="CHART_DURATION"'
1733                     + ' role="application"></div>';
1734             }
1735         ]
1736     },
1737
1738     'mem.committed': {
1739         colors: NETDATA.colors[3]
1740     },
1741
1742     // ------------------------------------------------------------------------
1743     // APPS
1744
1745     'apps.cpu': {
1746         height: 2.0
1747     },
1748
1749     'apps.preads': {
1750         height: 2.0
1751     },
1752
1753     'apps.pwrites': {
1754         height: 2.0
1755     },
1756
1757     // ------------------------------------------------------------------------
1758     // USERS
1759
1760     'users.cpu': {
1761         height: 2.0
1762     },
1763
1764     'users.preads': {
1765         height: 2.0
1766     },
1767
1768     'users.pwrites': {
1769         height: 2.0
1770     },
1771
1772     // ------------------------------------------------------------------------
1773     // GROUPS
1774
1775     'groups.cpu': {
1776         height: 2.0
1777     },
1778
1779     'groups.preads': {
1780         height: 2.0
1781     },
1782
1783     'groups.pwrites': {
1784         height: 2.0
1785     },
1786
1787     // ------------------------------------------------------------------------
1788     // NETWORK QoS
1789
1790     'tc.qos': {
1791         heads: [
1792             function(id) {
1793                 if(id.match(/.*-ifb$/))
1794                     return gaugeChart('Inbound', '12%', '', '#5555AA');
1795                 else
1796                     return gaugeChart('Outbound', '12%', '', '#AA9900');
1797             }
1798         ]
1799     },
1800
1801     // ------------------------------------------------------------------------
1802     // NETWORK INTERFACES
1803
1804     'net.net': {
1805         heads: [
1806             gaugeChart('Received', '12%', 'received'),
1807             gaugeChart('Sent', '12%', 'sent')
1808         ]
1809     },
1810
1811     // ------------------------------------------------------------------------
1812     // NETFILTER
1813
1814     'netfilter.sockets': {
1815         colors: '#88AA00',
1816         heads: [
1817             gaugeChart('Active Connections', '12%', '', '#88AA00')
1818         ]
1819     },
1820
1821     'netfilter.new': {
1822         heads: [
1823             gaugeChart('New Connections', '12%', 'new', '#5555AA')
1824         ]
1825     },
1826
1827     // ------------------------------------------------------------------------
1828     // DISKS
1829
1830     'disk.util': {
1831         colors: '#FF5588',
1832         heads: [
1833             gaugeChart('Utilization', '12%', '', '#FF5588')
1834         ],
1835         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.'
1836     },
1837
1838     'disk.backlog': {
1839         colors: '#0099CC',
1840         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.'
1841     },
1842
1843     'disk.io': {
1844         heads: [
1845             gaugeChart('Read', '12%', 'reads'),
1846             gaugeChart('Write', '12%', 'writes')
1847         ],
1848         info: 'Amount of data transferred to and from disk.'
1849     },
1850
1851     'disk.ops': {
1852         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).'
1853     },
1854
1855     'disk.qops': {
1856         info: 'I/O operations currently in progress. This metric is a snapshot - it is not an average over the last interval.'
1857     },
1858
1859     'disk.iotime': {
1860         height: 0.5,
1861         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.'
1862     },
1863     'disk.mops': {
1864         height: 0.5,
1865         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.'
1866     },
1867     'disk.svctm': {
1868         height: 0.5,
1869         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.'
1870     },
1871     'disk.avgsz': {
1872         height: 0.5,
1873         info: 'The average I/O operation size.'
1874     },
1875     'disk.await': {
1876         height: 0.5,
1877         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.'
1878     },
1879
1880     'disk.space': {
1881         info: 'Disk space utilization. reserved for root is automatically reserved by the system to prevent the root user from getting out of space.'
1882     },
1883     'disk.inodes': {
1884         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.'
1885     },
1886
1887     'mysql.net': {
1888         info: 'The amount of data sent to mysql clients (<strong>out</strong>) and received from mysql clients (<strong>in</strong>).'
1889     },
1890
1891     // ------------------------------------------------------------------------
1892     // MYSQL
1893
1894     'mysql.queries': {
1895         info: 'The number of statements executed by the server.<ul>' +
1896         '<li><strong>queries</strong> counts the statements executed within stored SQL programs.</li>' +
1897         '<li><strong>questions</strong> counts the statements sent to the mysql server by mysql clients.</li>' +
1898         '<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.' +
1899         ' 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>' +
1900         '</ul>'
1901     },
1902
1903     'mysql.handlers': {
1904         info: 'Usage of the internal handlers of mysql. This chart provides very good insights of what the mysql server is actually doing.' +
1905         ' (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>' +
1906         '<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>' +
1907         '<li><strong>delete</strong>, the number of times that rows have been deleted from tables.</li>' +
1908         '<li><strong>prepare</strong>, a counter for the prepare phase of two-phase commit operations.</li>' +
1909         '<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>' +
1910         '<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>' +
1911         '<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>' +
1912         '<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>' +
1913         '<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>' +
1914         '<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>' +
1915         '<li><strong>rollback</strong>, the number of requests for a storage engine to perform a rollback operation.</li>' +
1916         '<li><strong>savepoint</strong>, the number of requests for a storage engine to place a savepoint.</li>' +
1917         '<li><strong>savepoint rollback</strong>, the number of requests for a storage engine to roll back to a savepoint.</li>' +
1918         '<li><strong>update</strong>, the number of requests to update a row in a table.</li>' +
1919         '<li><strong>write</strong>, the number of requests to insert a row in a table.</li>' +
1920         '</ul>'
1921     },
1922
1923     'mysql.table_locks': {
1924         info: 'MySQL table locks counters: <ul>' +
1925         '<li><strong>immediate</strong>, the number of times that a request for a table lock could be granted immediately.</li>' +
1926         '<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>' +
1927         '</ul>'
1928     },
1929
1930     // ------------------------------------------------------------------------
1931     // APACHE
1932
1933     'apache.connections': {
1934         colors: NETDATA.colors[4],
1935         mainheads: [
1936             gaugeChart('Connections', '12%', '', NETDATA.colors[4])
1937         ]
1938     },
1939
1940     'apache.requests': {
1941         colors: NETDATA.colors[0],
1942         mainheads: [
1943             gaugeChart('Requests', '12%', '', NETDATA.colors[0])
1944         ]
1945     },
1946
1947     'apache.net': {
1948         colors: NETDATA.colors[3],
1949         mainheads: [
1950             gaugeChart('Bandwidth', '12%', '', NETDATA.colors[3])
1951         ]
1952     },
1953
1954     'apache.workers': {
1955         mainheads: [
1956             function(id) {
1957                 return  '<div data-netdata="' + id + '"'
1958                     + ' data-dimensions="busy"'
1959                     + ' data-append-options="percentage"'
1960                     + ' data-gauge-max-value="100"'
1961                     + ' data-chart-library="gauge"'
1962                     + ' data-title="Workers Utilization"'
1963                     + ' data-units="percentage %"'
1964                     + ' data-gauge-adjust="width"'
1965                     + ' data-width="12%"'
1966                     + ' data-before="0"'
1967                     + ' data-after="-CHART_DURATION"'
1968                     + ' data-points="CHART_DURATION"'
1969                     + ' role="application"></div>';
1970             }
1971         ]
1972     },
1973
1974     'apache.bytesperreq': {
1975         colors: NETDATA.colors[3],
1976         height: 0.5
1977     },
1978
1979     'apache.reqpersec': {
1980         colors: NETDATA.colors[4],
1981         height: 0.5
1982     },
1983
1984     'apache.bytespersec': {
1985         colors: NETDATA.colors[6],
1986         height: 0.5
1987     },
1988
1989
1990     // ------------------------------------------------------------------------
1991     // NGINX
1992
1993     'nginx.connections': {
1994         colors: NETDATA.colors[4],
1995         mainheads: [
1996             gaugeChart('Connections', '12%', '', NETDATA.colors[4])
1997         ]
1998     },
1999
2000     'nginx.requests': {
2001         colors: NETDATA.colors[0],
2002         mainheads: [
2003             gaugeChart('Requests', '12%', '', NETDATA.colors[0])
2004         ]
2005     },
2006
2007     // ------------------------------------------------------------------------
2008     // NETDATA
2009
2010     'netdata.response_time': {
2011         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).'
2012     }
2013 };
2014
2015 function anyAttribute(obj, attr, key, def) {
2016     if(typeof obj[key] !== 'undefined') {
2017         if(typeof obj[key][attr] !== 'undefined')
2018             return obj[key][attr];
2019     }
2020     return def;
2021 }
2022
2023 function menuTitle(chart) {
2024     if(typeof chart.menu_pattern !== 'undefined') {
2025         return anyAttribute(menuData, 'title', chart.menu_pattern, chart.menu_pattern).toString()
2026                 + ' ' + chart.type.slice(-(chart.type.length - chart.menu_pattern.length - 1)).toString();
2027     }
2028
2029     return anyAttribute(menuData, 'title', chart.menu, chart.menu);
2030 }
2031
2032 function menuInfo(menu) {
2033     return anyAttribute(menuData, 'info', menu, null);
2034 }
2035
2036 function menuHeight(menu, relative) {
2037     return anyAttribute(menuData, 'height', menu, 1.0) * relative;
2038 }
2039
2040 function submenuTitle(menu, submenu) {
2041     var key = menu + '.' + submenu;
2042     var title = anyAttribute(submenuData, 'title', key, submenu);
2043     if(title.length > 30) {
2044         var a = title.substring(0, 13);
2045         var b = title.substring(title.length - 13, title.length);
2046         return a + '...' + b;
2047     }
2048     return title;
2049 }
2050
2051 function submenuInfo(menu, submenu) {
2052     var key = menu + '.' + submenu;
2053     return anyAttribute(submenuData, 'info', key, null);
2054 }
2055
2056 function submenuHeight(menu, submenu, relative) {
2057     var key = menu + '.' + submenu;
2058     return anyAttribute(submenuData, 'height', key, 1.0) * relative;
2059 }
2060
2061
2062 function chartInfo(id) {
2063     if(typeof chartData[id] !== 'undefined' && typeof chartData[id].info !== 'undefined')
2064         return '<div class="chart-message netdata-chart-alignment" role="document">' + chartData[id].info + '</div>';
2065     else
2066         return '';
2067 }
2068
2069 function chartHeight(id, def) {
2070     if(typeof chartData[id] !== 'undefined' && typeof chartData[id].height !== 'undefined')
2071         return def * chartData[id].height;
2072     else
2073         return def;
2074 }
2075
2076
2077 // ----------------------------------------------------------------------------
2078
2079 // enrich the data structure returned by netdata
2080 // to reflect our menu system and content
2081 function enrichChartData(chart) {
2082     var tmp = chart.type.split('_')[0];
2083
2084     switch(tmp) {
2085         case 'ap':
2086         case 'net':
2087         case 'disk':
2088             chart.menu = tmp;
2089             break;
2090
2091         case 'cgroup':
2092             chart.menu = chart.type;
2093             if(chart.id.match(/.*[\._\/-:]qemu[\._\/-:]*/) || chart.id.match(/.*[\._\/-:]kvm[\._\/-:]*/))
2094                 chart.menu_pattern = 'cgqemu';
2095             else
2096                 chart.menu_pattern = 'cgroup';
2097             break;
2098
2099         case 'apache':
2100         case 'exim':
2101         case 'memcached':
2102         case 'mysql':
2103         case 'named':
2104         case 'nginx':
2105         case 'nut':
2106         case 'phpfpm':
2107         case 'postfix':
2108         case 'redis':
2109         case 'ipfs':
2110         case 'squid':
2111         case 'snmp':
2112         case 'tomcat':
2113             chart.menu = chart.type;
2114             chart.menu_pattern = tmp;
2115             break;
2116
2117         case 'tc':
2118             chart.menu = tmp;
2119
2120             // find a name for this device from fireqos info
2121             // we strip '_(in|out)' or '(in|out)_'
2122             if(typeof options.submenu_names[chart.family] === 'undefined' || options.submenu_names[chart.family] === chart.family) {
2123                 var n = chart.name.split('.')[1];
2124                 if(n.endsWith('_in'))
2125                     options.submenu_names[chart.family] = n.slice(0, n.lastIndexOf('_in'));
2126                 else if(n.endsWith('_out'))
2127                     options.submenu_names[chart.family] = n.slice(0, n.lastIndexOf('_out'));
2128                 else if(n.startsWith('in_'))
2129                     options.submenu_names[chart.family] = n.slice(3, n.length);
2130                 else if(n.startsWith('out_'))
2131                     options.submenu_names[chart.family] = n.slice(4, n.length);
2132             }
2133
2134             // increase the priority of IFB devices
2135             // to have inbound appear before outbound
2136             if(chart.id.match(/.*-ifb$/))
2137                 chart.priority--;
2138
2139             break;
2140
2141         default:
2142             chart.menu = chart.type;
2143             break;
2144     }
2145
2146     chart.submenu = chart.family;
2147 }
2148
2149 // ----------------------------------------------------------------------------
2150
2151 function name2id(s) {
2152     return s
2153         .replace(/ /g, '_')
2154         .replace(/\(/g, '_')
2155         .replace(/\)/g, '_')
2156         .replace(/\./g, '_')
2157         .replace(/\//g, '_');
2158 }
2159
2160 function headMain(charts, duration) {
2161     var head = '';
2162
2163     if(typeof charts['system.swap'] !== 'undefined')
2164         head += '<div style="margin-right: 10px;" data-netdata="system.swap"'
2165         + ' data-dimensions="free"'
2166         + ' data-append-options="percentage"'
2167         + ' data-chart-library="easypiechart"'
2168         + ' data-title="Free Swap"'
2169         + ' data-units="%"'
2170         + ' data-easypiechart-max-value="100"'
2171         + ' data-width="8%"'
2172         + ' data-before="0"'
2173         + ' data-after="-' + duration.toString() + '"'
2174         + ' data-points="' + duration.toString() + '"'
2175         + ' data-colors="#DD4400"'
2176         + ' role="application"></div>';
2177
2178     if(typeof charts['system.io'] !== 'undefined') {
2179         head += '<div style="margin-right: 10px;" data-netdata="system.io"'
2180         + ' data-dimensions="in"'
2181         + ' data-chart-library="easypiechart"'
2182         + ' data-title="Disk Read"'
2183         + ' data-width="10%"'
2184         + ' data-before="0"'
2185         + ' data-after="-' + duration.toString() + '"'
2186         + ' data-points="' + duration.toString() + '"'
2187         + ' role="application"></div>';
2188
2189         head += '<div style="margin-right: 10px;" data-netdata="system.io"'
2190         + ' data-dimensions="out"'
2191         + ' data-chart-library="easypiechart"'
2192         + ' data-title="Disk Write"'
2193         + ' data-width="10%"'
2194         + ' data-before="0"'
2195         + ' data-after="-' + duration.toString() + '"'
2196         + ' data-points="' + duration.toString() + '"'
2197         + ' role="application"></div>';
2198     }
2199
2200     if(typeof charts['system.cpu'] !== 'undefined')
2201         head += '<div data-netdata="system.cpu"'
2202         + ' data-chart-library="gauge"'
2203         + ' data-title="CPU"'
2204         + ' data-units="%"'
2205         + ' data-gauge-max-value="100"'
2206         + ' data-width="18%"'
2207         + ' data-after="-' + duration.toString() + '"'
2208         + ' data-points="' + duration.toString() + '"'
2209         + ' data-colors="' + NETDATA.colors[12] + '"'
2210         + ' role="application"></div>';
2211
2212     if(typeof charts['system.ipv4'] !== 'undefined') {
2213         head += '<div style="margin-right: 10px;" data-netdata="system.ipv4"'
2214         + ' data-dimensions="received"'
2215         + ' data-chart-library="easypiechart"'
2216         + ' data-title="IPv4 Inbound"'
2217         + ' data-width="10%"'
2218         + ' data-before="0"'
2219         + ' data-after="-' + duration.toString() + '"'
2220         + ' data-points="' + duration.toString() + '"'
2221         + ' role="application"></div>';
2222
2223         head += '<div style="margin-right: 10px;" data-netdata="system.ipv4"'
2224         + ' data-dimensions="sent"'
2225         + ' data-chart-library="easypiechart"'
2226         + ' data-title="IPv4 Outbound"'
2227         + ' data-width="10%"'
2228         + ' data-before="0"'
2229         + ' data-after="-' + duration.toString() + '"'
2230         + ' data-points="' + duration.toString() + '"'
2231         + ' role="application"></div>';
2232     }
2233     else if(typeof charts['system.ipv6'] !== 'undefined') {
2234         head += '<div style="margin-right: 10px;" data-netdata="system.ipv6"'
2235         + ' data-dimensions="received"'
2236         + ' data-chart-library="easypiechart"'
2237         + ' data-title="IPv6 Inbound"'
2238         + ' data-units="kbps"'
2239         + ' data-width="10%"'
2240         + ' data-before="0"'
2241         + ' data-after="-' + duration.toString() + '"'
2242         + ' data-points="' + duration.toString() + '"'
2243         + ' role="application"></div>';
2244
2245         head += '<div style="margin-right: 10px;" data-netdata="system.ipv6"'
2246         + ' data-dimensions="sent"'
2247         + ' data-chart-library="easypiechart"'
2248         + ' data-title="IPv6 Outbound"'
2249         + ' data-units="kbps"'
2250         + ' data-width="10%"'
2251         + ' data-before="0"'
2252         + ' data-after="-' + duration.toString() + '"'
2253         + ' data-points="' + duration.toString() + '"'
2254         + ' role="application"></div>';
2255     }
2256
2257     if(typeof charts['system.ram'] !== 'undefined')
2258         head += '<div style="margin-right: 10px;" data-netdata="system.ram"'
2259         + ' data-dimensions="cached|free"'
2260         + ' data-append-options="percentage"'
2261         + ' data-chart-library="easypiechart"'
2262         + ' data-title="Available RAM"'
2263         + ' data-units="%"'
2264         + ' data-easypiechart-max-value="100"'
2265         + ' data-width="8%"'
2266         + ' data-after="-' + duration.toString() + '"'
2267         + ' data-points="' + duration.toString() + '"'
2268         + ' data-colors="' + NETDATA.colors[7] + '"'
2269         + ' role="application"></div>';
2270
2271     return head;
2272 }
2273
2274 function generateHeadCharts(type, chart, duration) {
2275     var head = '';
2276     var hcharts = anyAttribute(chartData, type, chart.context, []);
2277     if(hcharts.length > 0) {
2278         var hi = 0, hlen = hcharts.length;
2279         while(hi < hlen) {
2280             if(typeof hcharts[hi] === 'function')
2281                 head += hcharts[hi](chart.id).replace('CHART_DURATION', duration.toString()).replace('CHART_UNIQUE_ID', chart.id);
2282             else
2283                 head += hcharts[hi].replace('CHART_DURATION', duration.toString()).replace('CHART_UNIQUE_ID', chart.id);
2284             hi++;
2285         }
2286     }
2287     return head;
2288 }
2289
2290 function renderPage(menus, data) {
2291     var div = document.getElementById('charts_div');
2292     var pcent_width = Math.floor(100 / chartsPerRow($(div).width()));
2293
2294     // find the proper duration for per-second updates
2295     var duration = Math.round(($(div).width() * pcent_width / 100 * data.update_every / 3) / 60) * 60;
2296     var html = '';
2297     var sidebar = '<ul class="nav dashboard-sidenav" data-spy="affix" id="sidebar_ul">';
2298     var mainhead = headMain(data.charts, duration);
2299
2300     // sort the menus
2301     var main = sortObjectByPriority(menus);
2302     var i = 0, len = main.length;
2303     while(i < len) {
2304         var menu = main[i++];
2305
2306         // generate an entry at the main menu
2307
2308         var menuid = name2id(menu);
2309         sidebar += '<li class=""><a href="#' + menuid + '" onClick="return scrollToId(\'' + menuid + '\');">' + menus[menu].title + '</a><ul class="nav">';
2310         html += '<div role="section"><div role="sectionhead"><h1 id="' + menuid + '" role="heading">' + menus[menu].title + '</h1></div><div id="menu_' + menuid + '" role="document">';
2311
2312         if(menus[menu].info !== null)
2313             html += menus[menu].info;
2314
2315         // console.log(' >> ' + menu + ' (' + menus[menu].priority + '): ' + menus[menu].title);
2316
2317         var shtml = '';
2318         var mhead = '<div class="netdata-chart-row">' + mainhead;
2319         mainhead = '';
2320
2321         // sort the submenus of this menu
2322         var sub = sortObjectByPriority(menus[menu].submenus);
2323         var si = 0, slen = sub.length;
2324         while(si < slen) {
2325             var submenu = sub[si++];
2326
2327             // generate an entry at the submenu
2328             var submenuid = name2id(menu + '_' + submenu);
2329             sidebar += '<li class><a href="#' + submenuid + '" onClick="return scrollToId(\'' + submenuid + '\');">' + menus[menu].submenus[submenu].title + '</a></li>';
2330             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>';
2331
2332             if(menus[menu].submenus[submenu].info !== null)
2333                 shtml += '<div class="chart-message netdata-chart-alignment" role="document">' + menus[menu].submenus[submenu].info + '</div>';
2334
2335             var head = '<div class="netdata-chart-row">';
2336             var chtml = '';
2337
2338             // console.log('    \------- ' + submenu + ' (' + menus[menu].submenus[submenu].priority + '): ' + menus[menu].submenus[submenu].title);
2339
2340             // sort the charts in this submenu of this menu
2341             menus[menu].submenus[submenu].charts.sort(prioritySort);
2342             var ci = 0, clen = menus[menu].submenus[submenu].charts.length;
2343             while(ci < clen) {
2344                 var chart = menus[menu].submenus[submenu].charts[ci++];
2345
2346                 // generate the submenu heading charts
2347                 mhead += generateHeadCharts('mainheads', chart, duration);
2348                 head += generateHeadCharts('heads', chart, duration);
2349
2350                 // generate the chart
2351                 chtml += chartInfo(chart.context) + '<div data-netdata="' + chart.id + '"'
2352                     + ' data-width="' + pcent_width.toString() + '%"'
2353                     + ' data-height="' + chartHeight(chart.context, options.chartsHeight).toString() + 'px"'
2354                     + ' data-before="0"'
2355                     + ' data-after="-' + duration.toString() + '"'
2356                     + ' data-id="' + name2id(options.hostname + '/' + chart.id) + '"'
2357                     + ' data-colors="' + anyAttribute(chartData, 'colors', chart.context, '') + '"'
2358                     + ' role="application"></div>';
2359
2360                 // console.log('         \------- ' + chart.id + ' (' + chart.priority + '): ' + chart.context  + ' height: ' + menus[menu].submenus[submenu].height);
2361             }
2362
2363             head += '</div>';
2364             shtml += head + chtml + '</div>';
2365         }
2366
2367         mhead += '</div>';
2368         sidebar += '</ul></li>';
2369         html += mhead + shtml + '</div></div><hr role="separator"/>';
2370     }
2371
2372     sidebar += '</ul>';
2373     div.innerHTML = html;
2374     document.getElementById('sidebar').innerHTML = sidebar;
2375     finalizePage();
2376 }
2377
2378 function renderChartsAndMenu(data) {
2379     var menus = options.menus;
2380     var charts = data.charts;
2381
2382     for(var c in charts) {
2383         enrichChartData(charts[c]);
2384
2385         // create the menu
2386         if(typeof menus[charts[c].menu] === 'undefined') {
2387             menus[charts[c].menu] = {
2388                 priority: charts[c].priority,
2389                 submenus: {},
2390                 title: menuTitle(charts[c]),
2391                 info: menuInfo(charts[c].menu),
2392                 height: menuHeight(charts[c].menu, options.chartsHeight)
2393             };
2394         }
2395
2396         if(charts[c].priority < menus[charts[c].menu].priority)
2397             menus[charts[c].menu].priority = charts[c].priority;
2398
2399         // create the submenu
2400         if(typeof menus[charts[c].menu].submenus[charts[c].submenu] === 'undefined') {
2401             menus[charts[c].menu].submenus[charts[c].submenu] = {
2402                 priority: charts[c].priority,
2403                 charts: new Array(),
2404                 title: null,
2405                 info: submenuInfo(charts[c].menu, charts[c].submenu),
2406                 height: submenuHeight(charts[c].menu, charts[c].submenu, menus[charts[c].menu].height)
2407             };
2408         }
2409
2410         if(charts[c].priority < menus[charts[c].menu].submenus[charts[c].submenu].priority)
2411             menus[charts[c].menu].submenus[charts[c].submenu].priority = charts[c].priority;
2412
2413         // index the chart in the menu/submenu
2414         menus[charts[c].menu].submenus[charts[c].submenu].charts.push(charts[c]);
2415     }
2416
2417     // propagate the descriptive subname given to QoS
2418     // to all the other submenus with the same name
2419     for(var m in menus) {
2420         for(var s in menus[m].submenus) {
2421             // set the family using a name
2422             if(typeof options.submenu_names[s] !== 'undefined') {
2423                 menus[m].submenus[s].title = s + ' (' + options.submenu_names[s] + ')';
2424             }
2425             else {
2426                 menus[m].submenus[s].title = submenuTitle(m, s);
2427             }
2428         }
2429     }
2430
2431     renderPage(menus, data);
2432 }
2433
2434 // ----------------------------------------------------------------------------
2435
2436 function alarmsUpdateModal() {
2437     var active = '<h3>Raised Alarms</h3><table class="table">';
2438     var all = '<h3>All Running Alarms</h3><div class="panel-group" id="alarms_all_accordion" role="tablist" aria-multiselectable="true">';
2439     var log = '<h3>Alarm Log</h3><table class="table"><tr><th>When</th><th>Chart</th><th>Alarm</th><th>Status</th>';
2440     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.';
2441
2442     NETDATA.alarms.get('all', function(data) {
2443         options.alarm_families = new Array();
2444
2445         alarmsCallback(data);
2446
2447         if(data === null) {
2448             document.getElementById('alarms_active').innerHTML =
2449                     document.getElementById('alarms_all').innerHTML =
2450                             document.getElementById('alarms_log').innerHTML =
2451                                     'failed to load alarm data!';
2452             return;
2453         }
2454
2455         function frequency_text(seconds, sfx) {
2456             if(seconds === 0)
2457                 return 'now';
2458
2459             var suffix = '';
2460             if(seconds < 0) {
2461                 seconds = -seconds;
2462                 if(sfx) suffix = '&nbsp;ago';
2463             }
2464
2465             var hours = Math.floor(seconds / 3600);
2466             seconds -= (hours * 3600);
2467
2468             var minutes = Math.floor(seconds / 60);
2469             seconds -= (minutes * 60);
2470
2471             var txt = '';
2472             
2473             if(hours > 1) txt += hours.toString() + '&nbsp;hours';
2474             else if(hours === 1) txt += hours.toString() + '&nbsp;hour';
2475
2476             if(hours > 0 && minutes > 0 && seconds == 0)
2477                 txt += '&nbsp;and&nbsp;';
2478             else if(hours > 0 && minutes > 0 && seconds > 0)
2479                 txt += ',&nbsp;';
2480
2481             if(minutes > 1) txt += minutes.toString() + '&nbsp;minutes';
2482             else if(minutes === 1) txt += minutes.toString() + '&nbsp;minute';
2483
2484             if((minutes > 0 || minutes > 0) && seconds > 0)
2485                 txt += '&nbsp;and&nbsp;';
2486
2487             if(seconds > 1) txt += seconds.toString() + '&nbsp;seconds';
2488             else if(seconds === 1) txt += seconds.toString() + '&nbsp;second';
2489
2490             return txt + suffix;
2491         }
2492
2493         function alarm_lookup_explain(alarm, chart) {
2494             var dimensions = ' of all values ';
2495
2496             if(chart.dimensions.length > 1)
2497                 dimensions = ' of the sum of all dimensions ';
2498
2499             if(typeof alarm.lookup_dimensions !== 'undefined') {
2500                 var d = alarm.lookup_dimensions.replace('|', ',');
2501                 var x = d.split(',');
2502                 if(x.length > 1)
2503                     dimensions = 'of the sum of dimensions <code>' + alarm.lookup_dimensions + '</code> ';
2504                 else
2505                     dimensions = 'of all values of dimension <code>' + alarm.lookup_dimensions + '</code> ';
2506             }
2507
2508             return '<code>' + alarm.lookup_method + '</code> '
2509                 + dimensions + ', of chart <code>' + alarm.chart + '</code>'
2510                 + ', starting <code>' + frequency_text(alarm.lookup_after + alarm.lookup_before, true) + '</code> and up to <code>' + frequency_text(alarm.lookup_before, true) + '</code>'
2511                 + ((alarm.lookup_options)?(', with options <code>' + alarm.lookup_options.replace(' ', ',&nbsp;') + '</code>'):'')
2512                 + '.';
2513         }
2514
2515         function alarm_to_html(alarm, full) {
2516             var chart = options.data.charts[alarm.chart];
2517
2518             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>'
2519                 + '<td><table class="table">'
2520                 + ((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>'):'')
2521                 + ((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>'):'');
2522
2523             if(full === true) {
2524                     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>'):'')
2525                     + ((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>'):'')
2526                     + ((chart.green !== null)?('<tr><td width="10%" style="text-align:right">green&nbsp;threshold</td><td><code>' + chart.green + ' ' + chart.units + '</code></td></tr>'):'')
2527                     + ((chart.red !== null)?('<tr><td width="10%" style="text-align:right">red&nbsp;threshold</td><td><code>' + chart.red + ' ' + chart.units + '</code></td></tr>'):'');
2528             }
2529
2530             html += '<tr><td width="10%" style="text-align:right">check&nbsp;every</td><td>' + frequency_text(alarm.update_every) + '</td></tr>'
2531                 + '<tr><td width="10%" style="text-align:right">execute</td><td><span style="font-family: monospace;">' + alarm.exec + '</span></td></tr>'
2532                 + '<tr><td width="10%" style="text-align:right">source</td><td><span style="font-family: monospace;">' + alarm.source + '</span></td></tr>'
2533                 + '</table></td></tr>';
2534
2535             return html;
2536         }
2537
2538         function alarm_family_show(id) {
2539             var html = '<table class="table">';
2540             var family = options.alarm_families[id];
2541             var len = family.arr.length;
2542             while(len--) {
2543                 var alarm = family.arr[len];
2544                 html += alarm_to_html(alarm, true);
2545             }
2546             html += '</table>';
2547
2548             $('#alarm_all_' + id.toString()).html(html);
2549         }
2550
2551         // find the proper family of each alarm
2552         var now = new Date().getTime();
2553         var x;
2554         var count_active = 0;
2555         var count_all = 0;
2556         var families = {};
2557         var families_sort = new Array();
2558         for(x in data.alarms) {
2559             var alarm = data.alarms[x];
2560             var family = alarm.family;
2561
2562             // find the chart
2563             var chart = options.data.charts[alarm.chart];
2564             if(typeof chart === 'undefined')
2565                 chart = options.data.charts_by_name[alarm.chart];
2566
2567             // not found - this should never happen!
2568             if(typeof chart === 'undefined') {
2569                 console.log('WARNING: alarm ' + x + ' is linked to chart ' + alarm.chart + ', which is not found in the list of chart got from the server.');
2570                 chart = { priority: 9999999 };
2571             }
2572             else if(typeof chart.menu !== 'undefined' && typeof chart.submenu !== 'undefined')
2573                 // the family based on the chart
2574                 family = chart.menu + ' - ' + chart.submenu;
2575
2576             if(typeof families[family] === 'undefined') {
2577                 families[family] = {
2578                     name: family,
2579                     arr: new Array(),
2580                     priority: chart.priority
2581                 };
2582
2583                 families_sort.push(families[family]);
2584             }
2585
2586             if(chart.priority < families[family].priority)
2587                 families[family].priority = chart.priority;
2588
2589             families[family].arr.push(alarm);
2590         }
2591
2592         // sort the families, like the dashboard menu does
2593         var families_sorted = families_sort.sort(function (a, b) {
2594             if (a.priority > b.priority) return -1;
2595             if (a.priority < b.priority) return 1;
2596             if (a.name < b.name) return 1;
2597             if (a.name > b.name) return -1;
2598             return 0;
2599         });
2600
2601         var fc = 0;
2602         var len = families_sorted.length;
2603         while(len--) {
2604             var family = families_sorted[len].name;
2605             var active_family_added = false;
2606             var expanded = 'true';
2607             var collapsed = '';
2608             var cin = 'in';
2609
2610             if(fc !== 0) {
2611                 all += "</table></div></div></div>";
2612                 expanded = 'false';
2613                 collapsed = 'class="collapsed"'
2614                 cin = '';
2615             }
2616
2617             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() + '">';
2618
2619             options.alarm_families[fc] = families[family];
2620
2621             fc++;
2622
2623             var arr = families[family].arr;
2624             var c = arr.length;
2625             while(c--) {
2626                 var alarm = arr[c];
2627                 if(alarm.status === 'WARNING' || alarm.status === 'CRITICAL') {
2628                     if(!active_family_added) {
2629                         active_family_added = true;
2630                         active += '<tr><th class="text-center" colspan="2"><h4>' + family + '</h4></th></tr>';
2631                     }
2632                     count_active++;
2633                     active += alarm_to_html(alarm, false);
2634                 }
2635
2636                 count_all++;
2637             }
2638         }
2639         active += "</table>";
2640         if(families_sorted.length > 0) all += "</div></div></div>";
2641         all += "</div>";
2642
2643         if(!count_active)
2644             active += "<h4>Everything is normal. No raised alarms.</h4>";
2645         else
2646             active += footer;
2647
2648         if(!count_all)
2649             all += "<h4>No alarms are running in this system.</h4>";
2650         else
2651             all += footer;
2652
2653         document.getElementById('alarms_active').innerHTML = active;
2654         document.getElementById('alarms_all').innerHTML = all;
2655
2656         if(families_sorted.length > 0) alarm_family_show(0);
2657
2658         // register bootstrap events
2659         $('#alarms_all_accordion').on('show.bs.collapse', function (d) {
2660             var target = $(d.target);
2661             var id = $(target).data('alarm-id');
2662             alarm_family_show(id);
2663         });
2664         $('#alarms_all_accordion').on('hidden.bs.collapse', function (d) {
2665             var target = $(d.target);
2666             var id = $(target).data('alarm-id');
2667             $('#alarm_all_' + id.toString()).html('');
2668         });
2669
2670         NETDATA.alarms.get_log(function(data) {
2671             if(data === null) {
2672                 document.getElementById('alarms_log').innerHTML =
2673                         'failed to load alarm data!';
2674                 return;
2675             }
2676
2677             var i = 0;
2678             var len = data.length;
2679             if(len > 50) len = 50;
2680             while(i < len) {
2681                 var time = new Date(data[i].when * 1000);
2682                 log += '<tr><td>' + time.toLocaleDateString() + ' ' + time.toLocaleTimeString() + '</td><td>' + data[i].chart + '</td><td>' + data[i].name + '</td><td>' + data[i].status + '</td></tr>';
2683                 i++;
2684             }
2685             log += "</table>";
2686
2687             if(i == 0)
2688                 log += "<h4>No alarms have been logged in this system.</h4>";
2689
2690             document.getElementById('alarms_log').innerHTML = log;
2691         })
2692     });
2693 }
2694
2695 function alarmsCallback(data) {
2696     var count = 0;
2697     for(x in data.alarms) {
2698         var alarm = data.alarms[x];
2699         if(alarm.status === 'WARNING' || alarm.status === 'CRITICAL')
2700             count++;
2701     }
2702
2703     if(count > 0)
2704         document.getElementById('alarms_count_badge').innerHTML = count.toString();
2705     else
2706         document.getElementById('alarms_count_badge').innerHTML = '';
2707 }
2708
2709 function downloadAllCharts(netdata_url) {
2710     if(typeof netdata_url === 'undefined' || netdata_url === null)
2711         netdata_url = NETDATA.serverDefault;
2712
2713     NETDATA.pause(function() {
2714         $("#loadOverlay").css("display","none");
2715
2716         NETDATA.alarms.callback = alarmsCallback;
2717
2718         // download all the charts the server knows
2719         NETDATA.chartRegistry.downloadAll(netdata_url, function(data) {
2720
2721             if(data !== null) {
2722                 options.hostname = data.hostname;
2723                 options.data = data;
2724
2725                 // create a chart_by_name index
2726                 data.charts_by_name = {};
2727                 var charts = data.charts;
2728                 var x;
2729                 for(x in charts) {
2730                     var chart = charts[x];
2731                     data.charts_by_name[chart.name] = chart;
2732                 }
2733
2734                 // update the dashboard hostname
2735                 document.getElementById('hostname').innerHTML = options.hostname;
2736                 document.getElementById('hostname').href = NETDATA.serverDefault;
2737
2738                 // update the dashboard title
2739                 document.title = options.hostname + ' netdata dashboard';
2740
2741                 // render all charts
2742                 renderChartsAndMenu(data);
2743             }
2744         });
2745     });
2746 }
2747
2748 // ----------------------------------------------------------------------------
2749
2750 function versionLog(msg) {
2751     document.getElementById('versionCheckLog').innerHTML = msg;
2752 }
2753
2754 function getNetdataVersion(callback) {
2755     versionLog('Downloading installed version info from netdata...');
2756
2757     $.ajax({
2758         url: 'version.txt',
2759         async: true,
2760         cache: false
2761     })
2762     .done(function(data) {
2763         data = data.replace(/(\r\n|\n|\r| |\t)/gm,"");
2764         if(data.length !== 40) {
2765             versionLog('Received version string is invalid.');
2766             callback(null);
2767         }
2768         else {
2769             versionLog('Installed version of netdata is ' + data);
2770             document.getElementById('netdataVersion').innerHTML = data;
2771             callback(data);
2772         }
2773     })
2774     .fail(function() {
2775         versionLog('Failed to download installed version info from netdata!');
2776         callback(null);
2777     });
2778 }
2779
2780 function getGithubLatestCommit(callback) {
2781     versionLog('Downloading latest version info from github...');
2782
2783     $.ajax({
2784         url: 'https://api.github.com/repos/firehol/netdata/commits',
2785         async: true,
2786         cache: false
2787     })
2788     .done(function(data) {
2789         versionLog('Latest version info from github is ' + data[0].sha);
2790         callback(data[0].sha);
2791     })
2792     .fail(function() {
2793         versionLog('Failed to download installed version info from github!');
2794         callback(null);
2795     });
2796 }
2797
2798 function checkForUpdate(callback) {
2799     getNetdataVersion(function(sha1) {
2800         if(sha1 === null) callback(null, null);
2801
2802         getGithubLatestCommit(function(sha2) {
2803             callback(sha1, sha2);
2804         });
2805     });
2806
2807     return null;
2808 }
2809
2810 function notifyForUpdate(force) {
2811     versionLog('<p>checking for updates...</p>');
2812
2813     var now = new Date().getTime();
2814
2815     if(typeof force === 'undefined' || force !== true) {
2816         var last = loadLocalStorage('last_update_check');
2817
2818         if(typeof last === 'string')
2819             last = parseInt(last);
2820         else
2821             last = 0;
2822
2823         if(now - last < 3600000 * 8) {
2824             // no need to check it - too soon
2825             return;
2826         }
2827     }
2828
2829     checkForUpdate(function(sha1, sha2) {
2830         var save = false;
2831
2832         if(sha1 === null) {
2833             save = false;
2834             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>');
2835         }
2836         else if(sha2 === null) {
2837             save = false;
2838             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>');
2839         }
2840         else if(sha1 === sha2) {
2841             save = true;
2842             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>');
2843         }
2844         else {
2845             save = true;
2846             var compare = 'https://github.com/firehol/netdata/compare/' + sha1.toString() + '...' + sha2.toString();
2847
2848             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>');
2849
2850             document.getElementById('update_badge').innerHTML = '!';
2851         }
2852
2853         if(save)
2854             saveLocalStorage('last_update_check', now.toString());
2855     });
2856 }
2857
2858 // ----------------------------------------------------------------------------
2859
2860 function finalizePage() {
2861     // resize all charts - without starting the background thread
2862     // this has to be done while NETDATA is paused
2863     // if we ommit this, the affix menu will be wrong, since all
2864     // the Dom elements are initially zero-sized
2865     NETDATA.parseDom();
2866
2867     if(urlOptions.pan_and_zoom === true) {
2868         urlOptions.nowelcome = true;
2869         NETDATA.globalPanAndZoom.setMaster(NETDATA.options.targets[0], urlOptions.after, urlOptions.before);
2870     }
2871
2872     // ------------------------------------------------------------------------
2873     // https://github.com/viralpatel/jquery.shorten/blob/master/src/jquery.shorten.js
2874     $.fn.shorten = function(settings) {
2875         "use strict";
2876
2877         var config = {
2878             showChars: 750,
2879             minHideChars: 10,
2880             ellipsesText: "...",
2881             moreText: '<i class="fa fa-expand" aria-hidden="true"></i> show more information',
2882             lessText: '<i class="fa fa-compress" aria-hidden="true"></i> show less information',
2883             onLess: function() { NETDATA.onscroll(); },
2884             onMore: function() { NETDATA.onscroll(); },
2885             errMsg: null,
2886             force: false
2887         };
2888
2889         if (settings) {
2890             $.extend(config, settings);
2891         }
2892
2893         if ($(this).data('jquery.shorten') && !config.force) {
2894             return false;
2895         }
2896         $(this).data('jquery.shorten', true);
2897
2898         $(document).off("click", '.morelink');
2899
2900         $(document).on({
2901             click: function() {
2902
2903                 var $this = $(this);
2904                 if ($this.hasClass('less')) {
2905                     $this.removeClass('less');
2906                     $this.html(config.moreText);
2907                     $this.parent().prev().animate({'height':'0'+'%'}, 0, function () { $this.parent().prev().prev().show(); }).hide(0, function() {
2908                         config.onLess();
2909                     });
2910
2911                 } else {
2912                     $this.addClass('less');
2913                     $this.html(config.lessText);
2914                     $this.parent().prev().animate({'height':'100'+'%'}, 0, function () { $this.parent().prev().prev().hide(); }).show(0, function() {
2915                         config.onMore();
2916                     });
2917                 }
2918                 return false;
2919             }
2920         }, '.morelink');
2921
2922         return this.each(function() {
2923             var $this = $(this);
2924
2925             var content = $this.html();
2926             var contentlen = $this.text().length;
2927             if (contentlen > config.showChars + config.minHideChars) {
2928                 var c = content.substr(0, config.showChars);
2929                 if (c.indexOf('<') >= 0) // If there's HTML don't want to cut it
2930                 {
2931                     var inTag = false; // I'm in a tag?
2932                     var bag = ''; // Put the characters to be shown here
2933                     var countChars = 0; // Current bag size
2934                     var openTags = []; // Stack for opened tags, so I can close them later
2935                     var tagName = null;
2936
2937                     for (var i = 0, r = 0; r <= config.showChars; i++) {
2938                         if (content[i] == '<' && !inTag) {
2939                             inTag = true;
2940
2941                             // This could be "tag" or "/tag"
2942                             tagName = content.substring(i + 1, content.indexOf('>', i));
2943
2944                             // If its a closing tag
2945                             if (tagName[0] == '/') {
2946
2947
2948                                 if (tagName != '/' + openTags[0]) {
2949                                     config.errMsg = 'ERROR en HTML: the top of the stack should be the tag that closes';
2950                                 } else {
2951                                     openTags.shift(); // Pops the last tag from the open tag stack (the tag is closed in the retult HTML!)
2952                                 }
2953
2954                             } else {
2955                                 // There are some nasty tags that don't have a close tag like <br/>
2956                                 if (tagName.toLowerCase() != 'br') {
2957                                     openTags.unshift(tagName); // Add to start the name of the tag that opens
2958                                 }
2959                             }
2960                         }
2961                         if (inTag && content[i] == '>') {
2962                             inTag = false;
2963                         }
2964
2965                         if (inTag) { bag += content.charAt(i); } // Add tag name chars to the result
2966                         else {
2967                             r++;
2968                             if (countChars <= config.showChars) {
2969                                 bag += content.charAt(i); // Fix to ie 7 not allowing you to reference string characters using the []
2970                                 countChars++;
2971                             } else // Now I have the characters needed
2972                             {
2973                                 if (openTags.length > 0) // I have unclosed tags
2974                                 {
2975                                     //console.log('They were open tags');
2976                                     //console.log(openTags);
2977                                     for (j = 0; j < openTags.length; j++) {
2978                                         //console.log('Cierro tag ' + openTags[j]);
2979                                         bag += '</' + openTags[j] + '>'; // Close all tags that were opened
2980
2981                                         // 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
2982                                     }
2983                                     break;
2984                                 }
2985                             }
2986                         }
2987                     }
2988                     c = $('<div/>').html(bag + '<span class="ellip">' + config.ellipsesText + '</span>').html();
2989                 }else{
2990                     c+=config.ellipsesText;
2991                 }
2992
2993                 var html = '<div class="shortcontent">' + c +
2994                         '</div><div class="allcontent">' + content +
2995                         '</div><span><a href="javascript://nop/" class="morelink">' + config.moreText + '</a></span>';
2996
2997                 $this.html(html);
2998                 $this.find(".allcontent").hide(); // Hide all text
2999                 $('.shortcontent p:last', $this).css('margin-bottom', 0); //Remove bottom margin on last paragraph as it's likely shortened
3000             }
3001         });
3002
3003     };
3004     $(".chart-message").shorten();
3005     // ------------------------------------------------------------------------
3006
3007     // callback for us to track PanAndZoom operations
3008     NETDATA.globalPanAndZoom.callback = netdataPanAndZoomCallback;
3009
3010     // let it run (update the charts)
3011     NETDATA.unpause();
3012
3013     // check if we have to jump to a specific section
3014     scrollToId(urlOptions.hash.replace('#',''));
3015
3016     /* activate bootstrap sidebar (affix) */
3017     $('#sidebar').affix({
3018         offset: {
3019             top: (isdemo())?150:0,
3020             bottom: 0
3021         }
3022     });
3023
3024     /* fix scrolling of very long affix lists
3025        http://stackoverflow.com/questions/21691585/bootstrap-3-1-0-affix-too-long
3026      */
3027     $('#sidebar').on('affixed.bs.affix', function() {
3028         $(this).removeAttr('style');
3029     });
3030
3031     /* activate bootstrap scrollspy (needed for sidebar) */
3032     $(document.body).scrollspy({
3033         target: '#sidebar',
3034         offset: $(window).height() / 3 // controls the diff of the <hX> element to the top, to select it
3035     });
3036
3037     // change the URL based on the current position of the screen
3038     $('#sidebar').on('activate.bs.scrollspy', function (e) {
3039         var el = $(e.target);
3040         if(el.find('ul').size() == 0) {
3041             var hash = el.find('a').attr('href');
3042             if(typeof hash === 'string' && hash.substring(0, 1) == '#') {
3043                 urlOptions.hash = hash;
3044                 // console.log(urlOptions.hash);
3045                 netdataHashUpdate();
3046             }
3047         }
3048     });
3049
3050     document.getElementById('footer').style.display = 'block';
3051
3052     var update_options_modal = function() {
3053         // console.log('update_options_modal');
3054
3055         var sync_option = function(option) {
3056             var self = $('#' + option);
3057
3058             if(self.prop('checked') !== NETDATA.getOption(option)) {
3059                 // console.log('switching ' + option.toString());
3060                 self.bootstrapToggle(NETDATA.getOption(option)?'on':'off');
3061             }
3062         }
3063
3064         var theme_sync_option = function(option) {
3065             var self = $('#' + option);
3066
3067             self.bootstrapToggle(netdataTheme === 'slate'?'on':'off');
3068         }
3069
3070         sync_option('eliminate_zero_dimensions');
3071         sync_option('destroy_on_hide');
3072         sync_option('parallel_refresher');
3073         sync_option('concurrent_refreshes');
3074         sync_option('sync_selection');
3075         sync_option('sync_pan_and_zoom');
3076         sync_option('stop_updates_when_focus_is_lost');
3077         sync_option('smooth_plot');
3078         sync_option('pan_and_zoom_data_padding');
3079         sync_option('show_help');
3080         theme_sync_option('netdata_theme_control');
3081
3082         if(NETDATA.getOption('parallel_refresher') === false) {
3083             $('#concurrent_refreshes_row').hide();
3084         }
3085         else {
3086             $('#concurrent_refreshes_row').show();
3087         }
3088     };
3089     NETDATA.setOption('setOptionCallback', update_options_modal);
3090
3091     // handle options changes
3092     $('#eliminate_zero_dimensions').change(function()       { NETDATA.setOption('eliminate_zero_dimensions', $(this).prop('checked')); });
3093     $('#destroy_on_hide').change(function()                 { NETDATA.setOption('destroy_on_hide', $(this).prop('checked')); });
3094     $('#parallel_refresher').change(function()              { NETDATA.setOption('parallel_refresher', $(this).prop('checked')); });
3095     $('#concurrent_refreshes').change(function()            { NETDATA.setOption('concurrent_refreshes', $(this).prop('checked')); });
3096     $('#sync_selection').change(function()                  { NETDATA.setOption('sync_selection', $(this).prop('checked')); });
3097     $('#sync_pan_and_zoom').change(function()               { NETDATA.setOption('sync_pan_and_zoom', $(this).prop('checked')); });
3098     $('#stop_updates_when_focus_is_lost').change(function() { NETDATA.setOption('stop_updates_when_focus_is_lost', $(this).prop('checked')); });
3099     $('#smooth_plot').change(function()                     { NETDATA.setOption('smooth_plot', $(this).prop('checked')); });
3100     $('#pan_and_zoom_data_padding').change(function()       { NETDATA.setOption('pan_and_zoom_data_padding', $(this).prop('checked')); });
3101     $('#show_help').change(function()                       {
3102         urlOptions.help = $(this).prop('checked');
3103         NETDATA.setOption('show_help', urlOptions.help);
3104         netdataReload();
3105     });
3106
3107     // this has to be the last
3108     // it reloads the page
3109     $('#netdata_theme_control').change(function() {
3110         urlOptions.theme = $(this).prop('checked')?'slate':'white';
3111         if(setTheme(urlOptions.theme))
3112             netdataReload();
3113     });
3114
3115     $('#updateModal').on('shown.bs.modal', function() {
3116         notifyForUpdate(true);
3117     });
3118
3119     $('#alarmsModal').on('shown.bs.modal', function() {
3120         NETDATA.pause(alarmsUpdateModal);
3121     });
3122
3123     $('#alarmsModal').on('hidden.bs.modal', function() {
3124         NETDATA.unpause();
3125         document.getElementById('alarms_active').innerHTML =
3126                 document.getElementById('alarms_all').innerHTML =
3127                 document.getElementById('alarms_log').innerHTML =
3128                         'loading...';
3129     });
3130
3131     $('#deleteRegistryModal').on('hidden.bs.modal', function() {
3132         deleteRegistryGuid = null;
3133     });
3134
3135     if(isdemo()) {
3136         if(!urlOptions.nowelcome) {
3137             setTimeout(function() {
3138                 $('#welcomeModal').modal();
3139             }, 1000);
3140         }
3141
3142         // google analytics when this is used for the home page of the demo sites
3143         // this does not run on user's installations
3144         setTimeout(function() {
3145             (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
3146             (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
3147             m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
3148             })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
3149
3150             ga('create', 'UA-64295674-3', 'auto');
3151             ga('send', 'pageview');
3152         }, 2000);
3153     }
3154     else notifyForUpdate();
3155 }
3156
3157 function resetDashboardOptions() {
3158     var help = NETDATA.options.current.show_help;
3159
3160     NETDATA.resetOptions();
3161     if(setTheme('slate'))
3162         netdataReload();
3163
3164     if(help !== NETDATA.options.current.show_help)
3165         netdataReload();
3166 }
3167
3168 downloadAllCharts();
3169
3170 </script>
3171
3172 </body>
3173 </html>