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