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