]> arthur.barton.de Git - netdata.git/blob - web/index.html
modified robots.txt and page descriptions to allow posting on twitter and facebook
[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="http://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).toLocaleString() + ' ' + ((data.history == 3600)?'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 html = '<tr><td class="text-center" style="vertical-align:middle" width="40%"><b>' + alarm.chart + '</b><br/>&nbsp;<br/><embed src="' + NETDATA.alarms.server + '/api/v1/badge.svg?chart=' + alarm.chart + '&alarm=' + alarm.name + '&refresh=auto" type="image/svg+xml" height="20"/><br/>&nbsp;<br/><span style="font-size: 18px">' + alarm.info + '</span><br/>&nbsp;<br/>role: <b>' + alarm.recipient + '</b><br/>&nbsp;<br/><b><i class="fa fa-line-chart" aria-hidden="true"></i></b><small>&nbsp;&nbsp;<a href="#" onClick="NETDATA.alarms.scrollToChart(\'' + alarm.chart + '\'); $(\'#alarmsModal\').modal(\'hide\'); return false;">jump to chart</a></small></td>'
1568                         + '<td><table class="table">'
1569                         + ((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>'):'')
1570                         + ((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>'):'');
1571
1572                     if(full === true) {
1573                             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>'):'')
1574                             + ((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>'):'')
1575                             + ((chart.green !== null)?('<tr><td width="10%" style="text-align:right">green&nbsp;threshold</td><td><code>' + chart.green + ' ' + chart.units + '</code></td></tr>'):'')
1576                             + ((chart.red !== null)?('<tr><td width="10%" style="text-align:right">red&nbsp;threshold</td><td><code>' + chart.red + ' ' + chart.units + '</code></td></tr>'):'');
1577                     }
1578
1579                     var delay = '';
1580                     if((alarm.delay_up_duration > 0 || alarm.delay_down_duration > 0) && alarm.delay_multiplier != 0 && alarm.delay_max_duration > 0) {
1581                         if(alarm.delay_up_duration == alarm.delay_down_duration) {
1582                             delay += '<small><br/>hysteresis ' + seconds4human(alarm.delay_up_duration, { negative_suffix: '' });
1583                         }
1584                         else {
1585                             delay = '<small><br/>hysteresis ';
1586                             if(alarm.delay_up_duration > 0) {
1587                                 delay += 'on&nbsp;escalation&nbsp;<code>' + seconds4human(alarm.delay_up_duration, { negative_suffix: '' }) + '</code>, ';
1588                             }
1589                             if(alarm.delay_down_duration > 0) {
1590                                 delay += 'on&nbsp;recovery&nbsp;<code>' + seconds4human(alarm.delay_down_duration, { negative_suffix: '' }) + '</code>, ';
1591                             }
1592                         }
1593                         if(alarm.delay_multiplier != 1.0) {
1594                             delay += 'multiplied&nbsp;by&nbsp;<code>' + alarm.delay_multiplier.toString() + '</code>';
1595                             delay += ',&nbsp;up&nbsp;to&nbsp;<code>' + seconds4human(alarm.delay_max_duration, { negative_suffix: '' }) + '</code>';
1596                         }
1597                         delay += '</small>';
1598                     }
1599
1600                     html += '<tr><td width="10%" style="text-align:right">check&nbsp;every</td><td>' + seconds4human(alarm.update_every, { negative_suffix: '' }) + '</td></tr>'
1601                         + ((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>'):'')
1602                         + '<tr><td width="10%" style="text-align:right">source</td><td><span style="font-family: monospace;">' + alarm.source + '</span></td></tr>'
1603                         + '</table></td></tr>';
1604
1605                     return html;
1606                 }
1607
1608                 function alarm_family_show(id) {
1609                     var html = '<table class="table">';
1610                     var family = options.alarm_families[id];
1611                     var len = family.arr.length;
1612                     while(len--) {
1613                         var alarm = family.arr[len];
1614                         html += alarm_to_html(alarm, true);
1615                     }
1616                     html += '</table>';
1617
1618                     $('#alarm_all_' + id.toString()).html(html);
1619                 }
1620
1621                 // find the proper family of each alarm
1622                 var now = Date.now();
1623                 var x;
1624                 var count_active = 0;
1625                 var count_all = 0;
1626                 var families = {};
1627                 var families_sort = new Array();
1628                 for(x in data.alarms) {
1629                     var alarm = data.alarms[x];
1630                     var family = alarm.family;
1631
1632                     // find the chart
1633                     var chart = options.data.charts[alarm.chart];
1634                     if(typeof chart === 'undefined')
1635                         chart = options.data.charts_by_name[alarm.chart];
1636
1637                     // not found - this should never happen!
1638                     if(typeof chart === 'undefined') {
1639                         console.log('WARNING: alarm ' + x + ' is linked to chart ' + alarm.chart + ', which is not found in the list of chart got from the server.');
1640                         chart = { priority: 9999999 };
1641                     }
1642                     else if(typeof chart.menu !== 'undefined' && typeof chart.submenu !== 'undefined')
1643                         // the family based on the chart
1644                         family = chart.menu + ' - ' + chart.submenu;
1645
1646                     if(typeof families[family] === 'undefined') {
1647                         families[family] = {
1648                             name: family,
1649                             arr: new Array(),
1650                             priority: chart.priority
1651                         };
1652
1653                         families_sort.push(families[family]);
1654                     }
1655
1656                     if(chart.priority < families[family].priority)
1657                         families[family].priority = chart.priority;
1658
1659                     families[family].arr.unshift(alarm);
1660                 }
1661
1662                 // sort the families, like the dashboard menu does
1663                 var families_sorted = families_sort.sort(function (a, b) {
1664                     if (a.priority > b.priority) return -1;
1665                     if (a.priority < b.priority) return 1;
1666                     return 0;
1667                 });
1668
1669                 var fc = 0;
1670                 var len = families_sorted.length;
1671                 while(len--) {
1672                     var family = families_sorted[len].name;
1673                     var active_family_added = false;
1674                     var expanded = 'true';
1675                     var collapsed = '';
1676                     var cin = 'in';
1677
1678                     if(fc !== 0) {
1679                         all += "</table></div></div></div>";
1680                         expanded = 'false';
1681                         collapsed = 'class="collapsed"'
1682                         cin = '';
1683                     }
1684
1685                     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() + '">';
1686
1687                     options.alarm_families[fc] = families[family];
1688
1689                     fc++;
1690
1691                     var arr = families[family].arr;
1692                     var c = arr.length;
1693                     while(c--) {
1694                         var alarm = arr[c];
1695                         if(alarm.status === 'WARNING' || alarm.status === 'CRITICAL') {
1696                             if(!active_family_added) {
1697                                 active_family_added = true;
1698                                 active += '<tr><th class="text-center" colspan="2"><h4>' + family + '</h4></th></tr>';
1699                             }
1700                             count_active++;
1701                             active += alarm_to_html(alarm, true);
1702                         }
1703
1704                         count_all++;
1705                     }
1706                 }
1707                 active += "</table>";
1708                 if(families_sorted.length > 0) all += "</div></div></div>";
1709                 all += "</div>";
1710
1711                 if(!count_active)
1712                     active += "<h4>Everything is normal. No raised alarms.</h4>";
1713                 else
1714                     active += footer;
1715
1716                 if(!count_all)
1717                     all += "<h4>No alarms are running in this system.</h4>";
1718                 else
1719                     all += footer;
1720
1721                 document.getElementById('alarms_active').innerHTML = active;
1722                 document.getElementById('alarms_all').innerHTML = all;
1723
1724                 if(families_sorted.length > 0) alarm_family_show(0);
1725
1726                 // register bootstrap events
1727                 $('#alarms_all_accordion').on('show.bs.collapse', function (d) {
1728                     var target = $(d.target);
1729                     var id = $(target).data('alarm-id');
1730                     alarm_family_show(id);
1731                 });
1732                 $('#alarms_all_accordion').on('hidden.bs.collapse', function (d) {
1733                     var target = $(d.target);
1734                     var id = $(target).data('alarm-id');
1735                     $('#alarm_all_' + id.toString()).html('');
1736                 });
1737
1738                 document.getElementById('alarms_log').innerHTML = '<h3>Alarm Log</h3><table id="alarms_log_table"></table>';
1739
1740                 loadBootstrapTable(function () {
1741                     $('#alarms_log_table').bootstrapTable({
1742                         url: NETDATA.alarms.server + '/api/v1/alarm_log?all',
1743                         cache: false,
1744                         pagination: true,
1745                         pageSize: 10,
1746                         showPaginationSwitch: false,
1747                         search: true,
1748                         searchTimeOut: 300,
1749                         searchAlign: 'left',
1750                         showColumns: true,
1751                         showExport: true,
1752                         exportDataType: 'basic',
1753                         exportOptions: {
1754                             fileName: 'netdata_alarm_log'
1755                         },
1756                         rowStyle: function(row, index) {
1757                             switch(row.status) {
1758                                 case 'CRITICAL' : return { classes: 'danger'  }; break;
1759                                 case 'WARNING'  : return { classes: 'warning' }; break;
1760                                 case 'UNDEFINED': return { classes: 'info'    }; break;
1761                                 case 'CLEAR'    : return { classes: 'success' }; break;
1762                             }
1763                             return {};
1764                         },
1765                         showFooter: false,
1766                         showHeader: true,
1767                         showRefresh: true,
1768                         showToggle: false,
1769                         sortable: true,
1770                         silentSort: false,
1771                         columns: [
1772                             {
1773                                 field: 'when',
1774                                 title: 'Event Date',
1775                                 valign: 'middle',
1776                                 titleTooltip: 'The date and time the even took place',
1777                                 formatter: function(value, row, index) { return timestamp4human(value, ' '); },
1778                                 align: 'center',
1779                                 valign: 'middle',
1780                                 switchable: false,
1781                                 sortable: true
1782                             },
1783                             {
1784                                 field: 'hostname',
1785                                 title: 'Host',
1786                                 valign: 'middle',
1787                                 titleTooltip: 'The host that generated this event',
1788                                 align: 'center',
1789                                 valign: 'middle',
1790                                 visible: false,
1791                                 sortable: true
1792                             },
1793                             {
1794                                 field: 'unique_id',
1795                                 title: 'Unique ID',
1796                                 titleTooltip: 'The host unique ID for this event',
1797                                 formatter: function(value, row, index) { return alarmid4human(value); },
1798                                 align: 'center',
1799                                 valign: 'middle',
1800                                 visible: false,
1801                                 sortable: true
1802                             },
1803                             {
1804                                 field: 'alarm_id',
1805                                 title: 'Alarm ID',
1806                                 titleTooltip: 'The ID of the alarm that generated this event',
1807                                 formatter: function(value, row, index) { return alarmid4human(value); },
1808                                 align: 'center',
1809                                 valign: 'middle',
1810                                 visible: false,
1811                                 sortable: true
1812                             },
1813                             {
1814                                 field: 'alarm_event_id',
1815                                 title: 'Alarm Event ID',
1816                                 titleTooltip: 'The incremental ID of this event for the given alarm',
1817                                 formatter: function(value, row, index) { return alarmid4human(value); },
1818                                 align: 'center',
1819                                 valign: 'middle',
1820                                 visible: false,
1821                                 sortable: true
1822                             },
1823                             {
1824                                 field: 'chart',
1825                                 title: 'Chart',
1826                                 titleTooltip: 'The chart the alarm is attached to',
1827                                 align: 'center',
1828                                 valign: 'middle',
1829                                 switchable: false,
1830                                 sortable: true
1831                             },
1832                             {
1833                                 field: 'family',
1834                                 title: 'Family',
1835                                 titleTooltip: 'The family of the chart the alarm is attached to',
1836                                 align: 'center',
1837                                 valign: 'middle',
1838                                 visible: false,
1839                                 sortable: true
1840                             },
1841                             {
1842                                 field: 'name',
1843                                 title: 'Alarm',
1844                                 titleTooltip: 'The alarm name that generated this event',
1845                                 formatter: function(value, row, index) {
1846                                     return value.toString().replace(/_/g, ' ');
1847                                 },
1848                                 align: 'center',
1849                                 valign: 'middle',
1850                                 switchable: false,
1851                                 sortable: true
1852                             },
1853                             {
1854                                 field: 'old_value',
1855                                 title: 'Old Value',
1856                                 titleTooltip: 'The value of the alarm, just before this event',
1857                                 formatter: function(value, row, index) {
1858                                     return ((value !== null)?Math.round(value * 100) / 100:'NaN').toString();
1859                                 },
1860                                 align: 'center',
1861                                 valign: 'middle',
1862                                 visible: false,
1863                                 sortable: true
1864                             },
1865                             {
1866                                 field: 'value',
1867                                 title: 'Value',
1868                                 titleTooltip: 'The value of the alarm, that triggered this event',
1869                                 formatter: function(value, row, index) {
1870                                     return ((value !== null)?Math.round(value * 100) / 100:'NaN').toString();
1871                                 },
1872                                 align: 'right',
1873                                 valign: 'middle',
1874                                 sortable: true
1875                             },
1876                             {
1877                                 field: 'units',
1878                                 title: 'Units',
1879                                 titleTooltip: 'The units of the value of the alarm',
1880                                 align: 'left',
1881                                 valign: 'middle',
1882                                 sortable: true
1883                             },
1884                             {
1885                                 field: 'old_status',
1886                                 title: 'Old Status',
1887                                 titleTooltip: 'The status of the alarm, just before this event',
1888                                 align: 'center',
1889                                 valign: 'middle',
1890                                 visible: false,
1891                                 sortable: true
1892                             },
1893                             {
1894                                 field: 'status',
1895                                 title: 'Status',
1896                                 titleTooltip: 'The status of the alarm, that was set due to this event',
1897                                 align: 'center',
1898                                 valign: 'middle',
1899                                 switchable: false,
1900                                 sortable: true
1901                             },
1902                             {
1903                                 field: 'duration',
1904                                 title: 'Last Duration',
1905                                 titleTooltip: 'The duration the alarm was at its previous state, just before this event',
1906                                 formatter: function(value, row, index) { return seconds4human(value, { negative_suffix: '', space: ' ', now: 'no time' }); },
1907                                 align: 'center',
1908                                 valign: 'middle',
1909                                 visible: false,
1910                                 sortable: true
1911                             },
1912                             {
1913                                 field: 'non_clear_duration',
1914                                 title: 'Raised Duration',
1915                                 titleTooltip: 'The duration the alarm was raised, just before this event',
1916                                 formatter: function(value, row, index) { return seconds4human(value, { negative_suffix: '', space: ' ', now: 'no time' }); },
1917                                 align: 'center',
1918                                 valign: 'middle',
1919                                 visible: false,
1920                                 sortable: true
1921                             },
1922                             {
1923                                 field: 'recipient',
1924                                 title: 'Recipient',
1925                                 titleTooltip: 'The recipient of this event',
1926                                 align: 'center',
1927                                 valign: 'middle',
1928                                 visible: false,
1929                                 sortable: true
1930                             },
1931                             {
1932                                 field: 'processed',
1933                                 title: 'Processed Status',
1934                                 titleTooltip: 'True when this event is processed',
1935                                 formatter: function(value, row, index) {
1936                                     if(value === true)
1937                                         return 'DONE';
1938                                     else
1939                                         return 'PENDING';
1940                                 },
1941                                 align: 'center',
1942                                 valign: 'middle',
1943                                 visible: false,
1944                                 sortable: true
1945                             },
1946                             {
1947                                 field: 'updated',
1948                                 title: 'Updated Status',
1949                                 titleTooltip: 'True when this event has been updated by another event',
1950                                 formatter: function(value, row, index) {
1951                                     if(value === true)
1952                                         return 'UPDATED';
1953                                     else
1954                                         return 'CURRENT';
1955                                 },
1956                                 align: 'center',
1957                                 valign: 'middle',
1958                                 visible: false,
1959                                 sortable: true
1960                             },
1961                             {
1962                                 field: 'updated_by_id',
1963                                 title: 'Updated By ID',
1964                                 titleTooltip: 'The unique ID of the event that obsoleted this one',
1965                                 formatter: function(value, row, index) { return alarmid4human(value); },
1966                                 align: 'center',
1967                                 valign: 'middle',
1968                                 visible: false,
1969                                 sortable: true
1970                             },
1971                             {
1972                                 field: 'updates_id',
1973                                 title: 'Updates ID',
1974                                 titleTooltip: 'The unique ID of the event obsoleted because of this event',
1975                                 formatter: function(value, row, index) { return alarmid4human(value); },
1976                                 align: 'center',
1977                                 valign: 'middle',
1978                                 visible: false,
1979                                 sortable: true
1980                             },
1981                             {
1982                                 field: 'exec',
1983                                 title: 'Script',
1984                                 titleTooltip: 'The script to handle the event notification',
1985                                 align: 'center',
1986                                 valign: 'middle',
1987                                 visible: false,
1988                                 sortable: true
1989                             },
1990                             {
1991                                 field: 'exec_run',
1992                                 title: 'Script Run At',
1993                                 titleTooltip: 'The date and time the script has been ran',
1994                                 formatter: function(value, row, index) { return timestamp4human(value, ' '); },
1995                                 align: 'center',
1996                                 valign: 'middle',
1997                                 visible: false,
1998                                 sortable: true
1999                             },
2000                             {
2001                                 field: 'exec_code',
2002                                 title: 'Script Return Value',
2003                                 titleTooltip: 'The return code of the script',
2004                                 formatter: function(value, row, index) {
2005                                     if(value === 0)
2006                                         return 'OK (returned 0)';
2007                                     else
2008                                         return 'FAILED (with code ' + value.toString() + ')';
2009                                 },
2010                                 align: 'center',
2011                                 valign: 'middle',
2012                                 visible: false,
2013                                 sortable: true
2014                             },
2015                             {
2016                                 field: 'delay',
2017                                 title: 'Script Delay',
2018                                 titleTooltip: 'The hysteresis of the notification',
2019                                 formatter: function(value, row, index) { return seconds4human(value, { negative_suffix: '', space: ' ', now: 'no time' }); },
2020                                 align: 'center',
2021                                 valign: 'middle',
2022                                 visible: false,
2023                                 sortable: true
2024                             },
2025                             {
2026                                 field: 'delay_up_to_timestamp',
2027                                 title: 'Script Delay Run At',
2028                                 titleTooltip: 'The date and time the script should be run, after hysteresis',
2029                                 formatter: function(value, row, index) { return timestamp4human(value, ' '); },
2030                                 align: 'center',
2031                                 valign: 'middle',
2032                                 visible: false,
2033                                 sortable: true
2034                             },
2035                             {
2036                                 field: 'info',
2037                                 title: 'Description',
2038                                 titleTooltip: 'A short description of the alarm',
2039                                 align: 'center',
2040                                 valign: 'middle',
2041                                 visible: false,
2042                                 sortable: true
2043                             },
2044                             {
2045                                 field: 'source',
2046                                 title: 'Alarm Source',
2047                                 titleTooltip: 'The source of configuration of the alarm',
2048                                 align: 'center',
2049                                 valign: 'middle',
2050                                 visible: false,
2051                                 sortable: true
2052                             }
2053                         ]
2054                     });
2055                     // console.log($('#alarms_log_table').bootstrapTable('getOptions'));
2056                 });
2057             });
2058         }
2059
2060         function alarmsCallback(data) {
2061             var count = 0;
2062             for(x in data.alarms) {
2063                 var alarm = data.alarms[x];
2064                 if(alarm.status === 'WARNING' || alarm.status === 'CRITICAL')
2065                     count++;
2066             }
2067
2068             if(count > 0)
2069                 document.getElementById('alarms_count_badge').innerHTML = count.toString();
2070             else
2071                 document.getElementById('alarms_count_badge').innerHTML = '';
2072         }
2073
2074         function initializeDynamicDashboard(netdata_url) {
2075             if(typeof netdata_url === 'undefined' || netdata_url === null)
2076                 netdata_url = NETDATA.serverDefault;
2077
2078             // initialize clickable alarms
2079             NETDATA.alarms.chart_div_offset = 100;
2080             NETDATA.alarms.chart_div_id_prefix = 'chart_';
2081             NETDATA.alarms.chart_div_animation_duration = 0;
2082
2083             NETDATA.pause(function() {
2084                 NETDATA.alarms.callback = alarmsCallback;
2085
2086                 // download all the charts the server knows
2087                 NETDATA.chartRegistry.downloadAll(netdata_url, function(data) {
2088                     if(data !== null) {
2089                         options.hostname = data.hostname;
2090                         options.data = data;
2091
2092                         // update the dashboard hostname
2093                         document.getElementById('hostname').innerHTML = options.hostname;
2094                         document.getElementById('hostname').href = NETDATA.serverDefault;
2095
2096                         // update the dashboard title
2097                         document.title = options.hostname + ' netdata dashboard';
2098
2099                         // close the splash screen
2100                         $("#loadOverlay").css("display","none");
2101
2102                         // create a chart_by_name index
2103                         data.charts_by_name = {};
2104                         var charts = data.charts;
2105                         var x;
2106                         for(x in charts) {
2107                             var chart = charts[x];
2108                             data.charts_by_name[chart.name] = chart;
2109                         }
2110
2111                         // render all charts
2112                         renderChartsAndMenu(data);
2113                     }
2114                 });
2115             });
2116         }
2117
2118         // ----------------------------------------------------------------------------
2119
2120         function versionLog(msg) {
2121             document.getElementById('versionCheckLog').innerHTML = msg;
2122         }
2123
2124         function getNetdataVersion(callback) {
2125             versionLog('Downloading installed version info from netdata...');
2126
2127             $.ajax({
2128                 url: 'version.txt',
2129                 async: true,
2130                 cache: false,
2131                 xhrFields: { withCredentials: true } // required for the cookie
2132             })
2133             .done(function(data) {
2134                 data = data.replace(/(\r\n|\n|\r| |\t)/gm,"");
2135                 if(data.length !== 40) {
2136                     versionLog('Received version string is invalid.');
2137                     callback(null);
2138                 }
2139                 else {
2140                     versionLog('Installed version of netdata is ' + data);
2141                     document.getElementById('netdataVersion').innerHTML = data;
2142                     callback(data);
2143                 }
2144             })
2145             .fail(function() {
2146                 versionLog('Failed to download installed version info from netdata!');
2147                 callback(null);
2148             });
2149         }
2150
2151         function getGithubLatestCommit(callback) {
2152             versionLog('Downloading latest version info from github...');
2153
2154             $.ajax({
2155                 url: 'https://api.github.com/repos/firehol/netdata/commits',
2156                 async: true,
2157                 cache: false
2158             })
2159             .done(function(data) {
2160                 versionLog('Latest version info from github is ' + data[0].sha);
2161                 callback(data[0].sha);
2162             })
2163             .fail(function() {
2164                 versionLog('Failed to download installed version info from github!');
2165                 callback(null);
2166             });
2167         }
2168
2169         function checkForUpdate(callback) {
2170             getNetdataVersion(function(sha1) {
2171                 if(sha1 === null) callback(null, null);
2172
2173                 getGithubLatestCommit(function(sha2) {
2174                     callback(sha1, sha2);
2175                 });
2176             });
2177
2178             return null;
2179         }
2180
2181         function notifyForUpdate(force) {
2182             versionLog('<p>checking for updates...</p>');
2183
2184             var now = Date.now();
2185
2186             if(typeof force === 'undefined' || force !== true) {
2187                 var last = loadLocalStorage('last_update_check');
2188
2189                 if(typeof last === 'string')
2190                     last = parseInt(last);
2191                 else
2192                     last = 0;
2193
2194                 if(now - last < 3600000 * 8) {
2195                     // no need to check it - too soon
2196                     return;
2197                 }
2198             }
2199
2200             checkForUpdate(function(sha1, sha2) {
2201                 var save = false;
2202
2203                 if(sha1 === null) {
2204                     save = false;
2205                     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>');
2206                 }
2207                 else if(sha2 === null) {
2208                     save = false;
2209                     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>');
2210                 }
2211                 else if(sha1 === sha2) {
2212                     save = true;
2213                     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>');
2214                 }
2215                 else {
2216                     save = true;
2217                     var compare = 'https://github.com/firehol/netdata/compare/' + sha1.toString() + '...' + sha2.toString();
2218
2219                     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>');
2220
2221                     document.getElementById('update_badge').innerHTML = '!';
2222                 }
2223
2224                 if(save)
2225                     saveLocalStorage('last_update_check', now.toString());
2226             });
2227         }
2228
2229         // ----------------------------------------------------------------------------
2230
2231         function finalizePage() {
2232             // resize all charts - without starting the background thread
2233             // this has to be done while NETDATA is paused
2234             // if we ommit this, the affix menu will be wrong, since all
2235             // the Dom elements are initially zero-sized
2236             NETDATA.parseDom();
2237
2238             if(urlOptions.pan_and_zoom === true)
2239                 NETDATA.globalPanAndZoom.setMaster(NETDATA.options.targets[0], urlOptions.after, urlOptions.before);
2240
2241             // ------------------------------------------------------------------------
2242             // https://github.com/viralpatel/jquery.shorten/blob/master/src/jquery.shorten.js
2243             $.fn.shorten = function(settings) {
2244                 "use strict";
2245
2246                 var config = {
2247                     showChars: 750,
2248                     minHideChars: 10,
2249                     ellipsesText: "...",
2250                     moreText: '<i class="fa fa-expand" aria-hidden="true"></i> show more information',
2251                     lessText: '<i class="fa fa-compress" aria-hidden="true"></i> show less information',
2252                     onLess: function() { NETDATA.onscroll(); },
2253                     onMore: function() { NETDATA.onscroll(); },
2254                     errMsg: null,
2255                     force: false
2256                 };
2257
2258                 if (settings) {
2259                     $.extend(config, settings);
2260                 }
2261
2262                 if ($(this).data('jquery.shorten') && !config.force) {
2263                     return false;
2264                 }
2265                 $(this).data('jquery.shorten', true);
2266
2267                 $(document).off("click", '.morelink');
2268
2269                 $(document).on({
2270                     click: function() {
2271
2272                         var $this = $(this);
2273                         if ($this.hasClass('less')) {
2274                             $this.removeClass('less');
2275                             $this.html(config.moreText);
2276                             $this.parent().prev().animate({'height':'0'+'%'}, 0, function () { $this.parent().prev().prev().show(); }).hide(0, function() {
2277                                 config.onLess();
2278                             });
2279
2280                         } else {
2281                             $this.addClass('less');
2282                             $this.html(config.lessText);
2283                             $this.parent().prev().animate({'height':'100'+'%'}, 0, function () { $this.parent().prev().prev().hide(); }).show(0, function() {
2284                                 config.onMore();
2285                             });
2286                         }
2287                         return false;
2288                     }
2289                 }, '.morelink');
2290
2291                 return this.each(function() {
2292                     var $this = $(this);
2293
2294                     var content = $this.html();
2295                     var contentlen = $this.text().length;
2296                     if (contentlen > config.showChars + config.minHideChars) {
2297                         var c = content.substr(0, config.showChars);
2298                         if (c.indexOf('<') >= 0) // If there's HTML don't want to cut it
2299                         {
2300                             var inTag = false; // I'm in a tag?
2301                             var bag = ''; // Put the characters to be shown here
2302                             var countChars = 0; // Current bag size
2303                             var openTags = []; // Stack for opened tags, so I can close them later
2304                             var tagName = null;
2305
2306                             for (var i = 0, r = 0; r <= config.showChars; i++) {
2307                                 if (content[i] == '<' && !inTag) {
2308                                     inTag = true;
2309
2310                                     // This could be "tag" or "/tag"
2311                                     tagName = content.substring(i + 1, content.indexOf('>', i));
2312
2313                                     // If its a closing tag
2314                                     if (tagName[0] == '/') {
2315
2316
2317                                         if (tagName != '/' + openTags[0]) {
2318                                             config.errMsg = 'ERROR en HTML: the top of the stack should be the tag that closes';
2319                                         } else {
2320                                             openTags.shift(); // Pops the last tag from the open tag stack (the tag is closed in the retult HTML!)
2321                                         }
2322
2323                                     } else {
2324                                         // There are some nasty tags that don't have a close tag like <br/>
2325                                         if (tagName.toLowerCase() != 'br') {
2326                                             openTags.unshift(tagName); // Add to start the name of the tag that opens
2327                                         }
2328                                     }
2329                                 }
2330                                 if (inTag && content[i] == '>') {
2331                                     inTag = false;
2332                                 }
2333
2334                                 if (inTag) { bag += content.charAt(i); } // Add tag name chars to the result
2335                                 else {
2336                                     r++;
2337                                     if (countChars <= config.showChars) {
2338                                         bag += content.charAt(i); // Fix to ie 7 not allowing you to reference string characters using the []
2339                                         countChars++;
2340                                     } else // Now I have the characters needed
2341                                     {
2342                                         if (openTags.length > 0) // I have unclosed tags
2343                                         {
2344                                             //console.log('They were open tags');
2345                                             //console.log(openTags);
2346                                             for (j = 0; j < openTags.length; j++) {
2347                                                 //console.log('Cierro tag ' + openTags[j]);
2348                                                 bag += '</' + openTags[j] + '>'; // Close all tags that were opened
2349
2350                                                 // 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
2351                                             }
2352                                             break;
2353                                         }
2354                                     }
2355                                 }
2356                             }
2357                             c = $('<div/>').html(bag + '<span class="ellip">' + config.ellipsesText + '</span>').html();
2358                         }else{
2359                             c+=config.ellipsesText;
2360                         }
2361
2362                         var html = '<div class="shortcontent">' + c +
2363                                 '</div><div class="allcontent">' + content +
2364                                 '</div><span><a href="javascript://nop/" class="morelink">' + config.moreText + '</a></span>';
2365
2366                         $this.html(html);
2367                         $this.find(".allcontent").hide(); // Hide all text
2368                         $('.shortcontent p:last', $this).css('margin-bottom', 0); //Remove bottom margin on last paragraph as it's likely shortened
2369                     }
2370                 });
2371
2372             };
2373             $(".chart-message").shorten();
2374             // ------------------------------------------------------------------------
2375
2376             // callback for us to track PanAndZoom operations
2377             NETDATA.globalPanAndZoom.callback = urlOptions.netdataPanAndZoomCallback;
2378
2379             // let it run (update the charts)
2380             NETDATA.unpause();
2381
2382             // check if we have to jump to a specific section
2383             scrollToId(urlOptions.hash.replace('#',''));
2384
2385             if(urlOptions.chart !== null) {
2386                 NETDATA.alarms.scrollToChart(urlOptions.chart);
2387                 //urlOptions.hash = '#' + NETDATA.name2id('menu_' + charts[c].menu + '_submenu_' + charts[c].submenu);
2388                 //urlOptions.hash = '#chart_' + NETDATA.name2id(urlOptions.chart);
2389                 //console.log('hash = ' + urlOptions.hash);
2390             }
2391
2392             /* activate bootstrap sidebar (affix) */
2393             $('#sidebar').affix({
2394                 offset: {
2395                     top: (isdemo())?150:0,
2396                     bottom: 0
2397                 }
2398             });
2399
2400             /* fix scrolling of very long affix lists
2401                http://stackoverflow.com/questions/21691585/bootstrap-3-1-0-affix-too-long
2402              */
2403             $('#sidebar').on('affixed.bs.affix', function() {
2404                 $(this).removeAttr('style');
2405             });
2406
2407             /* activate bootstrap scrollspy (needed for sidebar) */
2408             $(document.body).scrollspy({
2409                 target: '#sidebar',
2410                 offset: $(window).height() / 5 // controls the diff of the <hX> element to the top, to select it
2411             });
2412
2413             // change the URL based on the current position of the screen
2414             $('#sidebar').on('activate.bs.scrollspy', function (e) {
2415                 // console.log(e);
2416                 var el = $(e.target);
2417                 //if(el.find('ul').size() == 0) {
2418                 var hash = el.find('a').attr('href');
2419                 if(typeof hash === 'string' && hash.substring(0, 1) === '#' && urlOptions.hash.startsWith(hash + '_submenu_') === false) {
2420                     urlOptions.hash = hash;
2421                     //console.log(urlOptions.hash);
2422                     urlOptions.hashUpdate();
2423                 }
2424                 //else console.log('hash: not accepting ' + hash);
2425                 //}
2426                 //else console.log('el.find(): not found');
2427             });
2428
2429             document.getElementById('footer').style.display = 'block';
2430
2431             var update_options_modal = function() {
2432                 // console.log('update_options_modal');
2433
2434                 var sync_option = function(option) {
2435                     var self = $('#' + option);
2436
2437                     if(self.prop('checked') !== NETDATA.getOption(option)) {
2438                         // console.log('switching ' + option.toString());
2439                         self.bootstrapToggle(NETDATA.getOption(option)?'on':'off');
2440                     }
2441                 }
2442
2443                 var theme_sync_option = function(option) {
2444                     var self = $('#' + option);
2445
2446                     self.bootstrapToggle(netdataTheme === 'slate'?'on':'off');
2447                 }
2448
2449                 sync_option('eliminate_zero_dimensions');
2450                 sync_option('destroy_on_hide');
2451                 sync_option('async_on_scroll');
2452                 sync_option('parallel_refresher');
2453                 sync_option('concurrent_refreshes');
2454                 sync_option('sync_selection');
2455                 sync_option('sync_pan_and_zoom');
2456                 sync_option('stop_updates_when_focus_is_lost');
2457                 sync_option('smooth_plot');
2458                 sync_option('pan_and_zoom_data_padding');
2459                 sync_option('show_help');
2460                 theme_sync_option('netdata_theme_control');
2461
2462                 if(NETDATA.getOption('parallel_refresher') === false) {
2463                     $('#concurrent_refreshes_row').hide();
2464                 }
2465                 else {
2466                     $('#concurrent_refreshes_row').show();
2467                 }
2468             };
2469             NETDATA.setOption('setOptionCallback', update_options_modal);
2470
2471             // handle options changes
2472             $('#eliminate_zero_dimensions').change(function()       { NETDATA.setOption('eliminate_zero_dimensions', $(this).prop('checked')); });
2473             $('#destroy_on_hide').change(function()                 { NETDATA.setOption('destroy_on_hide', $(this).prop('checked')); });
2474             $('#async_on_scroll').change(function()                 { NETDATA.setOption('async_on_scroll', $(this).prop('checked')); });
2475             $('#parallel_refresher').change(function()              { NETDATA.setOption('parallel_refresher', $(this).prop('checked')); });
2476             $('#concurrent_refreshes').change(function()            { NETDATA.setOption('concurrent_refreshes', $(this).prop('checked')); });
2477             $('#sync_selection').change(function()                  { NETDATA.setOption('sync_selection', $(this).prop('checked')); });
2478             $('#sync_pan_and_zoom').change(function()               { NETDATA.setOption('sync_pan_and_zoom', $(this).prop('checked')); });
2479             $('#stop_updates_when_focus_is_lost').change(function() {
2480                 urlOptions.update_always = !$(this).prop('checked');
2481                 urlOptions.hashUpdate();
2482
2483                 NETDATA.setOption('stop_updates_when_focus_is_lost', !urlOptions.update_always);
2484             });
2485             $('#smooth_plot').change(function()                     { NETDATA.setOption('smooth_plot', $(this).prop('checked')); });
2486             $('#pan_and_zoom_data_padding').change(function()       { NETDATA.setOption('pan_and_zoom_data_padding', $(this).prop('checked')); });
2487             $('#show_help').change(function()                       {
2488                 urlOptions.help = $(this).prop('checked');
2489                 urlOptions.hashUpdate();
2490
2491                 NETDATA.setOption('show_help', urlOptions.help);
2492                 netdataReload();
2493             });
2494
2495             // this has to be the last
2496             // it reloads the page
2497             $('#netdata_theme_control').change(function() {
2498                 urlOptions.theme = $(this).prop('checked')?'slate':'white';
2499                 urlOptions.hashUpdate();
2500
2501                 if(setTheme(urlOptions.theme))
2502                     netdataReload();
2503             });
2504
2505             $('#updateModal').on('shown.bs.modal', function() {
2506                 notifyForUpdate(true);
2507             });
2508
2509             $('#alarmsModal').on('shown.bs.modal', function() {
2510                 NETDATA.pause(alarmsUpdateModal);
2511             });
2512
2513             $('#alarmsModal').on('hidden.bs.modal', function() {
2514                 NETDATA.unpause();
2515                 document.getElementById('alarms_active').innerHTML =
2516                         document.getElementById('alarms_all').innerHTML =
2517                         document.getElementById('alarms_log').innerHTML =
2518                                 'loading...';
2519             });
2520
2521             $('#deleteRegistryModal').on('hidden.bs.modal', function() {
2522                 deleteRegistryGuid = null;
2523             });
2524
2525             if(isdemo()) {
2526                 // do not to give errors on netdata demo servers for 60 seconds
2527                 NETDATA.options.current.retries_on_data_failures = 60;
2528
2529                 if(urlOptions.nowelcome !== true) {
2530                     setTimeout(function() {
2531                         $('#welcomeModal').modal();
2532                     }, 1000);
2533                 }
2534
2535                 // google analytics when this is used for the home page of the demo sites
2536                 // this does not run on user's installations
2537                 setTimeout(function() {
2538                     (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
2539                     (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
2540                     m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
2541                     })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
2542
2543                     ga('create', 'UA-64295674-3', 'auto');
2544                     ga('send', 'pageview');
2545                 }, 2000);
2546             }
2547             else notifyForUpdate();
2548
2549             if(urlOptions.show_alarms === true)
2550                 setTimeout(function() { $('#alarmsModal').modal('show'); }, 1000);
2551
2552             var sidebar = document.getElementById('sidebar');
2553             Ps.initialize(sidebar, {
2554                 wheelSpeed: 0.5,
2555                 wheelPropagation: true,
2556                 swipePropagation: true,
2557                 minScrollbarLength: null,
2558                 maxScrollbarLength: null,
2559                 useBothWheelAxes: false,
2560                 suppressScrollX: true,
2561                 suppressScrollY: false,
2562                 scrollXMarginOffset: 0,
2563                 scrollYMarginOffset: 0,
2564                 theme: 'default'
2565             });
2566             Ps.update(sidebar);
2567
2568             var registry = document.getElementById('myNetdataDropdownUL');
2569             Ps.initialize(registry, {
2570                 wheelSpeed: 1,
2571                 wheelPropagation: false,
2572                 swipePropagation: false,
2573                 minScrollbarLength: null,
2574                 maxScrollbarLength: null,
2575                 useBothWheelAxes: false,
2576                 suppressScrollX: true,
2577                 suppressScrollY: false,
2578                 scrollXMarginOffset: 0,
2579                 scrollYMarginOffset: 0,
2580                 theme: 'default'
2581             });
2582             Ps.update(registry);
2583
2584             NETDATA.onresizeCallback = function() {
2585                 Ps.update(sidebar);
2586                 Ps.update(registry);
2587             };
2588
2589             $('#myNetdataDropdownParent')
2590                 .on('show.bs.dropdown', function () {
2591                     NETDATA.pause(function() {});
2592                 })
2593                 .on('shown.bs.dropdown', function () {
2594                     Ps.update(registry);
2595                 })
2596                 .on('hidden.bs.dropdown', function () {
2597                     NETDATA.unpause();
2598                 });
2599         }
2600
2601         function resetDashboardOptions() {
2602             var help = NETDATA.options.current.show_help;
2603
2604             NETDATA.resetOptions();
2605             if(setTheme('slate'))
2606                 netdataReload();
2607
2608             if(help !== NETDATA.options.current.show_help)
2609                 netdataReload();
2610         }
2611
2612         // callback to add the dashboard info to the
2613         // parallel javascript downloader in netdata
2614         var netdataPrepCallback = function() {
2615             NETDATA.requiredCSS.push({
2616                 url: NETDATA.serverDefault + 'css/bootstrap-toggle-2.2.2.min.css',
2617                 isAlreadyLoaded: function() { return false; }
2618             });
2619
2620             NETDATA.requiredJs.push({
2621                 url: NETDATA.serverDefault + 'lib/bootstrap-toggle-2.2.2.min.js',
2622                 isAlreadyLoaded: function() { return false; }
2623             });
2624
2625             NETDATA.requiredJs.push({
2626                 url: NETDATA.serverDefault + 'dashboard_info.js?v20161226-1',
2627                 async: false,
2628                 isAlreadyLoaded: function() { return false; }
2629             });
2630
2631             if(isdemo()) {
2632                 document.getElementById('masthead').style.display = 'block';
2633             }
2634             else {
2635                 if(urlOptions.update_always === true)
2636                     NETDATA.setOption('stop_updates_when_focus_is_lost', !urlOptions.update_always);
2637             }
2638         };
2639
2640         // our entry point
2641         var netdataCallback = initializeDynamicDashboard;
2642     </script>
2643 </head>
2644
2645 <body data-spy="scroll" data-target="#sidebar">
2646     <div id="loadOverlay" class="loadOverlay" style="background-color: #888; color: #888;">
2647         netdata<br/><div style="font-size: 3vh;">Real-time performance monitoring, done right!</div>
2648     </div>
2649     <script type="text/javascript">
2650         // change the loadOverlay colors ASAP to match the theme
2651         document.getElementById('loadOverlay').style = (urlOptions.theme === 'slate')?"background-color:#272b30; color: #373b40;":"background-color:#fff; color: #ddd;";
2652     </script>
2653     <nav class="navbar navbar-default navbar-fixed-top" role="banner">
2654         <div class="container">
2655             <nav id="mynetdata_nav" class="collapse navbar-collapse navbar-left hidden-sm hidden-xs" role="navigation" style="padding-right: 20px;">
2656                 <ul class="nav navbar-nav">
2657                     <li class="dropdown" id="myNetdataDropdownParent">
2658                         <a href="#" class="dropdown-toggle" data-toggle="dropdown">my-netdata <strong class="caret"></strong></a>
2659                         <ul class="dropdown-menu scrollable-menu inpagemenu multi-column columns-2" role="menu" id="myNetdataDropdownUL">
2660                             <div class="row">
2661                                 <div class="col-sm-6" style="width: 85%; padding-right: 0;">
2662                                     <ul id="mynetdata_servers" class="multi-column-dropdown">
2663                                         <li><a href="#" onclick="return false;" style="color: #999;">loading...</a></li>
2664                                     </ul>
2665                                 </div>
2666                                 <div class="col-sm-3 hidden-xs" style="width: 15%; padding-left: 0;">
2667                                     <ul id="mynetdata_actions1" class="multi-column-dropdown">
2668                                     <li style="color: #999;">&nbsp;</li>
2669                                     </ul>
2670                                 </div>
2671                             </div>
2672                         </ul>
2673                     </li>
2674                 </ul>
2675             </nav>
2676             <div class="navbar-header">
2677                 <button class="navbar-toggle" type="button" data-toggle="collapse" data-target=".navbar-collapse">
2678                     <span class="sr-only">Toggle navigation</span>
2679                     <span class="icon-bar"></span>
2680                     <span class="icon-bar"></span>
2681                     <span class="icon-bar"></span>
2682                 </button>
2683                 <a href="/" class="navbar-brand" id="hostname" title="reload the dashboard">netdata</a>
2684             </div>
2685             <nav class="collapse navbar-collapse navbar-right" role="navigation">
2686                 <ul class="nav navbar-nav">
2687                     <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>
2688                     <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>
2689                     <li><a href="https://github.com/firehol/netdata/wiki" class="btn" target="_blank" title="netdata community"><i class="fa fa-github"></i>&nbsp;<span class="hidden-sm hidden-md">Community</span></a></li>
2690                     <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>
2691                     <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>
2692                     <li class="dropdown hidden-sm hidden-md hidden-lg">
2693                         <a href="#" class="dropdown-toggle" data-toggle="dropdown">my-netdata <strong class="caret"></strong></a>
2694                         <ul id="mynetdata_servers2" class="dropdown-menu scrollable-menu inpagemenu" role="menu">
2695                             <li><a href="#" onclick="return false;" style="color: #999;">loading...</a></li>
2696                         </ul>
2697                     </li>
2698                 </ul>
2699             </nav>
2700         </div>
2701     </nav>
2702
2703     <div id="masthead" style="display: none;">
2704         <div class="container">
2705             <div class="row">
2706                 <div class="col-md-7">
2707                     <h1>Netdata
2708                         <p class="lead">Real-time performance monitoring, in the greatest possible detail</p>
2709                     </h1>
2710                 </div>
2711                 <div class="col-md-5">
2712                     <div class="well well-lg">
2713                         <div class="row">
2714                         <div class="col-md-6">
2715                             <b>Drag</b> charts to pan.
2716                             <b>Shift + wheel</b> on them, to zoom in and out.
2717                             <b>Double-click</b> on them, to reset.
2718                             <b>Hover</b> on them too!
2719                             </div>
2720                         <div class="col-md-6">
2721                             <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>
2722                             </div>
2723                         </div>
2724                     </div>
2725                 </div>
2726             </div>
2727         </div>
2728     </div>
2729
2730     <div class="container">
2731         <div class="row">
2732             <div class="charts-body" role="main">
2733                 <div id="charts_div"></div>
2734             </div>
2735             <div class="sidebar-body hidden-xs hidden-sm" id="sidebar-body" role="complementary">
2736                 <nav class="dashboard-sidebar hidden-print hidden-xs hidden-sm" id="sidebar" role="menu"></nav>
2737             </div>
2738         </div>
2739     </div>
2740
2741     <div id="footer" class="container" style="display: none;">
2742         <div class="row">
2743             <div class="col-md-10" role="main">
2744                 <div class="p">
2745                     <big><a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata</a></big><br/>
2746                     <i class="fa fa-copyright"></i> Copyright 2016, Costa Tsaousis.<br/>
2747                     Released under <a href="http://www.gnu.org/licenses/gpl-3.0.en.html" target="_blank">GPL v3 or later</a>.<br/>
2748                 </div>
2749                 <div class="p">
2750                     <small>
2751                         <a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata</a> re-distributes these software tools:
2752
2753                         <i class="fa fa-circle"></i> The excellent <a href="http://dygraphs.com/" target="_blank">Dygraphs.com</a> web chart library,
2754                         <i class="fa fa-copyright"></i> Copyright 2009, Dan Vanderkam, <a href="http://dygraphs.com/legal.html" target="_blank">MIT License</a>
2755
2756                         <i class="fa fa-circle"></i> <a href="https://rendro.github.io/easy-pie-chart/" target="_blank">Easy Pie Chart</a> web chart library,
2757                         <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>
2758
2759                         <i class="fa fa-circle"></i> <a href="http://bernii.github.io/gauge.js/" target="_blank">Gauge.js</a> web chart library,
2760                         <i class="fa fa-copyright"></i> Copyright, Bernard Kobos, <a href="http://bernii.github.io/gauge.js/" target="_blank">MIT License</a>
2761
2762                         <i class="fa fa-circle"></i> <a href="https://jquery.org/" target="_blank">jQuery</a>,
2763                         <i class="fa fa-copyright"></i> Copyright 2015, jQuery Foundation, <a href="https://jquery.org/license/" target="_blank">MIT License</a>
2764
2765                         <i class="fa fa-circle"></i> <a href="http://getbootstrap.com/getting-started/" target="_blank">Bootstrap</a>,
2766                         <i class="fa fa-copyright"></i> Copyright 2015, Twitter, <a href="http://getbootstrap.com/getting-started/#license-faqs" target="_blank">MIT License</a>
2767
2768                         <i class="fa fa-circle"></i> <a href="http://www.bootstraptoggle.com/" target="_blank">Bootstrap Toggle</a>,
2769                         <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>
2770
2771                         <i class="fa fa-circle"></i> <a href="https://github.com/noraesae/perfect-scrollbar" target="_blank">perfect-scrollbar</a>,
2772                         <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>
2773
2774                         <i class="fa fa-circle"></i> <a href="https://fortawesome.github.io/Font-Awesome/" target="_blank">FontAwesome</a>,
2775                         <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>
2776
2777                         <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.
2778
2779                         <i class="fa fa-circle"></i> <a href="http://bootstrap-table.wenzhixin.net.cn/" target="_blank">bootstrap-table</a>,
2780                         <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>
2781
2782                         <i class="fa fa-circle"></i> <a href="https://github.com/hhurz/tableExport.jquery.plugin" target="_blank">tableExport.jquery.plugin</a>,
2783                         <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>
2784
2785                     </small>
2786                 </div>
2787             </div>
2788         </div>
2789     </div>
2790
2791     <div class="modal fade" id="welcomeModal" tabindex="-1" role="dialog" aria-labelledby="welcomeModalLabel">
2792         <div class="modal-dialog modal-lg" role="document">
2793             <div class="modal-content">
2794                 <div class="modal-header">
2795                     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
2796                     <h4 class="modal-title" id="welcomeModalLabel">Welcome to the world of netdata</h4>
2797                 </div>
2798                 <div class="modal-body">
2799                     <div class="p">
2800                         <div style="width: 100%; text-align: center; padding-top: 10px; padding-bottom: 10px; font-size: 18px;">
2801                             if there is a metric for something, we want it visualised<br/>
2802                             and we want this visualisation to be <strong>real-time</strong>, <strong>efficient</strong> and <strong>awesome</strong>
2803                         </div>
2804                     </div>
2805                     <div class="p">
2806                         <b><a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata</a></b>
2807                         is a new way to monitor your systems and applications, to get <strong>real-time insights</strong>
2808                         of what is really happening and what affects performance.
2809                         It is carefully optimised to be a real-time system, without interfering in any way,
2810                         to the core function of your systems.
2811                     </div>
2812                     <div class="p">
2813                         <b><a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata</a></b>
2814                         has been designed to monitor <strong>massive amounts of metrics, per server, per second</strong>.
2815                         When installed, it might come up with 1k to 3k metrics, but we have been testing it with 100k
2816                         metrics, all collected per second, and still the cpu utilisation remained negligible.
2817                         <br/>
2818                         We have also tried to give each metric, a meaning, a context.
2819                         We have grouped and categorized all metrics into meaningful charts, providing a
2820                         better understanding of the underlying technologies and mechanisms.
2821                     </div>
2822                     <div class="p">
2823                         <b><a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata</a></b> is free,
2824                         open-source software. If you decide to use it,
2825                         <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>.
2826                     </div>
2827                     <div class="p">
2828                         Enjoy real-time performance monitoring!
2829                     </div>
2830                     <div class="p">
2831                         Costa Tsaousis
2832                     </div>
2833                 </div>
2834                 <div class="modal-footer">
2835                     <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
2836                 </div>
2837             </div>
2838         </div>
2839     </div>
2840
2841     <div class="modal fade" id="helpModal" tabindex="-1" role="dialog" aria-labelledby="helpModalLabel">
2842         <div class="modal-dialog modal-lg" role="document">
2843             <div class="modal-content">
2844                 <div class="modal-header">
2845                     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
2846                     <h4 class="modal-title" id="helpModalLabel">Dashboard Help</h4>
2847                 </div>
2848                 <div class="modal-body">
2849
2850                     <h4>Dygraphs (line, area and stacked area charts)</h4>
2851
2852                     <!-- Nav tabs -->
2853                     <ul class="nav nav-tabs" role="tablist">
2854                         <li role="presentation" class="active"><a href="#help_mouse" aria-controls="help_mouse" role="tab" data-toggle="tab">Mouse Interface</a></li>
2855                         <li role="presentation"><a href="#help_touch" aria-controls="help_touch" role="tab" data-toggle="tab">Touch Interface</a></li>
2856                     </ul>
2857
2858                     <!-- Tab panes -->
2859                     <div class="tab-content">
2860                         <div role="tabpanel" class="tab-pane active" id="help_mouse">
2861                             <div class="p">
2862                                 <h4>Mouse Over / Hover</h4>
2863                                 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).
2864                                 <br/>
2865                                 All the other visible charts will also show and highlight their values for the same timestamp.
2866                             </div>
2867                             <hr/>
2868                             <div class="p">
2869                                 <h4>Drag Chart Contents</h4>
2870                                 Drag the contents of a chart to pan it horizontally.
2871                                 <br/>
2872                                 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).
2873                                 <br/>
2874                                 Once a chart is panned, auto refreshing stops for all charts. To enable it again, <b>double click</b> a panned chart.
2875                             </div>
2876                             <hr/>
2877                             <div class="p">
2878                                 <h4>Double Click</h4>
2879                                 Double Click a chart to reset all the charts to their default auto-refreshing state.
2880                             </div>
2881                             <hr/>
2882                             <div class="p">
2883                                 <h4>SHIFT + Drag</h4>
2884                                 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:
2885                                 <ul>
2886                                     <li>The already loaded chart contents are zoomed (low resolution)</li>
2887                                     <li>New data are transferred from the netdata server, to refresh the chart with possibly more detail.</li>
2888                                 </ul>
2889                                 Once a chart is zoomed, auto refreshing stops for all charts. To enable it again, <b>double click</b> a zoomed chart.
2890                             </div>
2891                             <hr/>
2892                             <div class="p">
2893                                 <h4>SHIFT + Mouse Wheel</h4>
2894                                 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.
2895                                 <br/>
2896                                 Once a chart is zoomed, auto refreshing stops for all charts. To enable it again, <b>double click</b> a zoomed chart.
2897                             </div>
2898                             <hr/>
2899                             <div class="p">
2900                                 <h4>Legend Operations</h4>
2901                                 Click on the label or value of a dimension, will select / un-select this dimension.
2902                                 <br/>
2903                                 You can press any of the SHIFT or CONTROL keys and then click on legend labels or values, to select / un-select multiple dimensions.
2904                             </div>
2905                         </div>
2906                         <div role="tabpanel" class="tab-pane" id="help_touch">
2907                             <div class="p">
2908                                 <h4>Single Tap</h4>
2909                                 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).
2910                                 <br/>
2911                                 All the other visible charts will also show and highlight their values for the same timestamp.
2912                             </div>
2913                             <hr/>
2914                             <div class="p">
2915                                 <h4>Drag Chart Contents</h4>
2916                                 Touch and Drag the contents of a chart to pan it horizontally.
2917                                 <br/>
2918                                 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).
2919                                 <br/>
2920                                 Once a chart is panned, auto refreshing stops for all charts. To enable it again, <b>double tap</b> a panned chart.
2921                             </div>
2922                             <hr/>
2923                             <div class="p">
2924                                 <h4>Double Tap</h4>
2925                                 Double tap a chart to reset all the charts to their default auto-refreshing state.
2926                             </div>
2927                             <hr/>
2928                             <div class="p">
2929                                 <h4>Zoom <small>(does not work on firefox and IE/Edge)</small></h4>
2930                                 With two fingers, zoom in or out.
2931                                 <br/>
2932                                 Once a chart is zoomed, auto refreshing stops for all charts. To enable it again, <b>double click</b> a zoomed chart.
2933                             </div>
2934                             <hr/>
2935                             <div class="p">
2936                                 <h4>Legend Operations</h4>
2937                                 Tap on the label or value of a dimension, will select / un-select this dimension.
2938                             </div>
2939                         </div>
2940                     </div>
2941                 </div>
2942                 <div class="modal-footer">
2943                     <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
2944                 </div>
2945             </div>
2946         </div>
2947     </div>
2948
2949     <div class="modal fade" id="alarmsModal" tabindex="-1" role="dialog" aria-labelledby="alarmsModalLabel">
2950         <div class="modal-dialog modal-lg" role="document"  style="display: table;"> <!-- allow the modal to expand horizontally -->
2951             <div class="modal-content">
2952                 <div class="modal-header">
2953                     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
2954                     <h4 class="modal-title" id="alarmsModalLabel">netdata alarms</h4>
2955                 </div>
2956                 <div class="modal-body">
2957                     <!-- Nav tabs -->
2958                     <ul class="nav nav-tabs" role="tablist">
2959                         <li role="presentation" class="active"><a href="#alarms_active" aria-controls="alarms_active" role="tab" data-toggle="tab">Active</a></li>
2960                         <li role="presentation"><a href="#alarms_all" aria-controls="alarms_all" role="tab" data-toggle="tab">All</a></li>
2961                         <li role="presentation"><a href="#alarms_log" aria-controls="alarms_log" role="tab" data-toggle="tab">Log</a></li>
2962                     </ul>
2963
2964                     <!-- Tab panes -->
2965                     <div class="tab-content">
2966                         <div role="tabpanel" class="tab-pane active" id="alarms_active">
2967                             loading...
2968                         </div>
2969                         <div role="tabpanel" class="tab-pane" id="alarms_all">
2970                             loading...
2971                         </div>
2972                         <div role="tabpanel" class="tab-pane" id="alarms_log">
2973                             loading...
2974                         </div>
2975                     </div>
2976                 </div>
2977                 <div class="modal-footer">
2978                     <!-- <a href="#" onclick="alarmsUpdateModal(); return false;" type="button" class="btn btn-default">Update</a> -->
2979                     <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
2980                 </div>
2981             </div>
2982         </div>
2983     </div>
2984
2985     <div class="modal fade" id="optionsModal" tabindex="-1" role="dialog" aria-labelledby="optionsModalLabel">
2986         <div class="modal-dialog modal-lg" role="document">
2987             <div class="modal-content">
2988                 <div class="modal-header">
2989                     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
2990                     <h4 class="modal-title" id="optionsModalLabel">netdata dashboard options</h4>
2991                 </div>
2992                 <div class="modal-body">
2993                     <center>
2994                         <small style="color: #BBBBBB;">These are browser settings. Each viewer has its own. They do not affect the operation of your netdata server.
2995                         <br/>
2996                         Settings take effect immediately and are saved permanently to browser local storage (except the refresh on focus / always option).
2997                         <br/>
2998                         To reset all options (including charts sizes) to their defaults, click <a href="#" onclick="resetDashboardOptions(); return false;">here</a>.</small>
2999                     </center>
3000                     <div style="padding: 10px;"></div>
3001
3002                     <!-- Nav tabs -->
3003                     <ul class="nav nav-tabs" role="tablist">
3004                         <li role="presentation" class="active"><a href="#settings_performance" aria-controls="settings_performance" role="tab" data-toggle="tab">Performance</a></li>
3005                         <li role="presentation"><a href="#settings_sync" aria-controls="settings_sync" role="tab" data-toggle="tab">Synchronization</a></li>
3006                         <li role="presentation"><a href="#settings_visual" aria-controls="settings_visual" role="tab" data-toggle="tab">Visual</a></li>
3007                     </ul>
3008
3009                     <!-- Tab panes -->
3010                     <div class="tab-content">
3011                         <div role="tabpanel" class="tab-pane active" id="settings_performance">
3012                             <form id="optionsForm1" method="get" class="form-horizontal">
3013                                 <div class="form-group">
3014                                     <table>
3015                                     <tr class="option-row">
3016                                         <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>
3017                                         <td class="option-info"><strong>When to refresh the charts?</strong><br/>
3018                                             <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>
3019                                         </td>
3020                                         </tr>
3021                                     <tr class="option-row">
3022                                         <td class="option-control">
3023                                         <input id="eliminate_zero_dimensions" type="checkbox" checked data-toggle="toggle" data-on="Non Zero" data-off="All" data-width="110px">
3024                                         </td>
3025                                         <td class="option-info"><strong>Which dimensions to show?</strong><br/>
3026                                             <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>
3027                                         </td>
3028                                         </tr>
3029                                     <tr class="option-row">
3030                                         <td class="option-control"><input id="destroy_on_hide" type="checkbox" data-toggle="toggle" data-on="Destroy" data-off="Hide" data-width="110px"></td>
3031                                         <td class="option-info"><strong>How to handle hidden charts?</strong><br/>
3032                                             <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>
3033                                         </td>
3034                                         </tr>
3035                                     <tr class="option-row">
3036                                         <td class="option-control"><input id="async_on_scroll" type="checkbox" data-toggle="toggle" data-on="Async" data-off="Sync" data-width="110px"></td>
3037                                         <td class="option-info"><strong>Page scroll handling?</strong><br/>
3038                                             <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>
3039                                         </td>
3040                                         </tr>
3041                                     </table>
3042                                 </div>
3043                             </form>
3044                         </div>
3045                         <div role="tabpanel" class="tab-pane" id="settings_sync">
3046                             <form id="optionsForm2" method="get" class="form-horizontal">
3047                                 <div class="form-group">
3048                                     <table>
3049                                     <tr class="option-row">
3050                                         <td class="option-control"><input id="parallel_refresher" type="checkbox" checked data-toggle="toggle" data-on="Parallel" data-off="Sequential" data-width="110px"></td>
3051                                         <td class="option-info"><strong>Which chart refresh policy to use?</strong><br/>
3052                                             <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>
3053                                         </td>
3054                                     </tr>
3055                                     <tr class="option-row" id="concurrent_refreshes_row">
3056                                         <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>
3057                                         <td class="option-info"><strong>Shall we re-sync chart refreshes?</strong><br/>
3058                                             <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>
3059                                         </td>
3060                                     </tr>
3061                                     <tr class="option-row">
3062                                         <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>
3063                                         <td class="option-info"><strong>Sync hover selection on all charts?</strong><br/>
3064                                             <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>
3065                                         </td>
3066                                         </tr>
3067                                     <tr class="option-row">
3068                                         <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>
3069                                         <td class="option-info"><strong>Sync pan and zoom on all charts?</strong><br/>
3070                                             <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>
3071                                         </td>
3072                                         </tr>
3073                                     </table>
3074                                 </div>
3075                             </form>
3076                         </div>
3077                         <div role="tabpanel" class="tab-pane" id="settings_visual">
3078                             <form id="optionsForm3" method="get" class="form-horizontal">
3079                                 <div class="form-group">
3080                                     <table>
3081                                     <tr class="option-row">
3082                                         <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>
3083                                         <td class="option-info"><strong>Which theme to use?</strong><br/>
3084                                             <small>Netdata comes with two themes: <b>Dark</b> (the default) and <b>White</b>.
3085                                             <br/>
3086                                             <b>Switching this will reload the dashboard</b>.
3087                                             </small>
3088                                         </td>
3089                                         </tr>
3090                                     <tr class="option-row">
3091                                         <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>
3092                                         <td class="option-info"><strong>Do you need help?</strong><br/>
3093                                             <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.
3094                                             <br/>
3095                                             <b>Switching this will reload the dashboard</b>.
3096                                             </small>
3097                                         </td>
3098                                         </tr>
3099                                     <tr class="option-row">
3100                                         <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>
3101                                         <td class="option-info"><strong>Enable data padding when panning and zooming?</strong><br/>
3102                                             <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>
3103                                         </td>
3104                                         </tr>
3105                                     <tr class="option-row">
3106                                         <td class="option-control"><input id="smooth_plot" type="checkbox" checked data-toggle="toggle"  data-on="Smooth" data-off="Rough" data-width="110px"></td>
3107                                         <td class="option-info"><strong>Enable Bézier lines on charts?</strong><br/>
3108                                             <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.
3109                                             <br/>
3110                                             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>
3111                                         </td>
3112                                         </tr>
3113                                     </table>
3114                                 </div>
3115                             </form>
3116                         </div>
3117                     </div>
3118                 </div>
3119                 <div class="modal-footer">
3120                     <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
3121                 </div>
3122             </div>
3123         </div>
3124     </div>
3125
3126
3127     <div class="modal fade" id="updateModal" tabindex="-1" role="dialog" aria-labelledby="updateModalLabel">
3128         <div class="modal-dialog" role="document">
3129             <div class="modal-content">
3130                 <div class="modal-header">
3131                     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
3132                     <h4 class="modal-title" id="updateModalLabel">Update Check</h4>
3133                 </div>
3134                 <div class="modal-body">
3135                     Your netdata version: <b><code><span id="netdataVersion">Unknown</span></code></b>
3136                     <br/>
3137                     <div style="padding: 10px;"></div>
3138                     <div id="versionCheckLog">Not checked yet. Please press the Check Now button.</div>
3139                 </div>
3140                 <div class="modal-footer">
3141                     <a href="#" onclick="notifyForUpdate(true); return false;" type="button" class="btn btn-default">Check Now</a>
3142                     <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
3143                 </div>
3144             </div>
3145         </div>
3146     </div>
3147
3148     <div class="modal fade" id="deleteRegistryModal" tabindex="-1" role="dialog" aria-labelledby="deleteRegistryModalLabel">
3149         <div class="modal-dialog" role="document">
3150             <div class="modal-content">
3151                 <div class="modal-header">
3152                     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
3153                     <h4 class="modal-title" id="deleteRegistryModalLabel">Delete <span id="deleteRegistryServerName"></span>?</h4>
3154                 </div>
3155                 <div class="modal-body">
3156                     You are about to delete, from your personal list of netdata servers, the following server:
3157                     <p style="text-align: center; padding-top: 10px; padding-bottom: 10px; line-height: 2;">
3158                     <b><span id="deleteRegistryServerName2"></span></b>
3159                     <br/>
3160                     <b><span id="deleteRegistryServerURL"></span></b>
3161                     </p>
3162                     Are you sure you want to do this?
3163                     <br/>
3164                     <div style="padding: 10px;"></div>
3165                     <small>Keep in mind, this server will be added back if and when you visit it again.</small>
3166                     <br/>
3167                     <div id="deleteRegistryResponse" style="display: block; width: 100%; text-align: center; padding-top: 20px;"></div>
3168                 </div>
3169                 <div class="modal-footer">
3170                     <button type="button" class="btn btn-success" data-dismiss="modal">keep it</button>
3171                     <a href="#" onclick="notifyForDeleteRegistry(true); return false;" type="button" class="btn btn-danger">delete it</a>
3172                 </div>
3173             </div>
3174         </div>
3175     </div>
3176
3177     <div class="modal fade" id="switchRegistryModal" tabindex="-1" role="dialog" aria-labelledby="switchRegistryModalLabel">
3178         <div class="modal-dialog" role="document">
3179             <div class="modal-content">
3180                 <div class="modal-header">
3181                     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
3182                     <h4 class="modal-title" id="switchRegistryModalLabel">Switch Netdata Registry Identity</h4>
3183                 </div>
3184                 <div class="modal-body">
3185                     You can copy and paste the following ID to all your browsers (e.g. work and home).
3186                     <br/>
3187                     All the browsers with the same ID will identify <b>you</b>, so please don't share this with others.
3188                     <p style="text-align: center; padding-top: 10px; padding-bottom: 10px; line-height: 2;">
3189                         <form action="#">
3190                             <input type="text" class="form-control" id="switchRegistryPersonGUID" placeholder="your personal ID" maxlength="36" autocomplete="off" style="text-align: center; font-size: 1.4em;">
3191                         </form>
3192                     </p>
3193                     Either copy this ID and paste it to another browser, or paste here the ID you have taken from another browser.
3194                     <p style="padding-top: 10px;"><small>
3195                         Keep in mind that:
3196                         <ul>
3197                             <li>when you switch ID, your previous ID will be lost forever - this is irreversible.</li>
3198                             <li>both IDs (your old and the new) must list this netdata at their personal lists.</li>
3199                             <li>both IDs have to be known by the registry: <b><span id="switchRegistryURL"></span></b>.</li>
3200                             <li>to get a new ID, just clear your browser cookies.</li>
3201                         </ul>
3202                     </small></p>
3203                     <div id="switchRegistryResponse" style="display: block; width: 100%; text-align: center; padding-top: 20px;"></div>
3204                 </div>
3205                 <div class="modal-footer">
3206                     <button type="button" class="btn btn-success" data-dismiss="modal">cancel</button>
3207                     <a href="#" onclick="notifyForSwitchRegistry(true); return false;" type="button" class="btn btn-danger">impersonate</a>
3208                 </div>
3209             </div>
3210         </div>
3211     </div>
3212
3213     <div class="modal fade" id="gotoServerModal" tabindex="-1" role="dialog" aria-labelledby="gotoServerModalLabel">
3214         <div class="modal-dialog" role="document">
3215             <div class="modal-content">
3216                 <div class="modal-header">
3217                     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
3218                     <h4 class="modal-title" id="gotoServerModalLabel"><span id="gotoServerName"></span></h4>
3219                 </div>
3220                 <div class="modal-body">
3221                     Checking known URLs for this server...
3222                     <div  style="padding-top: 20px;">
3223                         <table id="gotoServerList">
3224                         </table>
3225                     </div>
3226                     <p style="padding-top: 10px;"><small>
3227                         Checks may fail if you are viewing an HTTPS page and the server to be checked is HTTP only.
3228                     </small></p>
3229                     <div id="gotoServerResponse" 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-default" data-dismiss="modal">Close</button>
3233                 </div>
3234             </div>
3235         </div>
3236     </div>
3237 </body>
3238 </html>
3239 <script type="text/javascript" src="dashboard.js?v20161229-4"></script>