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