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