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