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