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