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