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