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