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