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