]> arthur.barton.de Git - netdata.git/blob - web/index.html
the overview charts now show used swap and used ram; fixes #549
[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 'ipfs':
1061             case 'memcached':
1062             case 'mysql':
1063             case 'named':
1064             case 'nginx':
1065             case 'nut':
1066             case 'phpfpm':
1067             case 'postfix':
1068             case 'postgres':
1069             case 'redis':
1070             case 'retroshare':
1071             case 'smawebbox':
1072             case 'snmp':
1073             case 'squid':
1074             case 'tomcat':
1075                 chart.menu = chart.type;
1076                 chart.menu_pattern = tmp;
1077                 break;
1078
1079             case 'tc':
1080                 chart.menu = tmp;
1081
1082                 // find a name for this device from fireqos info
1083                 // we strip '_(in|out)' or '(in|out)_'
1084                 if(typeof options.submenu_names[chart.family] === 'undefined' || options.submenu_names[chart.family] === chart.family) {
1085                     var n = chart.name.split('.')[1];
1086                     if(n.endsWith('_in'))
1087                         options.submenu_names[chart.family] = n.slice(0, n.lastIndexOf('_in'));
1088                     else if(n.endsWith('_out'))
1089                         options.submenu_names[chart.family] = n.slice(0, n.lastIndexOf('_out'));
1090                     else if(n.startsWith('in_'))
1091                         options.submenu_names[chart.family] = n.slice(3, n.length);
1092                     else if(n.startsWith('out_'))
1093                         options.submenu_names[chart.family] = n.slice(4, n.length);
1094                 }
1095
1096                 // increase the priority of IFB devices
1097                 // to have inbound appear before outbound
1098                 if(chart.id.match(/.*-ifb$/))
1099                     chart.priority--;
1100
1101                 break;
1102
1103             default:
1104                 chart.menu = chart.type;
1105                 break;
1106         }
1107
1108         chart.submenu = chart.family;
1109     }
1110
1111     // ----------------------------------------------------------------------------
1112
1113     function headMain(charts, duration) {
1114         var head = '';
1115
1116         if(typeof charts['system.swap'] !== 'undefined')
1117             head += '<div style="margin-right: 10px;" data-netdata="system.swap"'
1118             + ' data-dimensions="used"'
1119             + ' data-append-options="percentage"'
1120             + ' data-chart-library="easypiechart"'
1121             + ' data-title="Used Swap"'
1122             + ' data-units="%"'
1123             + ' data-easypiechart-max-value="100"'
1124             + ' data-width="8%"'
1125             + ' data-before="0"'
1126             + ' data-after="-' + duration.toString() + '"'
1127             + ' data-points="' + duration.toString() + '"'
1128             + ' data-colors="#DD4400"'
1129             + ' role="application"></div>';
1130
1131         if(typeof charts['system.io'] !== 'undefined') {
1132             head += '<div style="margin-right: 10px;" data-netdata="system.io"'
1133             + ' data-dimensions="in"'
1134             + ' data-chart-library="easypiechart"'
1135             + ' data-title="Disk Read"'
1136             + ' data-width="10%"'
1137             + ' data-before="0"'
1138             + ' data-after="-' + duration.toString() + '"'
1139             + ' data-points="' + duration.toString() + '"'
1140             + ' role="application"></div>';
1141
1142             head += '<div style="margin-right: 10px;" data-netdata="system.io"'
1143             + ' data-dimensions="out"'
1144             + ' data-chart-library="easypiechart"'
1145             + ' data-title="Disk Write"'
1146             + ' data-width="10%"'
1147             + ' data-before="0"'
1148             + ' data-after="-' + duration.toString() + '"'
1149             + ' data-points="' + duration.toString() + '"'
1150             + ' role="application"></div>';
1151         }
1152
1153         if(typeof charts['system.cpu'] !== 'undefined')
1154             head += '<div data-netdata="system.cpu"'
1155             + ' data-chart-library="gauge"'
1156             + ' data-title="CPU"'
1157             + ' data-units="%"'
1158             + ' data-gauge-max-value="100"'
1159             + ' data-width="18%"'
1160             + ' data-after="-' + duration.toString() + '"'
1161             + ' data-points="' + duration.toString() + '"'
1162             + ' data-colors="' + NETDATA.colors[12] + '"'
1163             + ' role="application"></div>';
1164
1165         if(typeof charts['system.ipv4'] !== 'undefined') {
1166             head += '<div style="margin-right: 10px;" data-netdata="system.ipv4"'
1167             + ' data-dimensions="received"'
1168             + ' data-chart-library="easypiechart"'
1169             + ' data-title="IPv4 Inbound"'
1170             + ' data-width="10%"'
1171             + ' data-before="0"'
1172             + ' data-after="-' + duration.toString() + '"'
1173             + ' data-points="' + duration.toString() + '"'
1174             + ' role="application"></div>';
1175
1176             head += '<div style="margin-right: 10px;" data-netdata="system.ipv4"'
1177             + ' data-dimensions="sent"'
1178             + ' data-chart-library="easypiechart"'
1179             + ' data-title="IPv4 Outbound"'
1180             + ' data-width="10%"'
1181             + ' data-before="0"'
1182             + ' data-after="-' + duration.toString() + '"'
1183             + ' data-points="' + duration.toString() + '"'
1184             + ' role="application"></div>';
1185         }
1186         else if(typeof charts['system.ipv6'] !== 'undefined') {
1187             head += '<div style="margin-right: 10px;" data-netdata="system.ipv6"'
1188             + ' data-dimensions="received"'
1189             + ' data-chart-library="easypiechart"'
1190             + ' data-title="IPv6 Inbound"'
1191             + ' data-units="kbps"'
1192             + ' data-width="10%"'
1193             + ' data-before="0"'
1194             + ' data-after="-' + duration.toString() + '"'
1195             + ' data-points="' + duration.toString() + '"'
1196             + ' role="application"></div>';
1197
1198             head += '<div style="margin-right: 10px;" data-netdata="system.ipv6"'
1199             + ' data-dimensions="sent"'
1200             + ' data-chart-library="easypiechart"'
1201             + ' data-title="IPv6 Outbound"'
1202             + ' data-units="kbps"'
1203             + ' data-width="10%"'
1204             + ' data-before="0"'
1205             + ' data-after="-' + duration.toString() + '"'
1206             + ' data-points="' + duration.toString() + '"'
1207             + ' role="application"></div>';
1208         }
1209
1210         if(typeof charts['system.ram'] !== 'undefined')
1211             head += '<div style="margin-right: 10px;" data-netdata="system.ram"'
1212             + ' data-dimensions="used|buffers"'
1213             + ' data-append-options="percentage"'
1214             + ' data-chart-library="easypiechart"'
1215             + ' data-title="Used RAM"'
1216             + ' data-units="%"'
1217             + ' data-easypiechart-max-value="100"'
1218             + ' data-width="8%"'
1219             + ' data-after="-' + duration.toString() + '"'
1220             + ' data-points="' + duration.toString() + '"'
1221             + ' data-colors="' + NETDATA.colors[7] + '"'
1222             + ' role="application"></div>';
1223
1224         return head;
1225     }
1226
1227     function generateHeadCharts(type, chart, duration) {
1228         var head = '';
1229         var hcharts = netdataDashboard.anyAttribute(netdataDashboard.context, type, chart.context, []);
1230         if(hcharts.length > 0) {
1231             var hi = 0, hlen = hcharts.length;
1232             while(hi < hlen) {
1233                 if(typeof hcharts[hi] === 'function')
1234                     head += hcharts[hi](chart.id).replace('CHART_DURATION', duration.toString()).replace('CHART_UNIQUE_ID', chart.id);
1235                 else
1236                     head += hcharts[hi].replace('CHART_DURATION', duration.toString()).replace('CHART_UNIQUE_ID', chart.id);
1237                 hi++;
1238             }
1239         }
1240         return head;
1241     }
1242
1243     function renderPage(menus, data) {
1244         var div = document.getElementById('charts_div');
1245         var pcent_width = Math.floor(100 / chartsPerRow($(div).width()));
1246
1247         // find the proper duration for per-second updates
1248         var duration = Math.round(($(div).width() * pcent_width / 100 * data.update_every / 3) / 60) * 60;
1249         var html = '';
1250         var sidebar = '<ul class="nav dashboard-sidenav" data-spy="affix" id="sidebar_ul">';
1251         var mainhead = headMain(data.charts, duration);
1252
1253         // sort the menus
1254         var main = sortObjectByPriority(menus);
1255         var i = 0, len = main.length;
1256         while(i < len) {
1257             var menu = main[i++];
1258
1259             // generate an entry at the main menu
1260
1261             var menuid = NETDATA.name2id('menu_' + menu);
1262             sidebar += '<li class=""><a href="#' + menuid + '" onClick="return scrollToId(\'' + menuid + '\');">' + menus[menu].icon + ' ' + menus[menu].title + '</a><ul class="nav">';
1263             html += '<div role="section"><div role="sectionhead"><h1 id="' + menuid + '" role="heading">' + menus[menu].title + '</h1></div><div role="document">';
1264
1265             if(menus[menu].info !== null)
1266                 html += menus[menu].info;
1267
1268             // console.log(' >> ' + menu + ' (' + menus[menu].priority + '): ' + menus[menu].title);
1269
1270             var shtml = '';
1271             var mhead = '<div class="netdata-chart-row">' + mainhead;
1272             mainhead = '';
1273
1274             // sort the submenus of this menu
1275             var sub = sortObjectByPriority(menus[menu].submenus);
1276             var si = 0, slen = sub.length;
1277             while(si < slen) {
1278                 var submenu = sub[si++];
1279
1280                 // generate an entry at the submenu
1281                 var submenuid = NETDATA.name2id('menu_' + menu + '_submenu_' + submenu);
1282                 sidebar += '<li class><a href="#' + submenuid + '" onClick="return scrollToId(\'' + submenuid + '\');">' + menus[menu].submenus[submenu].title + '</a></li>';
1283                 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>';
1284
1285                 if(menus[menu].submenus[submenu].info !== null)
1286                     shtml += '<div class="chart-message netdata-chart-alignment" role="document">' + menus[menu].submenus[submenu].info + '</div>';
1287
1288                 var head = '<div class="netdata-chart-row">';
1289                 var chtml = '';
1290
1291                 // console.log('    \------- ' + submenu + ' (' + menus[menu].submenus[submenu].priority + '): ' + menus[menu].submenus[submenu].title);
1292
1293                 // sort the charts in this submenu of this menu
1294                 menus[menu].submenus[submenu].charts.sort(prioritySort);
1295                 var ci = 0, clen = menus[menu].submenus[submenu].charts.length;
1296                 while(ci < clen) {
1297                     var chart = menus[menu].submenus[submenu].charts[ci++];
1298
1299                     // generate the submenu heading charts
1300                     mhead += generateHeadCharts('mainheads', chart, duration);
1301                     head += generateHeadCharts('heads', chart, duration);
1302
1303                     // generate the chart
1304                     chtml += netdataDashboard.contextInfo(chart.context) + '<div id="chart_' + NETDATA.name2id(chart.id) + '" data-netdata="' + chart.id + '"'
1305                         + ' data-width="' + pcent_width.toString() + '%"'
1306                         + ' data-height="' + netdataDashboard.contextHeight(chart.context, options.chartsHeight).toString() + 'px"'
1307                         + ' data-dygraph-valuerange="' + netdataDashboard.contextValueRange(chart.context) + '"'
1308                         + ' data-before="0"'
1309                         + ' data-after="-' + duration.toString() + '"'
1310                         + ' data-id="' + NETDATA.name2id(options.hostname + '/' + chart.id) + '"'
1311                         + ' data-colors="' + netdataDashboard.anyAttribute(netdataDashboard.context, 'colors', chart.context, '') + '"'
1312                         + ' role="application"></div>';
1313
1314                     // console.log('         \------- ' + chart.id + ' (' + chart.priority + '): ' + chart.context  + ' height: ' + menus[menu].submenus[submenu].height);
1315                 }
1316
1317                 head += '</div>';
1318                 shtml += head + chtml + '</div>';
1319             }
1320
1321             mhead += '</div>';
1322             sidebar += '</ul></li>';
1323             html += mhead + shtml + '</div></div><hr role="separator"/>';
1324         }
1325
1326         sidebar += '</ul>';
1327         div.innerHTML = html;
1328         document.getElementById('sidebar').innerHTML = sidebar;
1329         finalizePage();
1330     }
1331
1332     function renderChartsAndMenu(data) {
1333         var menus = options.menus;
1334         var charts = data.charts;
1335
1336         for(var c in charts) {
1337             enrichChartData(charts[c]);
1338
1339             // create the menu
1340             if(typeof menus[charts[c].menu] === 'undefined') {
1341                 menus[charts[c].menu] = {
1342                     priority: charts[c].priority,
1343                     submenus: {},
1344                     title: netdataDashboard.menuTitle(charts[c]),
1345                     icon: netdataDashboard.menuIcon(charts[c]),
1346                     info: netdataDashboard.menuInfo(charts[c].menu),
1347                     height: netdataDashboard.menuHeight(charts[c].menu, options.chartsHeight)
1348                 };
1349             }
1350
1351             if(charts[c].priority < menus[charts[c].menu].priority)
1352                 menus[charts[c].menu].priority = charts[c].priority;
1353
1354             // create the submenu
1355             if(typeof menus[charts[c].menu].submenus[charts[c].submenu] === 'undefined') {
1356                 menus[charts[c].menu].submenus[charts[c].submenu] = {
1357                     priority: charts[c].priority,
1358                     charts: new Array(),
1359                     title: null,
1360                     info: netdataDashboard.submenuInfo(charts[c].menu, charts[c].submenu),
1361                     height: netdataDashboard.submenuHeight(charts[c].menu, charts[c].submenu, menus[charts[c].menu].height)
1362                 };
1363             }
1364
1365             if(charts[c].priority < menus[charts[c].menu].submenus[charts[c].submenu].priority)
1366                 menus[charts[c].menu].submenus[charts[c].submenu].priority = charts[c].priority;
1367
1368             // index the chart in the menu/submenu
1369             menus[charts[c].menu].submenus[charts[c].submenu].charts.push(charts[c]);
1370         }
1371
1372         // propagate the descriptive subname given to QoS
1373         // to all the other submenus with the same name
1374         for(var m in menus) {
1375             for(var s in menus[m].submenus) {
1376                 // set the family using a name
1377                 if(typeof options.submenu_names[s] !== 'undefined') {
1378                     menus[m].submenus[s].title = s + ' (' + options.submenu_names[s] + ')';
1379                 }
1380                 else {
1381                     menus[m].submenus[s].title = netdataDashboard.submenuTitle(m, s);
1382                 }
1383             }
1384         }
1385
1386         renderPage(menus, data);
1387     }
1388
1389     // ----------------------------------------------------------------------------
1390
1391     function loadJs(url, callback) {
1392         $.ajax({
1393             url: url,
1394             cache: true,
1395             dataType: "script",
1396             xhrFields: { withCredentials: true } // required for the cookie
1397         })
1398         .fail(function() {
1399             alert('Cannot load required JS library: ' + url);
1400         })
1401         .always(function() {
1402             if(typeof callback === 'function')
1403                 callback();
1404         })
1405     }
1406
1407     var bootstrapTableLoaded = false;
1408     function loadBootstrapTable(callback) {
1409         if(bootstrapTableLoaded === false) {
1410             bootstrapTableLoaded === true;
1411             loadJs(NETDATA.serverDefault + 'lib/bootstrap-table-1.11.0.min.js', function() {
1412                 loadJs(NETDATA.serverDefault + 'lib/bootstrap-table-export-1.11.0.min.js', function() {
1413                     loadJs(NETDATA.serverDefault + 'lib/tableExport-1.6.0.min.js', callback);
1414                 })
1415             });
1416         }
1417         else callback();
1418     }
1419
1420     function alarmsUpdateModal() {
1421         var active = '<h3>Raised Alarms</h3><table class="table">';
1422         var all = '<h3>All Running Alarms</h3><div class="panel-group" id="alarms_all_accordion" role="tablist" aria-multiselectable="true">';
1423         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.';
1424
1425         NETDATA.alarms.get('all', function(data) {
1426             options.alarm_families = new Array();
1427
1428             alarmsCallback(data);
1429
1430             if(data === null) {
1431                 document.getElementById('alarms_active').innerHTML =
1432                         document.getElementById('alarms_all').innerHTML =
1433                                 document.getElementById('alarms_log').innerHTML =
1434                                         'failed to load alarm data!';
1435                 return;
1436             }
1437
1438             function alarmid4human(id) {
1439                 if(id === 0)
1440                     return '-';
1441
1442                 return id.toString();
1443             }
1444
1445             function timestamp4human(timestamp, space) {
1446                 if(timestamp === 0)
1447                     return '-';
1448
1449                 if(typeof space === 'undefined')
1450                     space = '&nbsp;';
1451
1452                 var t = new Date(timestamp * 1000);
1453                 var now = new Date();
1454
1455                 if(t.toDateString() == now.toDateString())
1456                     return t.toLocaleTimeString();
1457
1458                 return t.toLocaleDateString() + space + t.toLocaleTimeString();
1459             }
1460
1461             function seconds4human(seconds, options) {
1462                 var default_options = {
1463                     now: 'now',
1464                     space: '&nbsp;',
1465                     negative_suffix: 'ago',
1466                     hour: 'hour',
1467                     hours: 'hours',
1468                     minute: 'minute',
1469                     minutes: 'minutes',
1470                     second: 'second',
1471                     seconds: 'seconds',
1472                     and: 'and'
1473                 };
1474
1475                 if(typeof options !== 'object')
1476                     options = default_options;
1477                 else {
1478                     var x;
1479                     for(x in default_options) {
1480                         if(typeof options[x] !== 'string')
1481                             options[x] = default_options[x];
1482                     }
1483                 }
1484
1485                 if(typeof seconds === 'string')
1486                     seconds = parseInt(seconds);
1487
1488                 if(seconds === 0)
1489                     return options.now;
1490
1491                 var suffix = '';
1492                 if(seconds < 0) {
1493                     seconds = -seconds;
1494                     if(options.negative_suffix !== '') suffix = options.space + options.negative_suffix;
1495                 }
1496
1497                 var hours = Math.floor(seconds / 3600);
1498                 seconds -= (hours * 3600);
1499
1500                 var minutes = Math.floor(seconds / 60);
1501                 seconds -= (minutes * 60);
1502
1503                 var txt = '';
1504                 
1505                 if(hours > 1) txt += hours.toString() + options.space + options.hours;
1506                 else if(hours === 1) txt += hours.toString() + options.space + options.hour;
1507
1508                 if(hours > 0 && minutes > 0 && seconds == 0)
1509                     txt += options.space + options.and + options.space;
1510                 else if(hours > 0 && minutes > 0 && seconds > 0)
1511                     txt += ',' + options.space;
1512
1513                 if(minutes > 1) txt += minutes.toString() + options.space + options.minutes;
1514                 else if(minutes === 1) txt += minutes.toString() + options.space + options.minute;
1515
1516                 if((minutes > 0 || minutes > 0) && seconds > 0)
1517                     txt += options.space + options.and + options.space;
1518
1519                 if(seconds > 1) txt += Math.floor(seconds).toString() + options.space + options.seconds;
1520                 else if(seconds === 1) txt += Math.floor(seconds).toString() + options.space + options.second;
1521
1522                 return txt + suffix;
1523             }
1524
1525             function alarm_lookup_explain(alarm, chart) {
1526                 var dimensions = ' of all values ';
1527
1528                 if(chart.dimensions.length > 1)
1529                     dimensions = ' of the sum of all dimensions ';
1530
1531                 if(typeof alarm.lookup_dimensions !== 'undefined') {
1532                     var d = alarm.lookup_dimensions.replace('|', ',');
1533                     var x = d.split(',');
1534                     if(x.length > 1)
1535                         dimensions = 'of the sum of dimensions <code>' + alarm.lookup_dimensions + '</code> ';
1536                     else
1537                         dimensions = 'of all values of dimension <code>' + alarm.lookup_dimensions + '</code> ';
1538                 }
1539
1540                 return '<code>' + alarm.lookup_method + '</code> '
1541                     + dimensions + ', of chart <code>' + alarm.chart + '</code>'
1542                     + ', starting <code>' + seconds4human(alarm.lookup_after + alarm.lookup_before) + '</code> and up to <code>' + seconds4human(alarm.lookup_before) + '</code>'
1543                     + ((alarm.lookup_options)?(', with options <code>' + alarm.lookup_options.replace(' ', ',&nbsp;') + '</code>'):'')
1544                     + '.';
1545             }
1546
1547             function alarm_to_html(alarm, full) {
1548                 var chart = options.data.charts[alarm.chart];
1549
1550                 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>'
1551                     + '<td><table class="table">'
1552                     + ((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>'):'')
1553                     + ((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>'):'');
1554
1555                 if(full === true) {
1556                         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>'):'')
1557                         + ((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>'):'')
1558                         + ((chart.green !== null)?('<tr><td width="10%" style="text-align:right">green&nbsp;threshold</td><td><code>' + chart.green + ' ' + chart.units + '</code></td></tr>'):'')
1559                         + ((chart.red !== null)?('<tr><td width="10%" style="text-align:right">red&nbsp;threshold</td><td><code>' + chart.red + ' ' + chart.units + '</code></td></tr>'):'');
1560                 }
1561
1562                 var delay = '';
1563                 if((alarm.delay_up_duration > 0 || alarm.delay_down_duration > 0) && alarm.delay_multiplier != 0 && alarm.delay_max_duration > 0) {
1564                     if(alarm.delay_up_duration == alarm.delay_down_duration) {
1565                         delay += '<small><br/>hysteresis ' + seconds4human(alarm.delay_up_duration, { negative_suffix: '' });
1566                     }
1567                     else {
1568                         delay = '<small><br/>hysteresis ';
1569                         if(alarm.delay_up_duration > 0) {
1570                             delay += 'on&nbsp;escalation&nbsp;<code>' + seconds4human(alarm.delay_up_duration, { negative_suffix: '' }) + '</code>, ';
1571                         }
1572                         if(alarm.delay_down_duration > 0) {
1573                             delay += 'on&nbsp;recovery&nbsp;<code>' + seconds4human(alarm.delay_down_duration, { negative_suffix: '' }) + '</code>, ';
1574                         }
1575                     }
1576                     if(alarm.delay_multiplier != 1.0) {
1577                         delay += 'multiplied&nbsp;by&nbsp;<code>' + alarm.delay_multiplier.toString() + '</code>';
1578                         delay += ',&nbsp;up&nbsp;to&nbsp;<code>' + seconds4human(alarm.delay_max_duration, { negative_suffix: '' }) + '</code>';
1579                     }
1580                     delay += '</small>';
1581                 }
1582
1583                 html += '<tr><td width="10%" style="text-align:right">check&nbsp;every</td><td>' + seconds4human(alarm.update_every, { negative_suffix: '' }) + '</td></tr>'
1584                     + '<tr><td width="10%" style="text-align:right">execute</td><td><span style="font-family: monospace;">' + alarm.exec + '</span>' + delay + '</td></tr>'
1585                     + '<tr><td width="10%" style="text-align:right">source</td><td><span style="font-family: monospace;">' + alarm.source + '</span></td></tr>'
1586                     + '</table></td></tr>';
1587
1588                 return html;
1589             }
1590
1591             function alarm_family_show(id) {
1592                 var html = '<table class="table">';
1593                 var family = options.alarm_families[id];
1594                 var len = family.arr.length;
1595                 while(len--) {
1596                     var alarm = family.arr[len];
1597                     html += alarm_to_html(alarm, true);
1598                 }
1599                 html += '</table>';
1600
1601                 $('#alarm_all_' + id.toString()).html(html);
1602             }
1603
1604             // find the proper family of each alarm
1605             var now = new Date().getTime();
1606             var x;
1607             var count_active = 0;
1608             var count_all = 0;
1609             var families = {};
1610             var families_sort = new Array();
1611             for(x in data.alarms) {
1612                 var alarm = data.alarms[x];
1613                 var family = alarm.family;
1614
1615                 // find the chart
1616                 var chart = options.data.charts[alarm.chart];
1617                 if(typeof chart === 'undefined')
1618                     chart = options.data.charts_by_name[alarm.chart];
1619
1620                 // not found - this should never happen!
1621                 if(typeof chart === 'undefined') {
1622                     console.log('WARNING: alarm ' + x + ' is linked to chart ' + alarm.chart + ', which is not found in the list of chart got from the server.');
1623                     chart = { priority: 9999999 };
1624                 }
1625                 else if(typeof chart.menu !== 'undefined' && typeof chart.submenu !== 'undefined')
1626                     // the family based on the chart
1627                     family = chart.menu + ' - ' + chart.submenu;
1628
1629                 if(typeof families[family] === 'undefined') {
1630                     families[family] = {
1631                         name: family,
1632                         arr: new Array(),
1633                         priority: chart.priority
1634                     };
1635
1636                     families_sort.push(families[family]);
1637                 }
1638
1639                 if(chart.priority < families[family].priority)
1640                     families[family].priority = chart.priority;
1641
1642                 families[family].arr.unshift(alarm);
1643             }
1644
1645             // sort the families, like the dashboard menu does
1646             var families_sorted = families_sort.sort(function (a, b) {
1647                 if (a.priority > b.priority) return -1;
1648                 if (a.priority < b.priority) return 1;
1649                 return 0;
1650             });
1651
1652             var fc = 0;
1653             var len = families_sorted.length;
1654             while(len--) {
1655                 var family = families_sorted[len].name;
1656                 var active_family_added = false;
1657                 var expanded = 'true';
1658                 var collapsed = '';
1659                 var cin = 'in';
1660
1661                 if(fc !== 0) {
1662                     all += "</table></div></div></div>";
1663                     expanded = 'false';
1664                     collapsed = 'class="collapsed"'
1665                     cin = '';
1666                 }
1667
1668                 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() + '">';
1669
1670                 options.alarm_families[fc] = families[family];
1671
1672                 fc++;
1673
1674                 var arr = families[family].arr;
1675                 var c = arr.length;
1676                 while(c--) {
1677                     var alarm = arr[c];
1678                     if(alarm.status === 'WARNING' || alarm.status === 'CRITICAL') {
1679                         if(!active_family_added) {
1680                             active_family_added = true;
1681                             active += '<tr><th class="text-center" colspan="2"><h4>' + family + '</h4></th></tr>';
1682                         }
1683                         count_active++;
1684                         active += alarm_to_html(alarm, true);
1685                     }
1686
1687                     count_all++;
1688                 }
1689             }
1690             active += "</table>";
1691             if(families_sorted.length > 0) all += "</div></div></div>";
1692             all += "</div>";
1693
1694             if(!count_active)
1695                 active += "<h4>Everything is normal. No raised alarms.</h4>";
1696             else
1697                 active += footer;
1698
1699             if(!count_all)
1700                 all += "<h4>No alarms are running in this system.</h4>";
1701             else
1702                 all += footer;
1703
1704             document.getElementById('alarms_active').innerHTML = active;
1705             document.getElementById('alarms_all').innerHTML = all;
1706
1707             if(families_sorted.length > 0) alarm_family_show(0);
1708
1709             // register bootstrap events
1710             $('#alarms_all_accordion').on('show.bs.collapse', function (d) {
1711                 var target = $(d.target);
1712                 var id = $(target).data('alarm-id');
1713                 alarm_family_show(id);
1714             });
1715             $('#alarms_all_accordion').on('hidden.bs.collapse', function (d) {
1716                 var target = $(d.target);
1717                 var id = $(target).data('alarm-id');
1718                 $('#alarm_all_' + id.toString()).html('');
1719             });
1720
1721             document.getElementById('alarms_log').innerHTML = '<h3>Alarm Log</h3><table id="alarms_log_table"></table>';
1722
1723             loadBootstrapTable(function () {
1724                 $('#alarms_log_table').bootstrapTable({
1725                     url: NETDATA.alarms.server + '/api/v1/alarm_log?all',
1726                     cache: false,
1727                     pagination: true,
1728                     pageSize: 10,
1729                     showPaginationSwitch: false,
1730                     search: true,
1731                     searchTimeOut: 300,
1732                     searchAlign: 'left',
1733                     showColumns: true,
1734                     showExport: true,
1735                     exportDataType: 'basic',
1736                     exportOptions: {
1737                         fileName: 'netdata_alarm_log'
1738                     },
1739                     rowStyle: function(row, index) {
1740                         switch(row.status) {
1741                             case 'CRITICAL' : return { classes: 'danger'  }; break;
1742                             case 'WARNING'  : return { classes: 'warning' }; break;
1743                             case 'UNDEFINED': return { classes: 'info'    }; break;
1744                             case 'CLEAR'    : return { classes: 'success' }; break;
1745                         }
1746                         return {};
1747                     },
1748                     showFooter: false,
1749                     showHeader: true,
1750                     showRefresh: true,
1751                     showToggle: false,
1752                     sortable: true,
1753                     silentSort: false,
1754                     columns: [
1755                         {
1756                             field: 'when',
1757                             title: 'Event Date',
1758                             valign: 'middle',
1759                             titleTooltip: 'The date and time the even took place',
1760                             formatter: function(value, row, index) { return timestamp4human(value, ' '); },
1761                             align: 'center',
1762                             valign: 'middle',
1763                             switchable: false,
1764                             sortable: true
1765                         },
1766                         {
1767                             field: 'hostname',
1768                             title: 'Host',
1769                             valign: 'middle',
1770                             titleTooltip: 'The host that generated this event',
1771                             align: 'center',
1772                             valign: 'middle',
1773                             visible: false,
1774                             sortable: true
1775                         },
1776                         {
1777                             field: 'unique_id',
1778                             title: 'Unique ID',
1779                             titleTooltip: 'The host unique ID for this event',
1780                             formatter: function(value, row, index) { return alarmid4human(value); },
1781                             align: 'center',
1782                             valign: 'middle',
1783                             visible: false,
1784                             sortable: true
1785                         },
1786                         {
1787                             field: 'alarm_id',
1788                             title: 'Alarm ID',
1789                             titleTooltip: 'The ID of the alarm that generated this event',
1790                             formatter: function(value, row, index) { return alarmid4human(value); },
1791                             align: 'center',
1792                             valign: 'middle',
1793                             visible: false,
1794                             sortable: true
1795                         },
1796                         {
1797                             field: 'alarm_event_id',
1798                             title: 'Alarm Event ID',
1799                             titleTooltip: 'The incremental ID of this event for the given alarm',
1800                             formatter: function(value, row, index) { return alarmid4human(value); },
1801                             align: 'center',
1802                             valign: 'middle',
1803                             visible: false,
1804                             sortable: true
1805                         },
1806                         {
1807                             field: 'chart',
1808                             title: 'Chart',
1809                             titleTooltip: 'The chart the alarm is attached to',
1810                             align: 'center',
1811                             valign: 'middle',
1812                             switchable: false,
1813                             sortable: true
1814                         },
1815                         {
1816                             field: 'family',
1817                             title: 'Family',
1818                             titleTooltip: 'The family of the chart the alarm is attached to',
1819                             align: 'center',
1820                             valign: 'middle',
1821                             visible: false,
1822                             sortable: true
1823                         },
1824                         {
1825                             field: 'name',
1826                             title: 'Alarm',
1827                             titleTooltip: 'The alarm name that generated this event',
1828                             formatter: function(value, row, index) {
1829                                 return value.toString().replace(/_/g, ' ');
1830                             },
1831                             align: 'center',
1832                             valign: 'middle',
1833                             switchable: false,
1834                             sortable: true
1835                         },
1836                         {
1837                             field: 'old_value',
1838                             title: 'Old Value',
1839                             titleTooltip: 'The value of the alarm, just before this event',
1840                             formatter: function(value, row, index) {
1841                                 return ((value !== null)?Math.round(value * 100) / 100:'NaN').toString();
1842                             },
1843                             align: 'center',
1844                             valign: 'middle',
1845                             visible: false,
1846                             sortable: true
1847                         },
1848                         {
1849                             field: 'value',
1850                             title: 'Value',
1851                             titleTooltip: 'The value of the alarm, that triggered this event',
1852                             formatter: function(value, row, index) {
1853                                 return ((value !== null)?Math.round(value * 100) / 100:'NaN').toString();
1854                             },
1855                             align: 'right',
1856                             valign: 'middle',
1857                             sortable: true
1858                         },
1859                         {
1860                             field: 'units',
1861                             title: 'Units',
1862                             titleTooltip: 'The units of the value of the alarm',
1863                             align: 'left',
1864                             valign: 'middle',
1865                             sortable: true
1866                         },
1867                         {
1868                             field: 'old_status',
1869                             title: 'Old Status',
1870                             titleTooltip: 'The status of the alarm, just before this event',
1871                             align: 'center',
1872                             valign: 'middle',
1873                             visible: false,
1874                             sortable: true
1875                         },
1876                         {
1877                             field: 'status',
1878                             title: 'Status',
1879                             titleTooltip: 'The status of the alarm, that was set due to this event',
1880                             align: 'center',
1881                             valign: 'middle',
1882                             switchable: false,
1883                             sortable: true
1884                         },
1885                         {
1886                             field: 'duration',
1887                             title: 'Last Duration',
1888                             titleTooltip: 'The duration the alarm was at its previous state, just before this event',
1889                             formatter: function(value, row, index) { return seconds4human(value, { negative_suffix: '', space: ' ', now: 'no time' }); },
1890                             align: 'center',
1891                             valign: 'middle',
1892                             visible: false,
1893                             sortable: true
1894                         },
1895                         {
1896                             field: 'non_clear_duration',
1897                             title: 'Raised Duration',
1898                             titleTooltip: 'The duration the alarm was raised, just before this event',
1899                             formatter: function(value, row, index) { return seconds4human(value, { negative_suffix: '', space: ' ', now: 'no time' }); },
1900                             align: 'center',
1901                             valign: 'middle',
1902                             visible: false,
1903                             sortable: true
1904                         },
1905                         {
1906                             field: 'recipient',
1907                             title: 'Recipient',
1908                             titleTooltip: 'The recipient of this event',
1909                             align: 'center',
1910                             valign: 'middle',
1911                             visible: false,
1912                             sortable: true
1913                         },
1914                         {
1915                             field: 'processed',
1916                             title: 'Processed Status',
1917                             titleTooltip: 'True when this event is processed',
1918                             formatter: function(value, row, index) {
1919                                 if(value === true)
1920                                     return 'DONE';
1921                                 else
1922                                     return 'PENDING';
1923                             },
1924                             align: 'center',
1925                             valign: 'middle',
1926                             visible: false,
1927                             sortable: true
1928                         },
1929                         {
1930                             field: 'updated',
1931                             title: 'Updated Status',
1932                             titleTooltip: 'True when this event has been updated by another event',
1933                             formatter: function(value, row, index) {
1934                                 if(value === true)
1935                                     return 'UPDATED';
1936                                 else
1937                                     return 'CURRENT';
1938                             },
1939                             align: 'center',
1940                             valign: 'middle',
1941                             visible: false,
1942                             sortable: true
1943                         },
1944                         {
1945                             field: 'updated_by_id',
1946                             title: 'Updated By ID',
1947                             titleTooltip: 'The unique ID of the event that obsoleted this one',
1948                             formatter: function(value, row, index) { return alarmid4human(value); },
1949                             align: 'center',
1950                             valign: 'middle',
1951                             visible: false,
1952                             sortable: true
1953                         },
1954                         {
1955                             field: 'updates_id',
1956                             title: 'Updates ID',
1957                             titleTooltip: 'The unique ID of the event obsoleted because of this event',
1958                             formatter: function(value, row, index) { return alarmid4human(value); },
1959                             align: 'center',
1960                             valign: 'middle',
1961                             visible: false,
1962                             sortable: true
1963                         },
1964                         {
1965                             field: 'exec',
1966                             title: 'Script',
1967                             titleTooltip: 'The script to handle the event notification',
1968                             align: 'center',
1969                             valign: 'middle',
1970                             visible: false,
1971                             sortable: true
1972                         },
1973                         {
1974                             field: 'exec_run',
1975                             title: 'Script Run At',
1976                             titleTooltip: 'The date and time the script has been ran',
1977                             formatter: function(value, row, index) { return timestamp4human(value, ' '); },
1978                             align: 'center',
1979                             valign: 'middle',
1980                             visible: false,
1981                             sortable: true
1982                         },
1983                         {
1984                             field: 'exec_code',
1985                             title: 'Script Return Value',
1986                             titleTooltip: 'The return code of the script',
1987                             formatter: function(value, row, index) {
1988                                 if(value === 0)
1989                                     return 'OK (returned 0)';
1990                                 else
1991                                     return 'FAILED (with code ' + value.toString() + ')';
1992                             },
1993                             align: 'center',
1994                             valign: 'middle',
1995                             visible: false,
1996                             sortable: true
1997                         },
1998                         {
1999                             field: 'delay',
2000                             title: 'Script Delay',
2001                             titleTooltip: 'The hysteresis of the notification',
2002                             formatter: function(value, row, index) { return seconds4human(value, { negative_suffix: '', space: ' ', now: 'no time' }); },
2003                             align: 'center',
2004                             valign: 'middle',
2005                             visible: false,
2006                             sortable: true
2007                         },
2008                         {
2009                             field: 'delay_up_to_timestamp',
2010                             title: 'Script Delay Run At',
2011                             titleTooltip: 'The date and time the script should be run, after hysteresis',
2012                             formatter: function(value, row, index) { return timestamp4human(value, ' '); },
2013                             align: 'center',
2014                             valign: 'middle',
2015                             visible: false,
2016                             sortable: true
2017                         },
2018                         {
2019                             field: 'info',
2020                             title: 'Description',
2021                             titleTooltip: 'A short description of the alarm',
2022                             align: 'center',
2023                             valign: 'middle',
2024                             visible: false,
2025                             sortable: true
2026                         },
2027                         {
2028                             field: 'source',
2029                             title: 'Alarm Source',
2030                             titleTooltip: 'The source of configuration of the alarm',
2031                             align: 'center',
2032                             valign: 'middle',
2033                             visible: false,
2034                             sortable: true
2035                         }
2036                     ]
2037                 });
2038                 // console.log($('#alarms_log_table').bootstrapTable('getOptions'));
2039             });
2040         });
2041     }
2042
2043     function alarmsCallback(data) {
2044         var count = 0;
2045         for(x in data.alarms) {
2046             var alarm = data.alarms[x];
2047             if(alarm.status === 'WARNING' || alarm.status === 'CRITICAL')
2048                 count++;
2049         }
2050
2051         if(count > 0)
2052             document.getElementById('alarms_count_badge').innerHTML = count.toString();
2053         else
2054             document.getElementById('alarms_count_badge').innerHTML = '';
2055     }
2056
2057     function initializeDynamicDashboard(netdata_url) {
2058         if(typeof netdata_url === 'undefined' || netdata_url === null)
2059             netdata_url = NETDATA.serverDefault;
2060
2061         // initialize clickable alarms
2062         NETDATA.alarms.chart_div_offset = 100;
2063         NETDATA.alarms.chart_div_id_prefix = 'chart_';
2064         NETDATA.alarms.chart_div_animation_duration = 0;
2065
2066         NETDATA.pause(function() {
2067             NETDATA.alarms.callback = alarmsCallback;
2068
2069             // download all the charts the server knows
2070             NETDATA.chartRegistry.downloadAll(netdata_url, function(data) {
2071                 if(data !== null) {
2072                     options.hostname = data.hostname;
2073                     options.data = data;
2074
2075                     // update the dashboard hostname
2076                     document.getElementById('hostname').innerHTML = options.hostname;
2077                     document.getElementById('hostname').href = NETDATA.serverDefault;
2078
2079                     // update the dashboard title
2080                     document.title = options.hostname + ' netdata dashboard';
2081
2082                     // close the splash screen
2083                     $("#loadOverlay").css("display","none");
2084
2085                     // create a chart_by_name index
2086                     data.charts_by_name = {};
2087                     var charts = data.charts;
2088                     var x;
2089                     for(x in charts) {
2090                         var chart = charts[x];
2091                         data.charts_by_name[chart.name] = chart;
2092                     }
2093
2094                     // render all charts
2095                     renderChartsAndMenu(data);
2096                 }
2097             });
2098         });
2099     }
2100
2101     // ----------------------------------------------------------------------------
2102
2103     function versionLog(msg) {
2104         document.getElementById('versionCheckLog').innerHTML = msg;
2105     }
2106
2107     function getNetdataVersion(callback) {
2108         versionLog('Downloading installed version info from netdata...');
2109
2110         $.ajax({
2111             url: 'version.txt',
2112             async: true,
2113             cache: false,
2114             xhrFields: { withCredentials: true } // required for the cookie
2115         })
2116         .done(function(data) {
2117             data = data.replace(/(\r\n|\n|\r| |\t)/gm,"");
2118             if(data.length !== 40) {
2119                 versionLog('Received version string is invalid.');
2120                 callback(null);
2121             }
2122             else {
2123                 versionLog('Installed version of netdata is ' + data);
2124                 document.getElementById('netdataVersion').innerHTML = data;
2125                 callback(data);
2126             }
2127         })
2128         .fail(function() {
2129             versionLog('Failed to download installed version info from netdata!');
2130             callback(null);
2131         });
2132     }
2133
2134     function getGithubLatestCommit(callback) {
2135         versionLog('Downloading latest version info from github...');
2136
2137         $.ajax({
2138             url: 'https://api.github.com/repos/firehol/netdata/commits',
2139             async: true,
2140             cache: false
2141         })
2142         .done(function(data) {
2143             versionLog('Latest version info from github is ' + data[0].sha);
2144             callback(data[0].sha);
2145         })
2146         .fail(function() {
2147             versionLog('Failed to download installed version info from github!');
2148             callback(null);
2149         });
2150     }
2151
2152     function checkForUpdate(callback) {
2153         getNetdataVersion(function(sha1) {
2154             if(sha1 === null) callback(null, null);
2155
2156             getGithubLatestCommit(function(sha2) {
2157                 callback(sha1, sha2);
2158             });
2159         });
2160
2161         return null;
2162     }
2163
2164     function notifyForUpdate(force) {
2165         versionLog('<p>checking for updates...</p>');
2166
2167         var now = new Date().getTime();
2168
2169         if(typeof force === 'undefined' || force !== true) {
2170             var last = loadLocalStorage('last_update_check');
2171
2172             if(typeof last === 'string')
2173                 last = parseInt(last);
2174             else
2175                 last = 0;
2176
2177             if(now - last < 3600000 * 8) {
2178                 // no need to check it - too soon
2179                 return;
2180             }
2181         }
2182
2183         checkForUpdate(function(sha1, sha2) {
2184             var save = false;
2185
2186             if(sha1 === null) {
2187                 save = false;
2188                 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>');
2189             }
2190             else if(sha2 === null) {
2191                 save = false;
2192                 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>');
2193             }
2194             else if(sha1 === sha2) {
2195                 save = true;
2196                 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>');
2197             }
2198             else {
2199                 save = true;
2200                 var compare = 'https://github.com/firehol/netdata/compare/' + sha1.toString() + '...' + sha2.toString();
2201
2202                 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>');
2203
2204                 document.getElementById('update_badge').innerHTML = '!';
2205             }
2206
2207             if(save)
2208                 saveLocalStorage('last_update_check', now.toString());
2209         });
2210     }
2211
2212     // ----------------------------------------------------------------------------
2213
2214     function finalizePage() {
2215         // resize all charts - without starting the background thread
2216         // this has to be done while NETDATA is paused
2217         // if we ommit this, the affix menu will be wrong, since all
2218         // the Dom elements are initially zero-sized
2219         NETDATA.parseDom();
2220
2221         if(urlOptions.pan_and_zoom === true)
2222             NETDATA.globalPanAndZoom.setMaster(NETDATA.options.targets[0], urlOptions.after, urlOptions.before);
2223
2224         // ------------------------------------------------------------------------
2225         // https://github.com/viralpatel/jquery.shorten/blob/master/src/jquery.shorten.js
2226         $.fn.shorten = function(settings) {
2227             "use strict";
2228
2229             var config = {
2230                 showChars: 750,
2231                 minHideChars: 10,
2232                 ellipsesText: "...",
2233                 moreText: '<i class="fa fa-expand" aria-hidden="true"></i> show more information',
2234                 lessText: '<i class="fa fa-compress" aria-hidden="true"></i> show less information',
2235                 onLess: function() { NETDATA.onscroll(); },
2236                 onMore: function() { NETDATA.onscroll(); },
2237                 errMsg: null,
2238                 force: false
2239             };
2240
2241             if (settings) {
2242                 $.extend(config, settings);
2243             }
2244
2245             if ($(this).data('jquery.shorten') && !config.force) {
2246                 return false;
2247             }
2248             $(this).data('jquery.shorten', true);
2249
2250             $(document).off("click", '.morelink');
2251
2252             $(document).on({
2253                 click: function() {
2254
2255                     var $this = $(this);
2256                     if ($this.hasClass('less')) {
2257                         $this.removeClass('less');
2258                         $this.html(config.moreText);
2259                         $this.parent().prev().animate({'height':'0'+'%'}, 0, function () { $this.parent().prev().prev().show(); }).hide(0, function() {
2260                             config.onLess();
2261                         });
2262
2263                     } else {
2264                         $this.addClass('less');
2265                         $this.html(config.lessText);
2266                         $this.parent().prev().animate({'height':'100'+'%'}, 0, function () { $this.parent().prev().prev().hide(); }).show(0, function() {
2267                             config.onMore();
2268                         });
2269                     }
2270                     return false;
2271                 }
2272             }, '.morelink');
2273
2274             return this.each(function() {
2275                 var $this = $(this);
2276
2277                 var content = $this.html();
2278                 var contentlen = $this.text().length;
2279                 if (contentlen > config.showChars + config.minHideChars) {
2280                     var c = content.substr(0, config.showChars);
2281                     if (c.indexOf('<') >= 0) // If there's HTML don't want to cut it
2282                     {
2283                         var inTag = false; // I'm in a tag?
2284                         var bag = ''; // Put the characters to be shown here
2285                         var countChars = 0; // Current bag size
2286                         var openTags = []; // Stack for opened tags, so I can close them later
2287                         var tagName = null;
2288
2289                         for (var i = 0, r = 0; r <= config.showChars; i++) {
2290                             if (content[i] == '<' && !inTag) {
2291                                 inTag = true;
2292
2293                                 // This could be "tag" or "/tag"
2294                                 tagName = content.substring(i + 1, content.indexOf('>', i));
2295
2296                                 // If its a closing tag
2297                                 if (tagName[0] == '/') {
2298
2299
2300                                     if (tagName != '/' + openTags[0]) {
2301                                         config.errMsg = 'ERROR en HTML: the top of the stack should be the tag that closes';
2302                                     } else {
2303                                         openTags.shift(); // Pops the last tag from the open tag stack (the tag is closed in the retult HTML!)
2304                                     }
2305
2306                                 } else {
2307                                     // There are some nasty tags that don't have a close tag like <br/>
2308                                     if (tagName.toLowerCase() != 'br') {
2309                                         openTags.unshift(tagName); // Add to start the name of the tag that opens
2310                                     }
2311                                 }
2312                             }
2313                             if (inTag && content[i] == '>') {
2314                                 inTag = false;
2315                             }
2316
2317                             if (inTag) { bag += content.charAt(i); } // Add tag name chars to the result
2318                             else {
2319                                 r++;
2320                                 if (countChars <= config.showChars) {
2321                                     bag += content.charAt(i); // Fix to ie 7 not allowing you to reference string characters using the []
2322                                     countChars++;
2323                                 } else // Now I have the characters needed
2324                                 {
2325                                     if (openTags.length > 0) // I have unclosed tags
2326                                     {
2327                                         //console.log('They were open tags');
2328                                         //console.log(openTags);
2329                                         for (j = 0; j < openTags.length; j++) {
2330                                             //console.log('Cierro tag ' + openTags[j]);
2331                                             bag += '</' + openTags[j] + '>'; // Close all tags that were opened
2332
2333                                             // 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
2334                                         }
2335                                         break;
2336                                     }
2337                                 }
2338                             }
2339                         }
2340                         c = $('<div/>').html(bag + '<span class="ellip">' + config.ellipsesText + '</span>').html();
2341                     }else{
2342                         c+=config.ellipsesText;
2343                     }
2344
2345                     var html = '<div class="shortcontent">' + c +
2346                             '</div><div class="allcontent">' + content +
2347                             '</div><span><a href="javascript://nop/" class="morelink">' + config.moreText + '</a></span>';
2348
2349                     $this.html(html);
2350                     $this.find(".allcontent").hide(); // Hide all text
2351                     $('.shortcontent p:last', $this).css('margin-bottom', 0); //Remove bottom margin on last paragraph as it's likely shortened
2352                 }
2353             });
2354
2355         };
2356         $(".chart-message").shorten();
2357         // ------------------------------------------------------------------------
2358
2359         // callback for us to track PanAndZoom operations
2360         NETDATA.globalPanAndZoom.callback = urlOptions.netdataPanAndZoomCallback;
2361
2362         // let it run (update the charts)
2363         NETDATA.unpause();
2364
2365         // check if we have to jump to a specific section
2366         scrollToId(urlOptions.hash.replace('#',''));
2367
2368         if(urlOptions.chart !== null) {
2369             NETDATA.alarms.scrollToChart(urlOptions.chart);
2370             //urlOptions.hash = '#' + NETDATA.name2id('menu_' + charts[c].menu + '_submenu_' + charts[c].submenu);
2371             //urlOptions.hash = '#chart_' + NETDATA.name2id(urlOptions.chart);
2372             //console.log('hash = ' + urlOptions.hash);
2373         }
2374
2375         /* activate bootstrap sidebar (affix) */
2376         $('#sidebar').affix({
2377             offset: {
2378                 top: (isdemo())?150:0,
2379                 bottom: 0
2380             }
2381         });
2382
2383         /* fix scrolling of very long affix lists
2384            http://stackoverflow.com/questions/21691585/bootstrap-3-1-0-affix-too-long
2385          */
2386         $('#sidebar').on('affixed.bs.affix', function() {
2387             $(this).removeAttr('style');
2388         });
2389
2390         /* activate bootstrap scrollspy (needed for sidebar) */
2391         $(document.body).scrollspy({
2392             target: '#sidebar',
2393             offset: $(window).height() / 5 // controls the diff of the <hX> element to the top, to select it
2394         });
2395
2396         // change the URL based on the current position of the screen
2397         $('#sidebar').on('activate.bs.scrollspy', function (e) {
2398             // console.log(e);
2399             var el = $(e.target);
2400             //if(el.find('ul').size() == 0) {
2401             var hash = el.find('a').attr('href');
2402             if(typeof hash === 'string' && hash.substring(0, 1) === '#' && urlOptions.hash.startsWith(hash + '_submenu_') === false) {
2403                 urlOptions.hash = hash;
2404                 //console.log(urlOptions.hash);
2405                 urlOptions.hashUpdate();
2406             }
2407             //else console.log('hash: not accepting ' + hash);
2408             //}
2409             //else console.log('el.find(): not found');
2410         });
2411
2412         document.getElementById('footer').style.display = 'block';
2413
2414         var update_options_modal = function() {
2415             // console.log('update_options_modal');
2416
2417             var sync_option = function(option) {
2418                 var self = $('#' + option);
2419
2420                 if(self.prop('checked') !== NETDATA.getOption(option)) {
2421                     // console.log('switching ' + option.toString());
2422                     self.bootstrapToggle(NETDATA.getOption(option)?'on':'off');
2423                 }
2424             }
2425
2426             var theme_sync_option = function(option) {
2427                 var self = $('#' + option);
2428
2429                 self.bootstrapToggle(netdataTheme === 'slate'?'on':'off');
2430             }
2431
2432             sync_option('eliminate_zero_dimensions');
2433             sync_option('destroy_on_hide');
2434             sync_option('async_on_scroll');
2435             sync_option('parallel_refresher');
2436             sync_option('concurrent_refreshes');
2437             sync_option('sync_selection');
2438             sync_option('sync_pan_and_zoom');
2439             sync_option('stop_updates_when_focus_is_lost');
2440             sync_option('smooth_plot');
2441             sync_option('pan_and_zoom_data_padding');
2442             sync_option('show_help');
2443             theme_sync_option('netdata_theme_control');
2444
2445             if(NETDATA.getOption('parallel_refresher') === false) {
2446                 $('#concurrent_refreshes_row').hide();
2447             }
2448             else {
2449                 $('#concurrent_refreshes_row').show();
2450             }
2451         };
2452         NETDATA.setOption('setOptionCallback', update_options_modal);
2453
2454         // handle options changes
2455         $('#eliminate_zero_dimensions').change(function()       { NETDATA.setOption('eliminate_zero_dimensions', $(this).prop('checked')); });
2456         $('#destroy_on_hide').change(function()                 { NETDATA.setOption('destroy_on_hide', $(this).prop('checked')); });
2457         $('#async_on_scroll').change(function()                 { NETDATA.setOption('async_on_scroll', $(this).prop('checked')); });
2458         $('#parallel_refresher').change(function()              { NETDATA.setOption('parallel_refresher', $(this).prop('checked')); });
2459         $('#concurrent_refreshes').change(function()            { NETDATA.setOption('concurrent_refreshes', $(this).prop('checked')); });
2460         $('#sync_selection').change(function()                  { NETDATA.setOption('sync_selection', $(this).prop('checked')); });
2461         $('#sync_pan_and_zoom').change(function()               { NETDATA.setOption('sync_pan_and_zoom', $(this).prop('checked')); });
2462         $('#stop_updates_when_focus_is_lost').change(function() {
2463             urlOptions.update_always = !$(this).prop('checked');
2464             urlOptions.hashUpdate();
2465
2466             NETDATA.setOption('stop_updates_when_focus_is_lost', !urlOptions.update_always);
2467         });
2468         $('#smooth_plot').change(function()                     { NETDATA.setOption('smooth_plot', $(this).prop('checked')); });
2469         $('#pan_and_zoom_data_padding').change(function()       { NETDATA.setOption('pan_and_zoom_data_padding', $(this).prop('checked')); });
2470         $('#show_help').change(function()                       {
2471             urlOptions.help = $(this).prop('checked');
2472             urlOptions.hashUpdate();
2473
2474             NETDATA.setOption('show_help', urlOptions.help);
2475             netdataReload();
2476         });
2477
2478         // this has to be the last
2479         // it reloads the page
2480         $('#netdata_theme_control').change(function() {
2481             urlOptions.theme = $(this).prop('checked')?'slate':'white';
2482             urlOptions.hashUpdate();
2483
2484             if(setTheme(urlOptions.theme))
2485                 netdataReload();
2486         });
2487
2488         $('#updateModal').on('shown.bs.modal', function() {
2489             notifyForUpdate(true);
2490         });
2491
2492         $('#alarmsModal').on('shown.bs.modal', function() {
2493             NETDATA.pause(alarmsUpdateModal);
2494         });
2495
2496         $('#alarmsModal').on('hidden.bs.modal', function() {
2497             NETDATA.unpause();
2498             document.getElementById('alarms_active').innerHTML =
2499                     document.getElementById('alarms_all').innerHTML =
2500                     document.getElementById('alarms_log').innerHTML =
2501                             'loading...';
2502         });
2503
2504         $('#deleteRegistryModal').on('hidden.bs.modal', function() {
2505             deleteRegistryGuid = null;
2506         });
2507
2508         if(isdemo()) {
2509             if(urlOptions.nowelcome !== true) {
2510                 setTimeout(function() {
2511                     $('#welcomeModal').modal();
2512                 }, 1000);
2513             }
2514
2515             // google analytics when this is used for the home page of the demo sites
2516             // this does not run on user's installations
2517             setTimeout(function() {
2518                 (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
2519                 (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
2520                 m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
2521                 })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
2522
2523                 ga('create', 'UA-64295674-3', 'auto');
2524                 ga('send', 'pageview');
2525             }, 2000);
2526         }
2527         else notifyForUpdate();
2528
2529         if(urlOptions.show_alarms === true)
2530             setTimeout(function() { $('#alarmsModal').modal('show'); }, 1000);
2531     }
2532
2533     function resetDashboardOptions() {
2534         var help = NETDATA.options.current.show_help;
2535
2536         NETDATA.resetOptions();
2537         if(setTheme('slate'))
2538             netdataReload();
2539
2540         if(help !== NETDATA.options.current.show_help)
2541             netdataReload();
2542     }
2543
2544     // callback to add the dashboard info to the
2545     // parallel javascript downloader in netdata
2546     var netdataPrepCallback = function() {
2547         NETDATA.requiredCSS.push({
2548             url: NETDATA.serverDefault + 'css/bootstrap-toggle-2.2.2.min.css',
2549             isAlreadyLoaded: function() { return false; }
2550         });
2551
2552         NETDATA.requiredJs.push({
2553             url: NETDATA.serverDefault + 'lib/bootstrap-toggle-2.2.2.min.js',
2554             isAlreadyLoaded: function() { return false; }
2555         });
2556
2557         NETDATA.requiredJs.push({
2558             url: NETDATA.serverDefault + 'dashboard_info.js?v20161108-1',
2559             async: false,
2560             isAlreadyLoaded: function() { return false; }
2561         });
2562
2563         if(isdemo()) {
2564             document.getElementById('masthead').style.display = 'block';
2565         }
2566         else {
2567             if(urlOptions.update_always === true)
2568                 NETDATA.setOption('stop_updates_when_focus_is_lost', !urlOptions.update_always);
2569         }
2570     }
2571
2572     // our entry point
2573     var netdataCallback = initializeDynamicDashboard;
2574
2575 </script>
2576
2577 <body data-spy="scroll" data-target="#sidebar">
2578     <div id="loadOverlay" class="loadOverlay" style="background-color: #888; color: #888;">
2579         netdata<br/><div style="font-size: 3vh;">Real-time performance monitoring, done right!</div>
2580     </div>
2581     <script type="text/javascript">
2582         // change the loadOverlay colors ASAP to match the theme
2583         document.getElementById('loadOverlay').style = (urlOptions.theme === 'slate')?"background-color:#272b30; color: #373b40;":"background-color:#fff; color: #ddd;";
2584     </script>
2585     <nav class="navbar navbar-default navbar-fixed-top" role="banner">
2586         <div class="container">
2587             <nav id="mynetdata_nav" class="collapse navbar-collapse navbar-left hidden-sm hidden-xs" role="navigation" style="padding-right: 20px;">
2588                 <ul class="nav navbar-nav">
2589                     <li class="dropdown">
2590                         <a href="#" class="dropdown-toggle" data-toggle="dropdown" id="current_view">my-netdata <strong class="caret"></strong></a>
2591                         <ul class="dropdown-menu scrollable-menu inpagemenu multi-column columns-2" role="menu">
2592                             <div class="row">
2593                                 <div class="col-sm-6" style="width: 85%; padding-right: 0;">
2594                                     <ul id="mynetdata_servers" class="multi-column-dropdown">
2595                                         <li><a href="#" onclick="return false;" style="color: #999;">loading...</a></li>
2596                                     </ul>
2597                                 </div>
2598                                 <div class="col-sm-3 hidden-xs" style="width: 15%; padding-left: 0;">
2599                                     <ul id="mynetdata_actions1" class="multi-column-dropdown">
2600                                     <li style="color: #999;">&nbsp;</li>
2601                                     </ul>
2602                                 </div>
2603                             </div>
2604                         </ul>
2605                     </li>
2606                 </ul>
2607             </nav>
2608             <div class="navbar-header">
2609                 <button class="navbar-toggle" type="button" data-toggle="collapse" data-target=".navbar-collapse">
2610                     <span class="sr-only">Toggle navigation</span>
2611                     <span class="icon-bar"></span>
2612                     <span class="icon-bar"></span>
2613                     <span class="icon-bar"></span>
2614                 </button>
2615                 <a href="/" class="navbar-brand" id="hostname" title="reload the dashboard">netdata</a>
2616             </div>
2617             <nav class="collapse navbar-collapse navbar-right" role="navigation">
2618                 <ul class="nav navbar-nav">
2619                     <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>
2620                     <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>
2621                     <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>
2622                     <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>
2623                     <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>
2624                     <!--
2625                     <li class="dropdown hidden-md hidden-lg hidden-xs">
2626                         <a href="#" class="dropdown-toggle" data-toggle="dropdown" id="current_view">Menu <strong class="caret"></strong></a>
2627                         <ul class="dropdown-menu scrollable-menu inpagemenu" role="menu">
2628                             <li><a href="#" class="btn" data-toggle="modal" data-target="#alarmsModal"><i class="fa fa-bell"></i> alarms</a></li>
2629                             <li><a href="#" class="btn" data-toggle="modal" data-target="#optionsModal"><i class="fa fa-sliders"></i> settings</a></li>
2630                             <li><a href="https://github.com/firehol/netdata/wiki" class="btn" target="_blank"><i class="fa fa-github"></i> community</a></li>
2631                             <li><a href="#" class="btn" data-toggle="modal" data-target="#helpModal"><i class="fa fa-question-circle"></i> help</a></li>
2632                         </ul>
2633                     </li>
2634                     -->
2635                     <li class="dropdown hidden-sm hidden-md hidden-lg">
2636                         <a href="#" class="dropdown-toggle" data-toggle="dropdown" id="current_view">my-netdata <strong class="caret"></strong></a>
2637                         <ul id="mynetdata_servers2" class="dropdown-menu scrollable-menu inpagemenu" role="menu">
2638                             <li><a href="#" onclick="return false;" style="color: #999;">loading...</a></li>
2639                         </ul>
2640                     </li>
2641                 </ul>
2642             </nav>
2643     </nav>
2644         </div>
2645     </nav>
2646
2647     <div id="masthead" style="display: none;">
2648         <div class="container">
2649             <div class="row">
2650                 <div class="col-md-7">
2651                     <h1>Netdata
2652                         <p class="lead">Real-time performance monitoring, in the greatest possible detail</p>
2653                     </h1>
2654                 </div>
2655                 <div class="col-md-5">
2656                     <div class="well well-lg">
2657                         <div class="row">
2658                         <div class="col-md-6">
2659                             <b>Drag</b> charts to pan.
2660                             <b>Shift + wheel</b> on them, to zoom in and out.
2661                             <b>Double-click</b> on them, to reset.
2662                             <b>Hover</b> on them too!
2663                             </div>
2664                         <div class="col-md-6">
2665                             <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>
2666                             </div>
2667                         </div>
2668                     </div>
2669                 </div>
2670             </div>
2671         </div>
2672     </div>
2673
2674     <div class="container">
2675         <div class="row">
2676             <div class="charts-body" role="main">
2677                 <div id="charts_div"></div>
2678             </div>
2679             <div class="sidebar-body hidden-xs hidden-sm" role="complementary">
2680                 <nav class="dashboard-sidebar hidden-print hidden-xs hidden-sm" id="sidebar" role="menu"></nav>
2681             </div>
2682         </div>
2683     </div>
2684
2685     <div id="footer" class="container" style="display: none;">
2686         <div class="row">
2687             <div class="col-md-10" role="main">
2688                 <div class="p">
2689                     <big><a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata</a></big><br/>
2690                     <i class="fa fa-copyright"></i> Copyright 2016, Costa Tsaousis.<br/>
2691                     Released under <a href="http://www.gnu.org/licenses/gpl-3.0.en.html" target="_blank">GPL v3 or later</a>.<br/>
2692                 </div>
2693                 <div class="p">
2694                     <small>
2695                         <a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata</a> re-distributes these software tools:
2696
2697                         <i class="fa fa-circle"></i> The excellent <a href="http://dygraphs.com/" target="_blank">Dygraphs.com</a> web chart library,
2698                         <i class="fa fa-copyright"></i> Copyright 2009, Dan Vanderkam, <a href="http://dygraphs.com/legal.html" target="_blank">MIT License</a>
2699
2700                         <i class="fa fa-circle"></i> <a href="https://rendro.github.io/easy-pie-chart/" target="_blank">Easy Pie Chart</a> web chart library,
2701                         <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>
2702
2703                         <i class="fa fa-circle"></i> <a href="http://bernii.github.io/gauge.js/" target="_blank">Gauge.js</a> web chart library,
2704                         <i class="fa fa-copyright"></i> Copyright, Bernard Kobos, <a href="http://bernii.github.io/gauge.js/" target="_blank">MIT License</a>
2705
2706                         <i class="fa fa-circle"></i> <a href="https://jquery.org/" target="_blank">jQuery</a>,
2707                         <i class="fa fa-copyright"></i> Copyright 2015, jQuery Foundation, <a href="https://jquery.org/license/" target="_blank">MIT License</a>
2708
2709                         <i class="fa fa-circle"></i> <a href="http://getbootstrap.com/getting-started/" target="_blank">Bootstrap</a>,
2710                         <i class="fa fa-copyright"></i> Copyright 2015, Twitter, <a href="http://getbootstrap.com/getting-started/#license-faqs" target="_blank">MIT License</a>
2711
2712                         <i class="fa fa-circle"></i> <a href="http://www.bootstraptoggle.com/" target="_blank">Bootstrap Toggle</a>,
2713                         <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>
2714
2715                         <i class="fa fa-circle"></i> <a href="https://jamesflorentino.github.io/nanoScrollerJS/" target="_blank">NanoScroller</a>,
2716                         <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>
2717
2718                         <i class="fa fa-circle"></i> <a href="https://fortawesome.github.io/Font-Awesome/" target="_blank">FontAwesome</a>,
2719                         <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>
2720
2721                         <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.
2722
2723                         <i class="fa fa-circle"></i> <a href="http://bootstrap-table.wenzhixin.net.cn/" target="_blank">bootstrap-table</a>,
2724                         <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>
2725
2726                         <i class="fa fa-circle"></i> <a href="https://github.com/hhurz/tableExport.jquery.plugin" target="_blank">tableExport.jquery.plugin</a>,
2727                         <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>
2728
2729                     </small>
2730                 </div>
2731             </div>
2732         </div>
2733     </div>
2734
2735     <div class="modal fade" id="welcomeModal" tabindex="-1" role="dialog" aria-labelledby="welcomeModalLabel">
2736         <div class="modal-dialog modal-lg" role="document">
2737             <div class="modal-content">
2738                 <div class="modal-header">
2739                     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
2740                     <h4 class="modal-title" id="welcomeModalLabel">Welcome!</h4>
2741                 </div>
2742                 <div class="modal-body">
2743                         <div class="p">
2744                         <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.
2745                         </div>
2746                         <div class="p">
2747                         <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.
2748                         </div>
2749                         <div class="p">
2750                         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.
2751                         </div>
2752                         <div class="p">
2753                         <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>%),
2754                         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).
2755                         </div>
2756                         <div class="p">
2757                         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>!).
2758                         </div>
2759                         <div class="p">
2760                         For more information please refer to the <b><a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata wiki</a></b>.
2761                         </div>
2762                 </div>
2763                 <div class="modal-footer">
2764                     <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
2765                 </div>
2766             </div>
2767         </div>
2768     </div>
2769
2770     <div class="modal fade" id="helpModal" tabindex="-1" role="dialog" aria-labelledby="helpModalLabel">
2771         <div class="modal-dialog modal-lg" role="document">
2772             <div class="modal-content">
2773                 <div class="modal-header">
2774                     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
2775                     <h4 class="modal-title" id="helpModalLabel">Dashboard Help</h4>
2776                 </div>
2777                 <div class="modal-body">
2778
2779                     <h4>Dygraphs (line, area and stacked area charts)</h4>
2780
2781                     <!-- Nav tabs -->
2782                     <ul class="nav nav-tabs" role="tablist">
2783                         <li role="presentation" class="active"><a href="#help_mouse" aria-controls="help_mouse" role="tab" data-toggle="tab">Mouse Interface</a></li>
2784                         <li role="presentation"><a href="#help_touch" aria-controls="help_touch" role="tab" data-toggle="tab">Touch Interface</a></li>
2785                     </ul>
2786
2787                     <!-- Tab panes -->
2788                     <div class="tab-content">
2789                         <div role="tabpanel" class="tab-pane active" id="help_mouse">
2790                             <div class="p">
2791                                 <h4>Mouse Over / Hover</h4>
2792                                 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).
2793                                 <br/>
2794                                 All the other visible charts will also show and highlight their values for the same timestamp.
2795                             </div>
2796                             <hr/>
2797                             <div class="p">
2798                                 <h4>Drag Chart Contents</h4>
2799                                 Drag the contents of a chart to pan it horizontally.
2800                                 <br/>
2801                                 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).
2802                                 <br/>
2803                                 Once a chart is panned, auto refreshing stops for all charts. To enable it again, <b>double click</b> a panned chart.
2804                             </div>
2805                             <hr/>
2806                             <div class="p">
2807                                 <h4>Double Click</h4>
2808                                 Double Click a chart to reset all the charts to their default auto-refreshing state.
2809                             </div>
2810                             <hr/>
2811                             <div class="p">
2812                                 <h4>SHIFT + Drag</h4>
2813                                 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:
2814                                 <ul>
2815                                     <li>The already loaded chart contents are zoomed (low resolution)</li>
2816                                     <li>New data are transferred from the netdata server, to refresh the chart with possibly more detail.</li>
2817                                 </ul>
2818                                 Once a chart is zoomed, auto refreshing stops for all charts. To enable it again, <b>double click</b> a zoomed chart.
2819                             </div>
2820                             <hr/>
2821                             <div class="p">
2822                                 <h4>SHIFT + Mouse Wheel</h4>
2823                                 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.
2824                                 <br/>
2825                                 Once a chart is zoomed, auto refreshing stops for all charts. To enable it again, <b>double click</b> a zoomed chart.
2826                             </div>
2827                             <hr/>
2828                             <div class="p">
2829                                 <h4>Legend Operations</h4>
2830                                 Click on the label or value of a dimension, will select / un-select this dimension.
2831                                 <br/>
2832                                 You can press any of the SHIFT or CONTROL keys and then click on legend labels or values, to select / un-select multiple dimensions.
2833                             </div>
2834                         </div>
2835                         <div role="tabpanel" class="tab-pane" id="help_touch">
2836                             <div class="p">
2837                                 <h4>Single Tap</h4>
2838                                 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).
2839                                 <br/>
2840                                 All the other visible charts will also show and highlight their values for the same timestamp.
2841                             </div>
2842                             <hr/>
2843                             <div class="p">
2844                                 <h4>Drag Chart Contents</h4>
2845                                 Touch and Drag the contents of a chart to pan it horizontally.
2846                                 <br/>
2847                                 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).
2848                                 <br/>
2849                                 Once a chart is panned, auto refreshing stops for all charts. To enable it again, <b>double tap</b> a panned chart.
2850                             </div>
2851                             <hr/>
2852                             <div class="p">
2853                                 <h4>Double Tap</h4>
2854                                 Double tap a chart to reset all the charts to their default auto-refreshing state.
2855                             </div>
2856                             <hr/>
2857                             <div class="p">
2858                                 <h4>Zoom <small>(does not work on firefox and IE/Edge)</small></h4>
2859                                 With two fingers, zoom in or out.
2860                                 <br/>
2861                                 Once a chart is zoomed, auto refreshing stops for all charts. To enable it again, <b>double click</b> a zoomed chart.
2862                             </div>
2863                             <hr/>
2864                             <div class="p">
2865                                 <h4>Legend Operations</h4>
2866                                 Tap on the label or value of a dimension, will select / un-select this dimension.
2867                             </div>
2868                         </div>
2869                     </div>
2870                 </div>
2871                 <div class="modal-footer">
2872                     <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
2873                 </div>
2874             </div>
2875         </div>
2876     </div>
2877
2878     <div class="modal fade" id="alarmsModal" tabindex="-1" role="dialog" aria-labelledby="alarmsModalLabel">
2879         <div class="modal-dialog modal-lg" role="document"  style="display: table;"> <!-- allow the modal to expand horizontally -->
2880             <div class="modal-content">
2881                 <div class="modal-header">
2882                     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
2883                     <h4 class="modal-title" id="alarmsModalLabel">netdata alarms</h4>
2884                 </div>
2885                 <div class="modal-body">
2886                     <!-- Nav tabs -->
2887                     <ul class="nav nav-tabs" role="tablist">
2888                         <li role="presentation" class="active"><a href="#alarms_active" aria-controls="alarms_active" role="tab" data-toggle="tab">Active</a></li>
2889                         <li role="presentation"><a href="#alarms_all" aria-controls="alarms_all" role="tab" data-toggle="tab">All</a></li>
2890                         <li role="presentation"><a href="#alarms_log" aria-controls="alarms_log" role="tab" data-toggle="tab">Log</a></li>
2891                     </ul>
2892
2893                     <!-- Tab panes -->
2894                     <div class="tab-content">
2895                         <div role="tabpanel" class="tab-pane active" id="alarms_active">
2896                             loading...
2897                         </div>
2898                         <div role="tabpanel" class="tab-pane" id="alarms_all">
2899                             loading...
2900                         </div>
2901                         <div role="tabpanel" class="tab-pane" id="alarms_log">
2902                             loading...
2903                         </div>
2904                     </div>
2905                 </div>
2906                 <div class="modal-footer">
2907                     <!-- <a href="#" onclick="alarmsUpdateModal(); return false;" type="button" class="btn btn-default">Update</a> -->
2908                     <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
2909                 </div>
2910             </div>
2911         </div>
2912     </div>
2913
2914     <div class="modal fade" id="optionsModal" tabindex="-1" role="dialog" aria-labelledby="optionsModalLabel">
2915         <div class="modal-dialog modal-lg" role="document">
2916             <div class="modal-content">
2917                 <div class="modal-header">
2918                     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
2919                     <h4 class="modal-title" id="optionsModalLabel">netdata dashboard options</h4>
2920                 </div>
2921                 <div class="modal-body">
2922                     <center>
2923                         <small style="color: #BBBBBB;">These are browser settings. Each viewer has its own. They do not affect the operation of your netdata server.
2924                         <br/>
2925                         Settings take effect immediately and are saved permanently to browser local storage (except the refresh on focus / always option).
2926                         <br/>
2927                         To reset all options (including charts sizes) to their defaults, click <a href="#" onclick="resetDashboardOptions(); return false;">here</a>.</small>
2928                     </center>
2929                     <div style="padding: 10px;"></div>
2930
2931                     <!-- Nav tabs -->
2932                     <ul class="nav nav-tabs" role="tablist">
2933                         <li role="presentation" class="active"><a href="#settings_performance" aria-controls="settings_performance" role="tab" data-toggle="tab">Performance</a></li>
2934                         <li role="presentation"><a href="#settings_sync" aria-controls="settings_sync" role="tab" data-toggle="tab">Synchronization</a></li>
2935                         <li role="presentation"><a href="#settings_visual" aria-controls="settings_visual" role="tab" data-toggle="tab">Visual</a></li>
2936                     </ul>
2937
2938                     <!-- Tab panes -->
2939                     <div class="tab-content">
2940                         <div role="tabpanel" class="tab-pane active" id="settings_performance">
2941                             <form id="optionsForm1" method="get" class="form-horizontal">
2942                                 <div class="form-group">
2943                                     <table>
2944                                     <tr class="option-row">
2945                                         <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>
2946                                         <td class="option-info"><strong>When to refresh the charts?</strong><br/>
2947                                             <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>
2948                                         </td>
2949                                         </tr>
2950                                     <tr class="option-row">
2951                                         <td class="option-control">
2952                                         <input id="eliminate_zero_dimensions" type="checkbox" checked data-toggle="toggle" data-on="Non Zero" data-off="All" data-width="110px">
2953                                         </td>
2954                                         <td class="option-info"><strong>Which dimensions to show?</strong><br/>
2955                                             <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>
2956                                         </td>
2957                                         </tr>
2958                                     <tr class="option-row">
2959                                         <td class="option-control"><input id="destroy_on_hide" type="checkbox" data-toggle="toggle" data-on="Destroy" data-off="Hide" data-width="110px"></td>
2960                                         <td class="option-info"><strong>How to handle hidden charts?</strong><br/>
2961                                             <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>
2962                                         </td>
2963                                         </tr>
2964                                     <tr class="option-row">
2965                                         <td class="option-control"><input id="async_on_scroll" type="checkbox" data-toggle="toggle" data-on="Async" data-off="Sync" data-width="110px"></td>
2966                                         <td class="option-info"><strong>Page scroll handling?</strong><br/>
2967                                             <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>
2968                                         </td>
2969                                         </tr>
2970                                     </table>
2971                                 </div>
2972                             </form>
2973                         </div>
2974                         <div role="tabpanel" class="tab-pane" id="settings_sync">
2975                             <form id="optionsForm2" method="get" class="form-horizontal">
2976                                 <div class="form-group">
2977                                     <table>
2978                                     <tr class="option-row">
2979                                         <td class="option-control"><input id="parallel_refresher" type="checkbox" checked data-toggle="toggle" data-on="Parallel" data-off="Sequential" data-width="110px"></td>
2980                                         <td class="option-info"><strong>Which chart refresh policy to use?</strong><br/>
2981                                             <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>
2982                                         </td>
2983                                         </tr>
2984                                     <tr class="option-row" id="concurrent_refreshes_row">
2985                                         <td class="option-control"></td>
2986                                         <td class="option-info">
2987                                             <table>
2988                                             <tr class="option-row">
2989                                             <td class="option-control">
2990                                             <input id="concurrent_refreshes" type="checkbox" checked data-toggle="toggle" data-on="Resync" data-off="Best Effort" data-width="110px">
2991                                             </td>
2992                                             <td class="option-info">
2993                                             <strong>Shall we re-sync chart refreshes?</strong><br/>
2994                                             <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>
2995                                             </td>
2996                                             </tr>
2997                                             </table>
2998                                         </td>
2999                                         </tr>
3000                                     <tr class="option-row">
3001                                         <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>
3002                                         <td class="option-info"><strong>Sync hover selection on all charts?</strong><br/>
3003                                             <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>
3004                                         </td>
3005                                         </tr>
3006                                     <tr class="option-row">
3007                                         <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>
3008                                         <td class="option-info"><strong>Sync pan and zoom on all charts?</strong><br/>
3009                                             <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>
3010                                         </td>
3011                                         </tr>
3012                                     </table>
3013                                 </div>
3014                             </form>
3015                         </div>
3016                         <div role="tabpanel" class="tab-pane" id="settings_visual">
3017                             <form id="optionsForm3" method="get" class="form-horizontal">
3018                                 <div class="form-group">
3019                                     <table>
3020                                     <tr class="option-row">
3021                                         <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>
3022                                         <td class="option-info"><strong>Which theme to use?</strong><br/>
3023                                             <small>Netdata comes with two themes: <b>Dark</b> (the default) and <b>White</b>.
3024                                             <br/>
3025                                             <b>Switching this will reload the dashboard</b>.
3026                                             </small>
3027                                         </td>
3028                                         </tr>
3029                                     <tr class="option-row">
3030                                         <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>
3031                                         <td class="option-info"><strong>Do you need help?</strong><br/>
3032                                             <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.
3033                                             <br/>
3034                                             <b>Switching this will reload the dashboard</b>.
3035                                             </small>
3036                                         </td>
3037                                         </tr>
3038                                     <tr class="option-row">
3039                                         <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>
3040                                         <td class="option-info"><strong>Enable data padding when panning and zooming?</strong><br/>
3041                                             <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>
3042                                         </td>
3043                                         </tr>
3044                                     <tr class="option-row">
3045                                         <td class="option-control"><input id="smooth_plot" type="checkbox" checked data-toggle="toggle"  data-on="Smooth" data-off="Rough" data-width="110px"></td>
3046                                         <td class="option-info"><strong>Enable Bézier lines on charts?</strong><br/>
3047                                             <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.
3048                                             <br/>
3049                                             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>
3050                                         </td>
3051                                         </tr>
3052                                     </table>
3053                                 </div>
3054                             </form>
3055                         </div>
3056                     </div>
3057                 </div>
3058                 <div class="modal-footer">
3059                     <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
3060                 </div>
3061             </div>
3062         </div>
3063     </div>
3064
3065
3066     <div class="modal fade" id="updateModal" tabindex="-1" role="dialog" aria-labelledby="updateModalLabel">
3067         <div class="modal-dialog" role="document">
3068             <div class="modal-content">
3069                 <div class="modal-header">
3070                     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
3071                     <h4 class="modal-title" id="updateModalLabel">Update Check</h4>
3072                 </div>
3073                 <div class="modal-body">
3074                     Your netdata version: <b><code><span id="netdataVersion">Unknown</span></code></b>
3075                     <br/>
3076                     <div style="padding: 10px;"></div>
3077                     <div id="versionCheckLog">Not checked yet. Please press the Check Now button.</div>
3078                 </div>
3079                 <div class="modal-footer">
3080                     <a href="#" onclick="notifyForUpdate(true); return false;" type="button" class="btn btn-default">Check Now</a>
3081                     <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
3082                 </div>
3083             </div>
3084         </div>
3085     </div>
3086
3087     <div class="modal fade" id="deleteRegistryModal" tabindex="-1" role="dialog" aria-labelledby="deleteRegistryModalLabel">
3088         <div class="modal-dialog" role="document">
3089             <div class="modal-content">
3090                 <div class="modal-header">
3091                     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
3092                     <h4 class="modal-title" id="deleteRegistryModalLabel">Delete <span id="deleteRegistryServerName"></span>?</h4>
3093                 </div>
3094                 <div class="modal-body">
3095                     You are about to delete, from your personal list of netdata servers, the following server:
3096                     <p style="text-align: center; padding-top: 10px; padding-bottom: 10px; line-height: 2;">
3097                     <b><span id="deleteRegistryServerName2"></span></b>
3098                     <br/>
3099                     <b><span id="deleteRegistryServerURL"></span></b>
3100                     </p>
3101                     Are you sure you want to do this?
3102                     <br/>
3103                     <div style="padding: 10px;"></div>
3104                     <small>Keep in mind, this server will be added back if and when you visit it again.</small>
3105                     <br/>
3106                     <div id="deleteRegistryResponse" style="display: block; width: 100%; text-align: center; padding-top: 20px;"></div>
3107                 </div>
3108                 <div class="modal-footer">
3109                     <button type="button" class="btn btn-success" data-dismiss="modal">keep it</button>
3110                     <a href="#" onclick="notifyForDeleteRegistry(true); return false;" type="button" class="btn btn-danger">delete it</a>
3111                 </div>
3112             </div>
3113         </div>
3114     </div>
3115
3116     <div class="modal fade" id="switchRegistryModal" tabindex="-1" role="dialog" aria-labelledby="switchRegistryModalLabel">
3117         <div class="modal-dialog" role="document">
3118             <div class="modal-content">
3119                 <div class="modal-header">
3120                     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
3121                     <h4 class="modal-title" id="switchRegistryModalLabel">Switch Netdata Registry Identity</h4>
3122                 </div>
3123                 <div class="modal-body">
3124                     You can copy and paste the following ID to all your browsers (e.g. work and home).
3125                     <br/>
3126                     All the browsers with the same ID will identify <b>you</b>, so please don't share this with others.
3127                     <p style="text-align: center; padding-top: 10px; padding-bottom: 10px; line-height: 2;">
3128                     <form action="#">
3129                     <input type="text" class="form-control" id="switchRegistryPersonGUID" placeholder="your personal ID" maxlength="36" autocomplete="off" style="text-align: center; font-size: 1.4em;">
3130                     </form>
3131                     </p>
3132                     Either copy this ID and paste it to another browser, or paste here the ID you have taken from another browser.
3133                     <p style="padding-top: 10px;"><small>
3134                         Keep in mind that:
3135                         <ul>
3136                             <li>when you switch ID, your previous ID will be lost forever - this is irreversible.</li>
3137                             <li>both IDs (your old and the new) must list this netdata at their personal lists.</li>
3138                             <li>both IDs have to be known by the registry: <b><span id="switchRegistryURL"></span></b>.</li>
3139                             <li>to get a new ID, just clear your browser cookies.</li>
3140                         </ul>
3141                     </small></p>
3142                     <div id="switchRegistryResponse" style="display: block; width: 100%; text-align: center; padding-top: 20px;"></div>
3143                 </div>
3144                 <div class="modal-footer">
3145                     <button type="button" class="btn btn-success" data-dismiss="modal">cancel</button>
3146                     <a href="#" onclick="notifyForSwitchRegistry(true); return false;" type="button" class="btn btn-danger">impersonate</a>
3147                 </div>
3148             </div>
3149         </div>
3150     </div>
3151
3152     <div class="modal fade" id="gotoServerModal" tabindex="-1" role="dialog" aria-labelledby="gotoServerModalLabel">
3153         <div class="modal-dialog" role="document">
3154             <div class="modal-content">
3155                 <div class="modal-header">
3156                     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
3157                     <h4 class="modal-title" id="gotoServerModalLabel"><span id="gotoServerName"></span></h4>
3158                 </div>
3159                 <div class="modal-body">
3160                     Checking known URLs for this server...
3161                     <div  style="padding-top: 20px;">
3162                         <table id="gotoServerList">
3163                         </table>
3164                     </div>
3165                     <p style="padding-top: 10px;"><small>
3166                         Checks may fail if you are viewing an HTTPS page and the server to be checked is HTTP only.
3167                     </small></p>
3168                     <div id="gotoServerResponse" style="display: block; width: 100%; text-align: center; padding-top: 20px;"></div>
3169                 </div>
3170                 <div class="modal-footer">
3171                     <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
3172                 </div>
3173             </div>
3174         </div>
3175     </div>
3176 </body>
3177 </html>
3178 <script type="text/javascript" src="dashboard.js?v20161031-1"></script>