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