]> arthur.barton.de Git - netdata.git/blob - web/index.html
e2a40f11be606edc284cc84f1df1d5438c29b4fd
[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="32x32" href="images/seo-performance-32.png">
27     <link rel="icon" type="image/png" sizes="24x24" href="images/seo-performance-24.png">
28     <link rel="icon" type="image/png" sizes="16x16" href="images/seo-performance-16.png">
29
30     <meta property="og:locale" content="en_US" />
31     <meta property="og:image" content="http://my-netdata.io/images/post.png"/>
32     <meta property="og:url" content="http://my-netdata.io/"/>
33     <meta property="og:type" content="website"/>
34     <meta property="og:site_name" content="netdata"/>
35     <meta property="og:title" content="netdata - real-time performance monitoring, done right!"/>
36     <meta property="og:description" content="Stunning real-time dashboards, blazingly fast and extremely interactive. Zero configuration, zero dependencies, zero maintenance." />
37
38     <style>
39     /* prevent body from hiding under the navbar */
40     body {
41         padding-top: 50px;
42     }
43
44     .loadOverlay {
45         position: absolute;
46         top: 0px;
47         left: 0px;
48         width: 100%;
49         height:100%;
50         z-index: 2000;
51         font-size: 10vh;
52         font-family: sans-serif;
53         padding: 40vh 0 40vh 0;
54         font-weight: bold;
55         text-align: center;
56     }
57
58     .modal-wide .modal-dialog {
59         width: 80%;
60     }
61
62     /* fix # anchors scrolling under the navbar
63        https://github.com/twbs/bootstrap/issues/1768#issuecomment-46519033
64      */
65     h1 {
66         position: relative;
67         z-index: -1;
68     }
69     h2 {
70         position: relative;
71         z-index: -2;
72     }
73     h1:before, h2:before {
74         display: block;
75         content: " ";
76         margin-top: -70px;
77         height: 70px;
78         visibility: hidden;
79     }
80
81     .p {
82         display: block;
83         margin-top: 15px;
84     }
85
86     .option-row,
87     .option-control {
88         vertical-align: top;
89         padding: 10px;
90         padding-top: 30px;
91         padding-left: 30px;
92     }
93
94     .option-info {
95         padding: 10px;
96     }
97
98     .chart-message {
99         display: block;
100         margin-top: 10px;
101     }
102
103     #masthead h1 {
104         /*font-size: 30px;*/
105         line-height: 1;
106         padding-top: 30px;
107     }
108
109     #masthead .well {
110         margin-top:4%;
111     }
112
113     /* fix the navbar shifting when a modal is open */
114     /* https://github.com/twbs/bootstrap/issues/14040#issuecomment-159891033 */
115     body.modal-open{
116         width: 100% !important;
117         padding-right: 0 !important;
118 /*      overflow-y: scroll !important; */
119 /*      position: fixed !important;*/
120         overflow: visible;
121     }
122
123     /* make accordion use the whole header bar for expand/collapse */
124     .panel-title a {
125         display: block;
126         padding: 10px 15px;
127         margin: -10px -15px;
128     }
129
130     /*
131      * Side navigation
132      *
133      * Scrollspy and affixed enhanced navigation to highlight sections and secondary
134      * sections of docs content.
135      */
136
137     .affix {
138         position: static;
139         top: 70px !important;
140         /*width: 220px;*/
141     }
142
143     .affix-top {
144         /*width: 220px;*/
145     }
146
147     .dashboard-sidebar {
148         max-height: calc(100% - 70px) !important;
149         overflow-y: auto;
150         /*width: 220px !important;*/
151     }
152
153     /* By default it's not affixed in mobile views, so undo that */
154     .dashboard-sidebar.affix {
155         position: static;
156     }
157
158     @media (min-width: 768px) {
159         .dashboard-sidebar {
160             padding-left: 20px;
161         }
162     }
163
164     /* First level of nav */
165     .dashboard-sidenav {
166         margin-top: 20px;
167         margin-bottom: 20px;
168     }
169
170     /* All levels of nav */
171     .dashboard-sidebar .nav > li > a {
172         display: block;
173         padding: 4px 20px;
174         font-size: 13px;
175         font-weight: 500;
176         color: #767676;
177     }
178     .dashboard-sidebar .nav > li > a:hover,
179     .dashboard-sidebar .nav > li > a:focus {
180         padding-left: 19px;
181         color: #563d7c;
182         text-decoration: none;
183         background-color: transparent;
184         border-left: 1px solid #563d7c;
185     }
186     .dashboard-sidebar .nav > .active > a,
187     .dashboard-sidebar .nav > .active:hover > a,
188     .dashboard-sidebar .nav > .active:focus > a {
189         padding-left: 18px;
190         font-weight: bold;
191         color: #563d7c;
192         background-color: transparent;
193         border-left: 2px solid #563d7c;
194     }
195
196     /* Nav: second level (shown on .active) */
197     .dashboard-sidebar .nav .nav {
198         display: none; /* Hide by default, but at >768px, show it */
199         padding-bottom: 10px;
200     }
201     .dashboard-sidebar .nav .nav > li > a {
202         padding-top: 1px;
203         padding-bottom: 1px;
204         padding-left: 30px;
205         font-size: 12px;
206         font-weight: normal;
207     }
208     .dashboard-sidebar .nav .nav > li > a:hover,
209     .dashboard-sidebar .nav .nav > li > a:focus {
210         padding-left: 29px;
211     }
212     .dashboard-sidebar .nav .nav > .active > a,
213     .dashboard-sidebar .nav .nav > .active:hover > a,
214     .dashboard-sidebar .nav .nav > .active:focus > a {
215         padding-left: 28px;
216         font-weight: 500;
217     }
218
219     .dropdown-menu {
220         min-width: 200px;
221     }
222     .dropdown-menu.columns-2 {
223         margin: 0;
224         padding: 0;
225         width: 400px;
226     }
227     .dropdown-menu li a {
228         padding: 5px 15px;
229         font-weight: 300;
230     }
231     .dropdown-menu.multi-column {
232         overflow-x: hidden;
233     }
234     .multi-column-dropdown {
235         list-style: none;
236         padding: 0;
237     }
238     .multi-column-dropdown li a {
239         display: block;
240         clear: both;
241         line-height: 1.428571429;
242         white-space: normal;
243     }
244     .multi-column-dropdown li a:hover {
245         text-decoration: none;
246         color: #f5f5f5;
247         background-color: #262626;
248     }
249     .scrollable-menu {
250         height: auto;
251         max-height: 80vh;
252         overflow-x: hidden;
253     }
254
255     /* Back to top (hidden on mobile) */
256     .back-to-top,
257     .dashboard-theme-toggle {
258         display: none;
259         padding: 4px 10px;
260         margin-top: 10px;
261         margin-left: 10px;
262         font-size: 12px;
263         font-weight: 500;
264         color: #999;
265     }
266     .back-to-top:hover,
267     .dashboard-theme-toggle:hover {
268         color: #563d7c;
269         text-decoration: none;
270     }
271     .dashboard-theme-toggle {
272         margin-top: 0;
273     }
274
275     .container {
276         width: calc(100% - 20px) !important;
277     }
278
279     .charts-body {
280         display: inline-block;
281         width: 100%;
282     }
283
284     .sidebar-body {
285         position: absolute;
286         display: none;
287     }
288
289     @media (min-width: 768px) {
290         .charts-body {
291             padding-left: 0%;
292             padding-right: 0%;
293         }
294
295         .back-to-top,
296         .dashboard-theme-toggle {
297             display: block;
298         }
299     }
300
301     /* Show and affix the side nav when space allows it */
302     @media (min-width: 992px) {
303         .container {
304             padding-left: 0% !important;
305         }
306
307         .charts-body {
308             width: calc(100% - 213px) !important;
309             padding-left: 1% !important;
310             padding-right: 0% !important;
311         }
312
313         .sidebar-body {
314             display: inline-block !important;
315             width: 213px !important;
316         }
317
318         .dashboard-sidebar .nav > .active > ul {
319             display: block;
320         }
321
322         /* Widen the fixed sidebar */
323         .dashboard-sidebar.affix,
324         .dashboard-sidebar.affix-top,
325         .dashboard-sidebar.affix-bottom {
326             width: 213px !important;
327         }
328         .dashboard-sidebar.affix {
329             position: fixed; /* Undo the static from mobile first approach */
330             top: 20px;
331         }
332         .dashboard-sidebar.affix-bottom {
333             position: absolute; /* Undo the static from mobile first approach */
334         }
335         .dashboard-sidebar.affix-bottom .dashboard-sidenav,
336         .dashboard-sidebar.affix .dashboard-sidenav {
337             margin-top: 0;
338             margin-bottom: 0;
339         }
340     }
341
342     @media (min-width: 1200px) {
343         .container {
344             padding-left: 2% !important;
345         }
346
347         .charts-body {
348             width: calc(100% - 233px) !important;
349             padding-left: 1% !important;
350             padding-right: 1% !important;
351         }
352
353         .sidebar-body {
354             display: inline-block !important;
355             width: 233px !important;
356         }
357
358         /* Widen the fixed sidebar again */
359         .dashboard-sidebar.affix,
360         .dashboard-sidebar.affix-top,
361         .dashboard-sidebar.affix-bottom {
362             width: 233px !important;
363         }
364     }
365     
366     @media (min-width: 1360px) {
367         .container {
368             padding-left: 3% !important;
369         }
370
371         .charts-body {
372             width: calc(100% - 263px) !important;
373             padding-left: 1% !important;
374             padding-right: 2% !important;
375         }
376
377         .sidebar-body {
378             display: inline-block !important;
379             width: 263px !important;
380         }
381
382         /* Widen the fixed sidebar again */
383         .dashboard-sidebar.affix,
384         .dashboard-sidebar.affix-top,
385         .dashboard-sidebar.affix-bottom {
386             width: 263px !important;
387         }
388     }
389
390     </style>
391 </head>
392
393 <!-- check which theme to use -->
394 <script type="text/javascript">
395     // enable alarms checking and notifications
396     var netdataShowAlarms = true;
397
398     // enable registry updates
399     var netdataRegistry = true;
400     
401     // --------------------------------------------------------------------
402     // urlOptions
403
404     var urlOptions = {
405         hash: '#',
406         theme: null,
407         help: null,
408         pan_and_zoom: false,
409         after: 0,
410         before: 0,
411         nowelcome: false,
412         show_alarms: false,
413         chart: null,
414         family: null,
415         alarm: null,
416         alarm_unique_id: 0,
417         alarm_id: 0,
418         alarm_event_id: 0,
419         hasProperty: function(property) {
420             // console.log('checking property ' + property + ' of type ' + typeof(this[property]));
421             return typeof this[property] !== 'undefined';
422         }
423     };
424
425     function netdataPanAndZoomCallback(status, after, before) {
426         urlOptions.pan_and_zoom = status;
427         urlOptions.after = after;
428         urlOptions.before = before;
429         netdataHashUpdate();
430     }
431
432     function netdataHashUpdate() {
433         history.replaceState(null, '', netdataHash());
434     }
435
436     function netdataHash() {
437         var hash = urlOptions.hash;
438
439         if(urlOptions.pan_and_zoom === true) {
440             hash += ';after='  + urlOptions.after.toString() +
441                     ';before=' + urlOptions.before.toString();
442         }
443
444         if(urlOptions.theme !== null)
445             hash += ';theme=' + urlOptions.theme.toString();
446
447         if(urlOptions.help !== null)
448             hash += ';help=' + urlOptions.help.toString();
449
450         return hash;
451     }
452
453     function netdataHashParse() {
454         var variables = document.location.hash.split(';');
455         var len = variables.length;
456         while(len--) {
457             if(len !== 0) {
458                 var p = variables[len].split('=');
459                 if(urlOptions.hasProperty(p[0]) && typeof p[1] !== 'undefined')
460                     urlOptions[p[0]] = decodeURIComponent(p[1]);
461             }
462             else {
463                 if(variables[len].length > 0)
464                     urlOptions.hash = variables[len];
465             }
466         }
467
468         var booleans = [ 'nowelcome', 'show_alarms', 'pan_and_zoom' ];
469         len = booleans.length;
470         while(len--) {
471             if(urlOptions[booleans[len]] === 'true' || urlOptions[booleans[len]] === true || urlOptions[booleans[len]] === '1' || urlOptions[booleans[len]] === 1)
472                 urlOptions[booleans[len]] = true;
473             else
474                 urlOptions[booleans[len]] = false;
475         }
476
477         if(urlOptions.before > 0 && urlOptions.after > 0) {
478             urlOptions.pan_and_zoom = true;
479             urlOptions.nowelcome = true;
480         }
481         else
482             urlOptions.pan_and_zoom = false;
483
484         // console.log(urlOptions);
485     }
486
487     netdataHashParse();
488
489     // --------------------------------------------------------------------
490     // check options that should be processed before loading netdata.js
491     
492     function loadLocalStorage(name) {
493         var ret = null;
494
495         try {
496             if(typeof Storage !== "undefined" && typeof localStorage === 'object')
497                 ret = localStorage.getItem(name);
498         }
499         catch(error) {
500             ;
501         }
502
503         if(typeof ret === 'undefined' || ret === null)
504             return null;
505
506         // console.log('loaded: ' + name.toString() + ' = ' + ret.toString());
507
508         return ret;
509     }
510
511     function saveLocalStorage(name, value) {
512         // console.log('saving: ' + name.toString() + ' = ' + value.toString());
513         try {
514             if(typeof Storage !== "undefined" && typeof localStorage === 'object') {
515                 localStorage.setItem(name, value.toString());
516                 return true;
517             }
518         }
519         catch(error) {
520             ;
521         }
522
523         return false;
524     }
525
526     function getTheme(def) {
527         var ret = loadLocalStorage('netdataTheme');
528         if(typeof ret === 'undefined' || ret === null || ret === 'undefined')
529             return def;
530         else
531             return ret;
532     }
533
534     function setTheme(theme) {
535         if(theme === netdataTheme) return false;
536         return saveLocalStorage('netdataTheme', theme);
537     }
538
539     var netdataTheme = getTheme('slate');
540     var netdataShowHelp = true;
541
542     if(urlOptions.theme !== null) {
543         setTheme(urlOptions.theme);
544         netdataTheme = urlOptions.theme;
545     }
546     else
547         urlOptions.theme = netdataTheme;
548
549     if(urlOptions.help !== null) {
550         saveLocalStorage('options.show_help', urlOptions.help);
551         netdataShowHelp = urlOptions.help;
552     }
553     else {
554         urlOptions.help = loadLocalStorage('options.show_help');
555     }
556
557     // --------------------------------------------------------------------
558     // registry call back to render my-netdata menu
559
560     var netdataRegistryCallback = function(machines_array) {
561         var el = '';
562         var a1 = '';
563         var found = 0;
564
565         if(machines_array === null) {
566             var ret = loadLocalStorage("registryCallback");
567             if(typeof ret !== 'undefined' && ret !== null) {
568                 machines_array = JSON.parse(ret);
569                 console.log("failed to contact the registry - loaded registry data from browser local storage");
570             }
571         }
572
573         if(machines_array) {
574             saveLocalStorage("registryCallback", JSON.stringify(machines_array));
575
576             var machines = machines_array.sort(function (a, b) {
577                 if (a.name > b.name) return -1;
578                 if (a.name < b.name) return 1;
579                 return 0;
580             });
581
582             var len = machines.length;
583             while(len--) {
584                 var u = machines[len];
585                 found++;
586                 el += '<li id="registry_server_' + u.guid + '"><a class="registry_link" href="' + u.url + '" onClick="return gotoServerModalHandler(\'' + u.guid + '\');">' + u.name + '</a></li>';
587                 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>';
588             }
589         }
590
591         if(!found) {
592             if(machines)
593                 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>';
594             else
595                 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>';
596
597             a1 += '<li><a href="#" onClick="return false;">&nbsp;</a></li>';
598
599             el += '<li role="separator" class="divider"></li>' +
600                     '<li><a href="//london.netdata.rocks/default.html">UK - London (DigitalOcean.com)</a></li>' +
601                     '<li><a href="//newyork.netdata.rocks/default.html">US - New York (DigitalOcean.com)</a></li>' +
602                     '<li><a href="//sanfrancisco.netdata.rocks/default.html">US - San Francisco (DigitalOcean.com)</a></li>' +
603                     '<li><a href="//atlanta.netdata.rocks/default.html">US - Atlanta (CDN77.com)</a></li>' +
604                     '<li><a href="//frankfurt.netdata.rocks/default.html">Germany - Frankfurt (DigitalOcean.com)</a></li>' +
605                     '<li><a href="//toronto.netdata.rocks/default.html">Canada - Toronto (DigitalOcean.com)</a></li>' +
606                     '<li><a href="//singapore.netdata.rocks/default.html">Japan - Singapore (DigitalOcean.com)</a></li>' +
607                     '<li><a href="//bangalore.netdata.rocks/default.html">India - Bangalore (DigitalOcean.com)</a></li>';
608             a1 += '<li role="separator" class="divider"></li>' +
609                     '<li><a href="#">&nbsp;</a></li>' +
610                     '<li><a href="#">&nbsp;</a></li>'+
611                     '<li><a href="#">&nbsp;</a></li>'+
612                     '<li><a href="#">&nbsp;</a></li>'+
613                     '<li><a href="#">&nbsp;</a></li>'+
614                     '<li><a href="#">&nbsp;</a></li>'+
615                     '<li><a href="#">&nbsp;</a></li>'+
616                     '<li><a href="#">&nbsp;</a></li>';
617         }
618
619         el += '<li role="separator" class="divider"></li>';
620         a1 += '<li role="separator" class="divider"></li>';
621
622         el += '<li><a href="https://github.com/firehol/netdata/wiki/mynetdata-menu-item" style="color: #999;" target="_blank">What is this?</a></li>';
623         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>'
624
625         document.getElementById('mynetdata_servers').innerHTML = el;
626         document.getElementById('mynetdata_servers2').innerHTML = el;
627         document.getElementById('mynetdata_actions1').innerHTML = a1;
628
629         gotoServerInit();
630     };
631
632     var this_is_demo = null;
633     function isdemo() {
634         if(this_is_demo !== null) return this_is_demo;
635         this_is_demo = false;
636
637         try {
638             if(typeof document.location.hostname === 'string') {
639                 if(document.location.hostname.endsWith('.my-netdata.io') ||
640                         document.location.hostname.endsWith('.mynetdata.io') ||
641                         document.location.hostname.endsWith('.netdata.rocks') ||
642                         document.location.hostname.endsWith('.firehol.org') ||
643                         document.location.hostname.endsWith('.netdata.online'))
644                         this_is_demo = true;
645             }
646         }
647         catch(error) {
648             ;
649         }
650
651         return this_is_demo;
652     }
653
654     if(isdemo()) {
655         document.getElementById('masthead').style.display = 'block';
656     }
657
658     function netdataURL(url) {
659         if(typeof url === 'undefined')
660             url = document.location.toString();
661
662         if(url.indexOf('#') !== -1)
663             url = url.substring(0, url.indexOf('#'));
664
665         var hash = netdataHash();
666
667         // console.log('netdataURL: ' + url + hash);
668
669         return url + hash;
670     }
671
672     function netdataReload(url) {
673         var t = netdataURL(url);
674         // console.log('netdataReload: ' + t);
675         document.location = t;
676
677         // since we play with hash
678         // this is needed to reload the page
679         location.reload();
680     }
681
682     var gotoServerValidateRemaining = 0;
683     var gotoServerMiddleClick = false;
684     var gotoServerStop = false;
685     function gotoServerValidateUrl(id, guid, url) {
686         var penaldy = 0;
687         var error = 'failed';
688
689         if(document.location.toString().startsWith('http://') && url.toString().startsWith('https://'))
690                 // we penalize https only if the current url is http
691                 // to allow the user walk through all its servers.
692                 penaldy = 500;
693
694         else if(document.location.toString().startsWith('https://') && url.toString().startsWith('http://'))
695             error = 'can\'t check';
696         
697         var finalURL = netdataURL(url);
698
699         setTimeout(function() {
700             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>';
701
702             NETDATA.registry.hello(url, function(data) {
703                 if (data) {
704                     // console.log('OK ' + id + ' URL: ' + url);
705                     document.getElementById(guid + '-' + id + '-status').innerHTML = "OK";
706
707                     if(!gotoServerStop) {
708                         gotoServerStop = true;
709
710                         if(gotoServerMiddleClick) {
711                             window.open(finalURL, '_blank');
712                             gotoServerMiddleClick = false;
713                             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)';
714                         }
715                         else
716                             document.location = finalURL;
717                     }
718                 }
719                 else {
720                     document.getElementById(guid + '-' + id + '-status').innerHTML = error;
721                     gotoServerValidateRemaining--;
722                     if(gotoServerValidateRemaining <= 0) {
723                         gotoServerMiddleClick = false;
724                         document.getElementById('gotoServerResponse').innerHTML = '<b>Sorry! I cannot find any operational URL for this server</b>';
725                     }
726                 }
727             });
728         }, (id * 50) + penaldy);
729     }
730
731     function gotoServerModalHandler(guid) {
732         // console.log('goto server: ' + guid);
733
734         gotoServerStop = false;
735         var len = NETDATA.registry.machines[guid].alternate_urls.length;
736
737         document.getElementById('gotoServerResponse').innerHTML = '';
738         document.getElementById('gotoServerList').innerHTML = '';
739         document.getElementById('gotoServerName').innerHTML = NETDATA.registry.machines[guid].name;
740         $('#gotoServerModal').modal('show');
741
742         gotoServerValidateRemaining = len;
743         while(len--)
744             gotoServerValidateUrl(len, guid, NETDATA.registry.machines[guid].alternate_urls[len]);
745
746         return false;
747     }
748
749     function gotoServerInit() {
750         $(".registry_link").on('click', function(e) {
751             if(e.which === 2) {
752                 e.preventDefault();
753                 gotoServerMiddleClick = true;
754             }
755             else {
756                 gotoServerMiddleClick = false;
757             }
758
759             return true;
760         });
761     }
762
763     function switchRegistryModalHandler() {
764         document.getElementById('switchRegistryPersonGUID').value = NETDATA.registry.person_guid;
765         document.getElementById('switchRegistryURL').innerHTML = NETDATA.registry.server;
766         document.getElementById('switchRegistryResponse').innerHTML = '';
767         $('#switchRegistryModal').modal('show');
768     }
769
770     function notifyForSwitchRegistry() {
771         var n = document.getElementById('switchRegistryPersonGUID').value;
772
773         if(n !== '' && n.length === 36) {
774             NETDATA.registry.switch(n, function(result) {
775                 if(result !== null) {
776                     $('#switchRegistryModal').modal('hide');
777                     NETDATA.registry.init();
778                 }
779                 else {
780                     document.getElementById('switchRegistryResponse').innerHTML = "<b>Sorry! The registry rejected your request.</b>";
781                 }
782             });
783         }
784         else
785             document.getElementById('switchRegistryResponse').innerHTML = "<b>The ID you have entered is not a GUID.</b>";
786     }
787
788     var deleteRegistryUrl = null;
789     function deleteRegistryModalHandler(guid, name, url) {
790         deleteRegistryUrl = url;
791         document.getElementById('deleteRegistryServerName').innerHTML = name;
792         document.getElementById('deleteRegistryServerName2').innerHTML = name;
793         document.getElementById('deleteRegistryServerURL').innerHTML = url;
794         document.getElementById('deleteRegistryResponse').innerHTML = '';
795         $('#deleteRegistryModal').modal('show');
796     }
797
798     function notifyForDeleteRegistry() {
799         if(deleteRegistryUrl) {
800             NETDATA.registry.delete(deleteRegistryUrl, function(result) {
801                 if(result !== null) {
802                     deleteRegistryUrl = null;
803                     $('#deleteRegistryModal').modal('hide');
804                     NETDATA.registry.init();
805                 }
806                 else {
807                     document.getElementById('deleteRegistryResponse').innerHTML = "<b>Sorry! this command was rejected by the registry server.</b>";
808                 }
809             });
810         }
811     }
812
813     var options = {
814         sparklines_registry: {},
815         menus: {},
816         submenu_names: {},
817         data: null,
818         hostname: 'netdata_server', // will be overwritten by the netdata server
819         categories: new Array(),
820         categories_idx: {},
821         families: new Array(),
822         families_idx: {},
823
824         chartsPerRow: 0,
825         chartsMinWidth: 1450,
826         chartsHeight: 180,
827         sparklinesHeight: 60,
828     };
829
830     // generate a sparkline
831     // used in the documentation
832     function sparkline(chart, dimension, units) {
833         var key = chart + '.' + dimension;
834
835         if(typeof units === 'undefined')
836             units = '';
837
838         if(typeof options.sparklines_registry[key] === 'undefined')
839             options.sparklines_registry[key] = { count: 1 };
840         else
841             options.sparklines_registry[key].count++;
842
843         key = key + '.' + options.sparklines_registry[key].count;
844
845         var h = '<div data-netdata="' + chart + '" data-after="-120" data-width="25%" data-height="15px" data-chart-library="dygraph" data-dygraph-theme="sparkline" data-dimensions="' + dimension + '" data-show-value-of-' + dimension + '-at="' + key + '"></div> (<span id="' + key + '" style="display: inline-block; min-width: 50px; text-align: right;">X</span>' + units + ')';
846
847         return h;
848     }
849
850     function chartsPerRow(total) {
851         if(options.chartsPerRow === 0) {
852             width = Math.floor(total / options.chartsMinWidth);
853             if(width === 0) width = 1;
854             return width;
855         }
856         else return options.chartsPerRow;
857     }
858
859     function prioritySort(a, b) {
860         if(a.priority < b.priority) return -1;
861         if(a.priority > b.priority) return 1;
862         if(a.name < b.name) return -1;
863         return 1;
864     }
865
866     function sortObjectByPriority(object) {
867         var idx = {};
868         var sorted = new Array();
869
870         for(var i in object) {
871             if(typeof idx[i] === 'undefined') {
872                 idx[i] = object[i];
873                 sorted.push(i);
874             }
875         }
876
877         sorted.sort(function(a, b) {
878             if(idx[a].priority < idx[b].priority) return -1;
879             if(idx[a].priority > idx[b].priority) return 1;
880             if(a < b) return -1;
881             return 1;
882         });
883
884         return sorted;
885     }
886
887
888     // ----------------------------------------------------------------------------
889     // scroll to a section, without changing the browser history
890
891     function scrollToId(hash) {
892         if(hash && hash != '') {
893             var offset = $('#' + hash).offset();
894             if(typeof offset !== 'undefined')
895                 $('html, body').animate({ scrollTop: offset.top }, 0);
896         }
897
898         // we must return false to prevent the default action
899         return false;
900     }
901
902     // ----------------------------------------------------------------------------
903
904     var netdataDashboard = {
905         menu: {},
906         submenu: {},
907         context: {},
908
909         gaugeChart: function(title, width, dimensions, colors) {
910             if(typeof colors === 'undefined')
911                 colors = '';
912
913             if(typeof dimensions === 'undefined')
914                 dimensions = '';
915
916             return '<div data-netdata="CHART_UNIQUE_ID"'
917                                     + ' data-dimensions="' + dimensions + '"'
918                                     + ' data-chart-library="gauge"'
919                                     + ' data-gauge-adjust="width"'
920                                     + ' data-title="' + title + '"'
921                                     + ' data-width="' + width + '"'
922                                     + ' data-before="0"'
923                                     + ' data-after="-CHART_DURATION"'
924                                     + ' data-points="CHART_DURATION"'
925                                     + ' data-colors="' + colors + '"'
926                                     + ' role="application"></div>';
927         },
928
929         anyAttribute: function(obj, attr, key, def) {
930             if(typeof obj[key] !== 'undefined') {
931                 if(typeof obj[key][attr] !== 'undefined')
932                     return obj[key][attr];
933             }
934             return def;
935         },
936
937         menuTitle: function(chart) {
938             if(typeof chart.menu_pattern !== 'undefined') {
939                 return (netdataDashboard.anyAttribute(netdataDashboard.menu, 'title', chart.menu_pattern, chart.menu_pattern).toString()
940                         + '&nbsp;' + chart.type.slice(-(chart.type.length - chart.menu_pattern.length - 1)).toString()).replace(/_/g, ' ');
941             }
942
943             return (netdataDashboard.anyAttribute(netdataDashboard.menu, 'title', chart.menu, chart.menu)).toString().replace(/_/g, ' ');
944         },
945
946         menuIcon: function(chart) {
947             if(typeof chart.menu_pattern !== 'undefined')
948                 return netdataDashboard.anyAttribute(netdataDashboard.menu, 'icon', chart.menu_pattern, '<i class="fa fa-puzzle-piece" aria-hidden="true"></i>').toString();
949
950             return netdataDashboard.anyAttribute(netdataDashboard.menu, 'icon', chart.menu, '<i class="fa fa-puzzle-piece" aria-hidden="true"></i>');
951         },
952
953         menuInfo: function(menu) {
954             return netdataDashboard.anyAttribute(netdataDashboard.menu, 'info', menu, null);
955         },
956
957         menuHeight: function(menu, relative) {
958             return netdataDashboard.anyAttribute(netdataDashboard.menu, 'height', menu, 1.0) * relative;
959         },
960
961         submenuTitle: function(menu, submenu) {
962             var key = menu + '.' + submenu;
963             var title = netdataDashboard.anyAttribute(netdataDashboard.submenu, 'title', key, submenu).toString().replace(/_/g, ' ');;
964             if(title.length > 28) {
965                 var a = title.substring(0, 13);
966                 var b = title.substring(title.length - 12, title.length);
967                 return a + '...' + b;
968             }
969             return title;
970         },
971
972         submenuInfo: function(menu, submenu) {
973             var key = menu + '.' + submenu;
974             return netdataDashboard.anyAttribute(netdataDashboard.submenu, 'info', key, null);
975         },
976
977         submenuHeight: function(menu, submenu, relative) {
978             var key = menu + '.' + submenu;
979             return netdataDashboard.anyAttribute(netdataDashboard.submenu, 'height', key, 1.0) * relative;
980         },
981
982         contextInfo: function(id) {
983             if(typeof netdataDashboard.context[id] !== 'undefined' && typeof netdataDashboard.context[id].info !== 'undefined')
984                 return '<div class="chart-message netdata-chart-alignment" role="document">' + netdataDashboard.context[id].info + '</div>';
985             else
986                 return '';
987         },
988
989         contextHeight: function(id, def) {
990             if(typeof netdataDashboard.context[id] !== 'undefined' && typeof netdataDashboard.context[id].height !== 'undefined')
991                 return def * netdataDashboard.context[id].height;
992             else
993                 return def;
994         }
995     };
996
997     // ----------------------------------------------------------------------------
998
999     // enrich the data structure returned by netdata
1000     // to reflect our menu system and content
1001     function enrichChartData(chart) {
1002         var tmp = chart.type.split('_')[0];
1003
1004         switch(tmp) {
1005             case 'ap':
1006             case 'net':
1007             case 'disk':
1008                 chart.menu = tmp;
1009                 break;
1010
1011             case 'cgroup':
1012                 chart.menu = chart.type;
1013                 if(chart.id.match(/.*[\._\/-:]qemu[\._\/-:]*/) || chart.id.match(/.*[\._\/-:]kvm[\._\/-:]*/))
1014                     chart.menu_pattern = 'cgqemu';
1015                 else
1016                     chart.menu_pattern = 'cgroup';
1017                 break;
1018
1019             case 'apache':
1020             case 'exim':
1021             case 'memcached':
1022             case 'mysql':
1023             case 'named':
1024             case 'nginx':
1025             case 'nut':
1026             case 'phpfpm':
1027             case 'postfix':
1028             case 'redis':
1029             case 'retroshare':
1030             case 'ipfs':
1031             case 'smawebbox':
1032             case 'squid':
1033             case 'snmp':
1034             case 'tomcat':
1035                 chart.menu = chart.type;
1036                 chart.menu_pattern = tmp;
1037                 break;
1038
1039             case 'tc':
1040                 chart.menu = tmp;
1041
1042                 // find a name for this device from fireqos info
1043                 // we strip '_(in|out)' or '(in|out)_'
1044                 if(typeof options.submenu_names[chart.family] === 'undefined' || options.submenu_names[chart.family] === chart.family) {
1045                     var n = chart.name.split('.')[1];
1046                     if(n.endsWith('_in'))
1047                         options.submenu_names[chart.family] = n.slice(0, n.lastIndexOf('_in'));
1048                     else if(n.endsWith('_out'))
1049                         options.submenu_names[chart.family] = n.slice(0, n.lastIndexOf('_out'));
1050                     else if(n.startsWith('in_'))
1051                         options.submenu_names[chart.family] = n.slice(3, n.length);
1052                     else if(n.startsWith('out_'))
1053                         options.submenu_names[chart.family] = n.slice(4, n.length);
1054                 }
1055
1056                 // increase the priority of IFB devices
1057                 // to have inbound appear before outbound
1058                 if(chart.id.match(/.*-ifb$/))
1059                     chart.priority--;
1060
1061                 break;
1062
1063             default:
1064                 chart.menu = chart.type;
1065                 break;
1066         }
1067
1068         chart.submenu = chart.family;
1069     }
1070
1071     // ----------------------------------------------------------------------------
1072
1073     function headMain(charts, duration) {
1074         var head = '';
1075
1076         if(typeof charts['system.swap'] !== 'undefined')
1077             head += '<div style="margin-right: 10px;" data-netdata="system.swap"'
1078             + ' data-dimensions="free"'
1079             + ' data-append-options="percentage"'
1080             + ' data-chart-library="easypiechart"'
1081             + ' data-title="Free Swap"'
1082             + ' data-units="%"'
1083             + ' data-easypiechart-max-value="100"'
1084             + ' data-width="8%"'
1085             + ' data-before="0"'
1086             + ' data-after="-' + duration.toString() + '"'
1087             + ' data-points="' + duration.toString() + '"'
1088             + ' data-colors="#DD4400"'
1089             + ' role="application"></div>';
1090
1091         if(typeof charts['system.io'] !== 'undefined') {
1092             head += '<div style="margin-right: 10px;" data-netdata="system.io"'
1093             + ' data-dimensions="in"'
1094             + ' data-chart-library="easypiechart"'
1095             + ' data-title="Disk Read"'
1096             + ' data-width="10%"'
1097             + ' data-before="0"'
1098             + ' data-after="-' + duration.toString() + '"'
1099             + ' data-points="' + duration.toString() + '"'
1100             + ' role="application"></div>';
1101
1102             head += '<div style="margin-right: 10px;" data-netdata="system.io"'
1103             + ' data-dimensions="out"'
1104             + ' data-chart-library="easypiechart"'
1105             + ' data-title="Disk Write"'
1106             + ' data-width="10%"'
1107             + ' data-before="0"'
1108             + ' data-after="-' + duration.toString() + '"'
1109             + ' data-points="' + duration.toString() + '"'
1110             + ' role="application"></div>';
1111         }
1112
1113         if(typeof charts['system.cpu'] !== 'undefined')
1114             head += '<div data-netdata="system.cpu"'
1115             + ' data-chart-library="gauge"'
1116             + ' data-title="CPU"'
1117             + ' data-units="%"'
1118             + ' data-gauge-max-value="100"'
1119             + ' data-width="18%"'
1120             + ' data-after="-' + duration.toString() + '"'
1121             + ' data-points="' + duration.toString() + '"'
1122             + ' data-colors="' + NETDATA.colors[12] + '"'
1123             + ' role="application"></div>';
1124
1125         if(typeof charts['system.ipv4'] !== 'undefined') {
1126             head += '<div style="margin-right: 10px;" data-netdata="system.ipv4"'
1127             + ' data-dimensions="received"'
1128             + ' data-chart-library="easypiechart"'
1129             + ' data-title="IPv4 Inbound"'
1130             + ' data-width="10%"'
1131             + ' data-before="0"'
1132             + ' data-after="-' + duration.toString() + '"'
1133             + ' data-points="' + duration.toString() + '"'
1134             + ' role="application"></div>';
1135
1136             head += '<div style="margin-right: 10px;" data-netdata="system.ipv4"'
1137             + ' data-dimensions="sent"'
1138             + ' data-chart-library="easypiechart"'
1139             + ' data-title="IPv4 Outbound"'
1140             + ' data-width="10%"'
1141             + ' data-before="0"'
1142             + ' data-after="-' + duration.toString() + '"'
1143             + ' data-points="' + duration.toString() + '"'
1144             + ' role="application"></div>';
1145         }
1146         else if(typeof charts['system.ipv6'] !== 'undefined') {
1147             head += '<div style="margin-right: 10px;" data-netdata="system.ipv6"'
1148             + ' data-dimensions="received"'
1149             + ' data-chart-library="easypiechart"'
1150             + ' data-title="IPv6 Inbound"'
1151             + ' data-units="kbps"'
1152             + ' data-width="10%"'
1153             + ' data-before="0"'
1154             + ' data-after="-' + duration.toString() + '"'
1155             + ' data-points="' + duration.toString() + '"'
1156             + ' role="application"></div>';
1157
1158             head += '<div style="margin-right: 10px;" data-netdata="system.ipv6"'
1159             + ' data-dimensions="sent"'
1160             + ' data-chart-library="easypiechart"'
1161             + ' data-title="IPv6 Outbound"'
1162             + ' data-units="kbps"'
1163             + ' data-width="10%"'
1164             + ' data-before="0"'
1165             + ' data-after="-' + duration.toString() + '"'
1166             + ' data-points="' + duration.toString() + '"'
1167             + ' role="application"></div>';
1168         }
1169
1170         if(typeof charts['system.ram'] !== 'undefined')
1171             head += '<div style="margin-right: 10px;" data-netdata="system.ram"'
1172             + ' data-dimensions="cached|free"'
1173             + ' data-append-options="percentage"'
1174             + ' data-chart-library="easypiechart"'
1175             + ' data-title="Available RAM"'
1176             + ' data-units="%"'
1177             + ' data-easypiechart-max-value="100"'
1178             + ' data-width="8%"'
1179             + ' data-after="-' + duration.toString() + '"'
1180             + ' data-points="' + duration.toString() + '"'
1181             + ' data-colors="' + NETDATA.colors[7] + '"'
1182             + ' role="application"></div>';
1183
1184         return head;
1185     }
1186
1187     function generateHeadCharts(type, chart, duration) {
1188         var head = '';
1189         var hcharts = netdataDashboard.anyAttribute(netdataDashboard.context, type, chart.context, []);
1190         if(hcharts.length > 0) {
1191             var hi = 0, hlen = hcharts.length;
1192             while(hi < hlen) {
1193                 if(typeof hcharts[hi] === 'function')
1194                     head += hcharts[hi](chart.id).replace('CHART_DURATION', duration.toString()).replace('CHART_UNIQUE_ID', chart.id);
1195                 else
1196                     head += hcharts[hi].replace('CHART_DURATION', duration.toString()).replace('CHART_UNIQUE_ID', chart.id);
1197                 hi++;
1198             }
1199         }
1200         return head;
1201     }
1202
1203     function renderPage(menus, data) {
1204         var div = document.getElementById('charts_div');
1205         var pcent_width = Math.floor(100 / chartsPerRow($(div).width()));
1206
1207         // find the proper duration for per-second updates
1208         var duration = Math.round(($(div).width() * pcent_width / 100 * data.update_every / 3) / 60) * 60;
1209         var html = '';
1210         var sidebar = '<ul class="nav dashboard-sidenav" data-spy="affix" id="sidebar_ul">';
1211         var mainhead = headMain(data.charts, duration);
1212
1213         // sort the menus
1214         var main = sortObjectByPriority(menus);
1215         var i = 0, len = main.length;
1216         while(i < len) {
1217             var menu = main[i++];
1218
1219             // generate an entry at the main menu
1220
1221             var menuid = NETDATA.name2id('menu_' + menu);
1222             sidebar += '<li class=""><a href="#' + menuid + '" onClick="return scrollToId(\'' + menuid + '\');">' + menus[menu].icon + ' ' + menus[menu].title + '</a><ul class="nav">';
1223             html += '<div role="section"><div role="sectionhead"><h1 id="' + menuid + '" role="heading">' + menus[menu].title + '</h1></div><div role="document">';
1224
1225             if(menus[menu].info !== null)
1226                 html += menus[menu].info;
1227
1228             // console.log(' >> ' + menu + ' (' + menus[menu].priority + '): ' + menus[menu].title);
1229
1230             var shtml = '';
1231             var mhead = '<div class="netdata-chart-row">' + mainhead;
1232             mainhead = '';
1233
1234             // sort the submenus of this menu
1235             var sub = sortObjectByPriority(menus[menu].submenus);
1236             var si = 0, slen = sub.length;
1237             while(si < slen) {
1238                 var submenu = sub[si++];
1239
1240                 // generate an entry at the submenu
1241                 var submenuid = NETDATA.name2id('menu_' + menu + '_submenu_' + submenu);
1242                 sidebar += '<li class><a href="#' + submenuid + '" onClick="return scrollToId(\'' + submenuid + '\');">' + menus[menu].submenus[submenu].title + '</a></li>';
1243                 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>';
1244
1245                 if(menus[menu].submenus[submenu].info !== null)
1246                     shtml += '<div class="chart-message netdata-chart-alignment" role="document">' + menus[menu].submenus[submenu].info + '</div>';
1247
1248                 var head = '<div class="netdata-chart-row">';
1249                 var chtml = '';
1250
1251                 // console.log('    \------- ' + submenu + ' (' + menus[menu].submenus[submenu].priority + '): ' + menus[menu].submenus[submenu].title);
1252
1253                 // sort the charts in this submenu of this menu
1254                 menus[menu].submenus[submenu].charts.sort(prioritySort);
1255                 var ci = 0, clen = menus[menu].submenus[submenu].charts.length;
1256                 while(ci < clen) {
1257                     var chart = menus[menu].submenus[submenu].charts[ci++];
1258
1259                     // generate the submenu heading charts
1260                     mhead += generateHeadCharts('mainheads', chart, duration);
1261                     head += generateHeadCharts('heads', chart, duration);
1262
1263                     // generate the chart
1264                     chtml += netdataDashboard.contextInfo(chart.context) + '<div id="chart_' + NETDATA.name2id(chart.id) + '" data-netdata="' + chart.id + '"'
1265                         + ' data-width="' + pcent_width.toString() + '%"'
1266                         + ' data-height="' + netdataDashboard.contextHeight(chart.context, options.chartsHeight).toString() + 'px"'
1267                         + ' data-before="0"'
1268                         + ' data-after="-' + duration.toString() + '"'
1269                         + ' data-id="' + NETDATA.name2id(options.hostname + '/' + chart.id) + '"'
1270                         + ' data-colors="' + netdataDashboard.anyAttribute(netdataDashboard.context, 'colors', chart.context, '') + '"'
1271                         + ' role="application"></div>';
1272
1273                     // console.log('         \------- ' + chart.id + ' (' + chart.priority + '): ' + chart.context  + ' height: ' + menus[menu].submenus[submenu].height);
1274                 }
1275
1276                 head += '</div>';
1277                 shtml += head + chtml + '</div>';
1278             }
1279
1280             mhead += '</div>';
1281             sidebar += '</ul></li>';
1282             html += mhead + shtml + '</div></div><hr role="separator"/>';
1283         }
1284
1285         sidebar += '</ul>';
1286         div.innerHTML = html;
1287         document.getElementById('sidebar').innerHTML = sidebar;
1288         finalizePage();
1289     }
1290
1291     function renderChartsAndMenu(data) {
1292         var menus = options.menus;
1293         var charts = data.charts;
1294
1295         for(var c in charts) {
1296             enrichChartData(charts[c]);
1297
1298             // create the menu
1299             if(typeof menus[charts[c].menu] === 'undefined') {
1300                 menus[charts[c].menu] = {
1301                     priority: charts[c].priority,
1302                     submenus: {},
1303                     title: netdataDashboard.menuTitle(charts[c]),
1304                     icon: netdataDashboard.menuIcon(charts[c]),
1305                     info: netdataDashboard.menuInfo(charts[c].menu),
1306                     height: netdataDashboard.menuHeight(charts[c].menu, options.chartsHeight)
1307                 };
1308             }
1309
1310             if(charts[c].priority < menus[charts[c].menu].priority)
1311                 menus[charts[c].menu].priority = charts[c].priority;
1312
1313             // create the submenu
1314             if(typeof menus[charts[c].menu].submenus[charts[c].submenu] === 'undefined') {
1315                 menus[charts[c].menu].submenus[charts[c].submenu] = {
1316                     priority: charts[c].priority,
1317                     charts: new Array(),
1318                     title: null,
1319                     info: netdataDashboard.submenuInfo(charts[c].menu, charts[c].submenu),
1320                     height: netdataDashboard.submenuHeight(charts[c].menu, charts[c].submenu, menus[charts[c].menu].height)
1321                 };
1322             }
1323
1324             if(charts[c].priority < menus[charts[c].menu].submenus[charts[c].submenu].priority)
1325                 menus[charts[c].menu].submenus[charts[c].submenu].priority = charts[c].priority;
1326
1327             // index the chart in the menu/submenu
1328             menus[charts[c].menu].submenus[charts[c].submenu].charts.push(charts[c]);
1329         }
1330
1331         // propagate the descriptive subname given to QoS
1332         // to all the other submenus with the same name
1333         for(var m in menus) {
1334             for(var s in menus[m].submenus) {
1335                 // set the family using a name
1336                 if(typeof options.submenu_names[s] !== 'undefined') {
1337                     menus[m].submenus[s].title = s + ' (' + options.submenu_names[s] + ')';
1338                 }
1339                 else {
1340                     menus[m].submenus[s].title = netdataDashboard.submenuTitle(m, s);
1341                 }
1342             }
1343         }
1344
1345         renderPage(menus, data);
1346     }
1347
1348     // ----------------------------------------------------------------------------
1349
1350     function alarmsUpdateModal() {
1351         var active = '<h3>Raised Alarms</h3><table class="table">';
1352         var all = '<h3>All Running Alarms</h3><div class="panel-group" id="alarms_all_accordion" role="tablist" aria-multiselectable="true">';
1353         var log = '<h3>Alarm Log</h3><table class="table"><tr><th>When</th><th>Chart</th><th>Alarm</th><th>Status</th>';
1354         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.';
1355
1356         NETDATA.alarms.get('all', function(data) {
1357             options.alarm_families = new Array();
1358
1359             alarmsCallback(data);
1360
1361             if(data === null) {
1362                 document.getElementById('alarms_active').innerHTML =
1363                         document.getElementById('alarms_all').innerHTML =
1364                                 document.getElementById('alarms_log').innerHTML =
1365                                         'failed to load alarm data!';
1366                 return;
1367             }
1368
1369             function frequency_text(seconds, sfx) {
1370                 if(seconds === 0)
1371                     return 'now';
1372
1373                 var suffix = '';
1374                 if(seconds < 0) {
1375                     seconds = -seconds;
1376                     if(sfx) suffix = '&nbsp;ago';
1377                 }
1378
1379                 var hours = Math.floor(seconds / 3600);
1380                 seconds -= (hours * 3600);
1381
1382                 var minutes = Math.floor(seconds / 60);
1383                 seconds -= (minutes * 60);
1384
1385                 var txt = '';
1386                 
1387                 if(hours > 1) txt += hours.toString() + '&nbsp;hours';
1388                 else if(hours === 1) txt += hours.toString() + '&nbsp;hour';
1389
1390                 if(hours > 0 && minutes > 0 && seconds == 0)
1391                     txt += '&nbsp;and&nbsp;';
1392                 else if(hours > 0 && minutes > 0 && seconds > 0)
1393                     txt += ',&nbsp;';
1394
1395                 if(minutes > 1) txt += minutes.toString() + '&nbsp;minutes';
1396                 else if(minutes === 1) txt += minutes.toString() + '&nbsp;minute';
1397
1398                 if((minutes > 0 || minutes > 0) && seconds > 0)
1399                     txt += '&nbsp;and&nbsp;';
1400
1401                 if(seconds > 1) txt += seconds.toString() + '&nbsp;seconds';
1402                 else if(seconds === 1) txt += seconds.toString() + '&nbsp;second';
1403
1404                 return txt + suffix;
1405             }
1406
1407             function alarm_lookup_explain(alarm, chart) {
1408                 var dimensions = ' of all values ';
1409
1410                 if(chart.dimensions.length > 1)
1411                     dimensions = ' of the sum of all dimensions ';
1412
1413                 if(typeof alarm.lookup_dimensions !== 'undefined') {
1414                     var d = alarm.lookup_dimensions.replace('|', ',');
1415                     var x = d.split(',');
1416                     if(x.length > 1)
1417                         dimensions = 'of the sum of dimensions <code>' + alarm.lookup_dimensions + '</code> ';
1418                     else
1419                         dimensions = 'of all values of dimension <code>' + alarm.lookup_dimensions + '</code> ';
1420                 }
1421
1422                 return '<code>' + alarm.lookup_method + '</code> '
1423                     + dimensions + ', of chart <code>' + alarm.chart + '</code>'
1424                     + ', starting <code>' + frequency_text(alarm.lookup_after + alarm.lookup_before, true) + '</code> and up to <code>' + frequency_text(alarm.lookup_before, true) + '</code>'
1425                     + ((alarm.lookup_options)?(', with options <code>' + alarm.lookup_options.replace(' ', ',&nbsp;') + '</code>'):'')
1426                     + '.';
1427             }
1428
1429             function alarm_to_html(alarm, full) {
1430                 var chart = options.data.charts[alarm.chart];
1431
1432                 var html = '<tr><td class="text-center" style="vertical-align:middle" width="40%"><b>' + alarm.chart + '</b><br/>&nbsp;<br/><embed src="' + NETDATA.alarms.server + '/api/v1/badge.svg?chart=' + alarm.chart + '&alarm=' + alarm.name + '&refresh=auto" type="image/svg+xml" height="20"/><br/>&nbsp;<br/><span style="font-size: 18px">' + alarm.info + '</span><br/>&nbsp;<br/>role: <b>' + alarm.recipient + '</b><br/>&nbsp;<br/><b><i class="fa fa-line-chart" aria-hidden="true"></i></b><small>&nbsp;&nbsp;<a href="#" onClick="NETDATA.alarms.scrollToChart(\'' + alarm.chart + '\'); $(\'#alarmsModal\').modal(\'hide\'); return false;">jump to chart</a></small></td>'
1433                     + '<td><table class="table">'
1434                     + ((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>'):'')
1435                     + ((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>'):'');
1436
1437                 if(full === true) {
1438                         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>'):'')
1439                         + ((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>'):'')
1440                         + ((chart.green !== null)?('<tr><td width="10%" style="text-align:right">green&nbsp;threshold</td><td><code>' + chart.green + ' ' + chart.units + '</code></td></tr>'):'')
1441                         + ((chart.red !== null)?('<tr><td width="10%" style="text-align:right">red&nbsp;threshold</td><td><code>' + chart.red + ' ' + chart.units + '</code></td></tr>'):'');
1442                 }
1443
1444                 var delay = '';
1445                 if((alarm.delay_up_duration > 0 || alarm.delay_down_duration > 0) && alarm.delay_multiplier != 0 && alarm.delay_max_duration > 0) {
1446                     if(alarm.delay_up_duration == alarm.delay_down_duration) {
1447                         delay += '<small><br/>hysteresis ' + frequency_text(alarm.delay_up_duration);
1448                     }
1449                     else {
1450                         delay = '<small><br/>hysteresis ';
1451                         if(alarm.delay_up_duration > 0) {
1452                             delay += 'on&nbsp;escalation&nbsp;<code>' + frequency_text(alarm.delay_up_duration) + '</code>, ';
1453                         }
1454                         if(alarm.delay_down_duration > 0) {
1455                             delay += 'on&nbsp;recovery&nbsp;<code>' + frequency_text(alarm.delay_down_duration) + '</code>, ';
1456                         }
1457                     }
1458                     if(alarm.delay_multiplier != 1.0) {
1459                         delay += 'multiplied&nbsp;by&nbsp;<code>' + alarm.delay_multiplier.toString() + '</code>';
1460                         delay += ',&nbsp;up&nbsp;to&nbsp;<code>' + frequency_text(alarm.delay_max_duration) + '</code>';
1461                     }
1462                     delay += '</small>';
1463                 }
1464
1465                 html += '<tr><td width="10%" style="text-align:right">check&nbsp;every</td><td>' + frequency_text(alarm.update_every) + '</td></tr>'
1466                     + '<tr><td width="10%" style="text-align:right">execute</td><td><span style="font-family: monospace;">' + alarm.exec + '</span>' + delay + '</td></tr>'
1467                     + '<tr><td width="10%" style="text-align:right">source</td><td><span style="font-family: monospace;">' + alarm.source + '</span></td></tr>'
1468                     + '</table></td></tr>';
1469
1470                 return html;
1471             }
1472
1473             function alarm_family_show(id) {
1474                 var html = '<table class="table">';
1475                 var family = options.alarm_families[id];
1476                 var len = family.arr.length;
1477                 while(len--) {
1478                     var alarm = family.arr[len];
1479                     html += alarm_to_html(alarm, true);
1480                 }
1481                 html += '</table>';
1482
1483                 $('#alarm_all_' + id.toString()).html(html);
1484             }
1485
1486             // find the proper family of each alarm
1487             var now = new Date().getTime();
1488             var x;
1489             var count_active = 0;
1490             var count_all = 0;
1491             var families = {};
1492             var families_sort = new Array();
1493             for(x in data.alarms) {
1494                 var alarm = data.alarms[x];
1495                 var family = alarm.family;
1496
1497                 // find the chart
1498                 var chart = options.data.charts[alarm.chart];
1499                 if(typeof chart === 'undefined')
1500                     chart = options.data.charts_by_name[alarm.chart];
1501
1502                 // not found - this should never happen!
1503                 if(typeof chart === 'undefined') {
1504                     console.log('WARNING: alarm ' + x + ' is linked to chart ' + alarm.chart + ', which is not found in the list of chart got from the server.');
1505                     chart = { priority: 9999999 };
1506                 }
1507                 else if(typeof chart.menu !== 'undefined' && typeof chart.submenu !== 'undefined')
1508                     // the family based on the chart
1509                     family = chart.menu + ' - ' + chart.submenu;
1510
1511                 if(typeof families[family] === 'undefined') {
1512                     families[family] = {
1513                         name: family,
1514                         arr: new Array(),
1515                         priority: chart.priority
1516                     };
1517
1518                     families_sort.push(families[family]);
1519                 }
1520
1521                 if(chart.priority < families[family].priority)
1522                     families[family].priority = chart.priority;
1523
1524                 families[family].arr.unshift(alarm);
1525             }
1526
1527             // sort the families, like the dashboard menu does
1528             var families_sorted = families_sort.sort(function (a, b) {
1529                 if (a.priority > b.priority) return -1;
1530                 if (a.priority < b.priority) return 1;
1531                 return 0;
1532             });
1533
1534             var fc = 0;
1535             var len = families_sorted.length;
1536             while(len--) {
1537                 var family = families_sorted[len].name;
1538                 var active_family_added = false;
1539                 var expanded = 'true';
1540                 var collapsed = '';
1541                 var cin = 'in';
1542
1543                 if(fc !== 0) {
1544                     all += "</table></div></div></div>";
1545                     expanded = 'false';
1546                     collapsed = 'class="collapsed"'
1547                     cin = '';
1548                 }
1549
1550                 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() + '">';
1551
1552                 options.alarm_families[fc] = families[family];
1553
1554                 fc++;
1555
1556                 var arr = families[family].arr;
1557                 var c = arr.length;
1558                 while(c--) {
1559                     var alarm = arr[c];
1560                     if(alarm.status === 'WARNING' || alarm.status === 'CRITICAL') {
1561                         if(!active_family_added) {
1562                             active_family_added = true;
1563                             active += '<tr><th class="text-center" colspan="2"><h4>' + family + '</h4></th></tr>';
1564                         }
1565                         count_active++;
1566                         active += alarm_to_html(alarm, true);
1567                     }
1568
1569                     count_all++;
1570                 }
1571             }
1572             active += "</table>";
1573             if(families_sorted.length > 0) all += "</div></div></div>";
1574             all += "</div>";
1575
1576             if(!count_active)
1577                 active += "<h4>Everything is normal. No raised alarms.</h4>";
1578             else
1579                 active += footer;
1580
1581             if(!count_all)
1582                 all += "<h4>No alarms are running in this system.</h4>";
1583             else
1584                 all += footer;
1585
1586             document.getElementById('alarms_active').innerHTML = active;
1587             document.getElementById('alarms_all').innerHTML = all;
1588
1589             if(families_sorted.length > 0) alarm_family_show(0);
1590
1591             // register bootstrap events
1592             $('#alarms_all_accordion').on('show.bs.collapse', function (d) {
1593                 var target = $(d.target);
1594                 var id = $(target).data('alarm-id');
1595                 alarm_family_show(id);
1596             });
1597             $('#alarms_all_accordion').on('hidden.bs.collapse', function (d) {
1598                 var target = $(d.target);
1599                 var id = $(target).data('alarm-id');
1600                 $('#alarm_all_' + id.toString()).html('');
1601             });
1602
1603             NETDATA.alarms.get_log(0, function(data) {
1604                 if(data === null) {
1605                     document.getElementById('alarms_log').innerHTML =
1606                             'failed to load alarm data!';
1607                     return;
1608                 }
1609
1610                 var i = 0;
1611                 var len = data.length;
1612                 if(len > 50) len = 50;
1613                 while(i < len) {
1614                     var time = new Date(data[i].when * 1000);
1615                     log += '<tr><td>'
1616                             + time.toLocaleDateString() + ' '
1617                             + time.toLocaleTimeString() + '</td><td>'
1618                             + data[i].chart.toString() + '</td><td>'
1619                             + data[i].name.toString() + ' = ' + ((data[i].value !== null)?Math.floor(data[i].value):'NaN').toString() + ' ' + data[i].units.toString() + '</td><td>'
1620                             + data[i].status.toString() + '</td></tr>';
1621                     i++;
1622                 }
1623                 log += "</table>";
1624
1625                 if(i == 0)
1626                     log += "<h4>No alarms have been logged in this system.</h4>";
1627
1628                 document.getElementById('alarms_log').innerHTML = log;
1629             })
1630         });
1631     }
1632
1633     function alarmsCallback(data) {
1634         var count = 0;
1635         for(x in data.alarms) {
1636             var alarm = data.alarms[x];
1637             if(alarm.status === 'WARNING' || alarm.status === 'CRITICAL')
1638                 count++;
1639         }
1640
1641         if(count > 0)
1642             document.getElementById('alarms_count_badge').innerHTML = count.toString();
1643         else
1644             document.getElementById('alarms_count_badge').innerHTML = '';
1645     }
1646
1647     function initializeDynamicDashboard(netdata_url) {
1648         if(typeof netdata_url === 'undefined' || netdata_url === null)
1649             netdata_url = NETDATA.serverDefault;
1650
1651         // initialize clickable alarms
1652         NETDATA.alarms.chart_div_offset = 100;
1653         NETDATA.alarms.chart_div_id_prefix = 'chart_';
1654         NETDATA.alarms.chart_div_animation_duration = 0;
1655
1656         NETDATA.pause(function() {
1657             NETDATA.alarms.callback = alarmsCallback;
1658
1659             // download all the charts the server knows
1660             NETDATA.chartRegistry.downloadAll(netdata_url, function(data) {
1661                 if(data !== null) {
1662                     options.hostname = data.hostname;
1663                     options.data = data;
1664
1665                     // update the dashboard hostname
1666                     document.getElementById('hostname').innerHTML = options.hostname;
1667                     document.getElementById('hostname').href = NETDATA.serverDefault;
1668
1669                     // update the dashboard title
1670                     document.title = options.hostname + ' netdata dashboard';
1671
1672                     // close the splash screen
1673                     $("#loadOverlay").css("display","none");
1674
1675                     // create a chart_by_name index
1676                     data.charts_by_name = {};
1677                     var charts = data.charts;
1678                     var x;
1679                     for(x in charts) {
1680                         var chart = charts[x];
1681                         data.charts_by_name[chart.name] = chart;
1682                     }
1683
1684                     // render all charts
1685                     renderChartsAndMenu(data);
1686                 }
1687             });
1688         });
1689     }
1690
1691     // ----------------------------------------------------------------------------
1692
1693     function versionLog(msg) {
1694         document.getElementById('versionCheckLog').innerHTML = msg;
1695     }
1696
1697     function getNetdataVersion(callback) {
1698         versionLog('Downloading installed version info from netdata...');
1699
1700         $.ajax({
1701             url: 'version.txt',
1702             async: true,
1703             cache: false
1704         })
1705         .done(function(data) {
1706             data = data.replace(/(\r\n|\n|\r| |\t)/gm,"");
1707             if(data.length !== 40) {
1708                 versionLog('Received version string is invalid.');
1709                 callback(null);
1710             }
1711             else {
1712                 versionLog('Installed version of netdata is ' + data);
1713                 document.getElementById('netdataVersion').innerHTML = data;
1714                 callback(data);
1715             }
1716         })
1717         .fail(function() {
1718             versionLog('Failed to download installed version info from netdata!');
1719             callback(null);
1720         });
1721     }
1722
1723     function getGithubLatestCommit(callback) {
1724         versionLog('Downloading latest version info from github...');
1725
1726         $.ajax({
1727             url: 'https://api.github.com/repos/firehol/netdata/commits',
1728             async: true,
1729             cache: false
1730         })
1731         .done(function(data) {
1732             versionLog('Latest version info from github is ' + data[0].sha);
1733             callback(data[0].sha);
1734         })
1735         .fail(function() {
1736             versionLog('Failed to download installed version info from github!');
1737             callback(null);
1738         });
1739     }
1740
1741     function checkForUpdate(callback) {
1742         getNetdataVersion(function(sha1) {
1743             if(sha1 === null) callback(null, null);
1744
1745             getGithubLatestCommit(function(sha2) {
1746                 callback(sha1, sha2);
1747             });
1748         });
1749
1750         return null;
1751     }
1752
1753     function notifyForUpdate(force) {
1754         versionLog('<p>checking for updates...</p>');
1755
1756         var now = new Date().getTime();
1757
1758         if(typeof force === 'undefined' || force !== true) {
1759             var last = loadLocalStorage('last_update_check');
1760
1761             if(typeof last === 'string')
1762                 last = parseInt(last);
1763             else
1764                 last = 0;
1765
1766             if(now - last < 3600000 * 8) {
1767                 // no need to check it - too soon
1768                 return;
1769             }
1770         }
1771
1772         checkForUpdate(function(sha1, sha2) {
1773             var save = false;
1774
1775             if(sha1 === null) {
1776                 save = false;
1777                 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>');
1778             }
1779             else if(sha2 === null) {
1780                 save = false;
1781                 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>');
1782             }
1783             else if(sha1 === sha2) {
1784                 save = true;
1785                 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>');
1786             }
1787             else {
1788                 save = true;
1789                 var compare = 'https://github.com/firehol/netdata/compare/' + sha1.toString() + '...' + sha2.toString();
1790
1791                 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>');
1792
1793                 document.getElementById('update_badge').innerHTML = '!';
1794             }
1795
1796             if(save)
1797                 saveLocalStorage('last_update_check', now.toString());
1798         });
1799     }
1800
1801     // ----------------------------------------------------------------------------
1802
1803     function finalizePage() {
1804         // resize all charts - without starting the background thread
1805         // this has to be done while NETDATA is paused
1806         // if we ommit this, the affix menu will be wrong, since all
1807         // the Dom elements are initially zero-sized
1808         NETDATA.parseDom();
1809
1810         if(urlOptions.pan_and_zoom === true)
1811             NETDATA.globalPanAndZoom.setMaster(NETDATA.options.targets[0], urlOptions.after, urlOptions.before);
1812
1813         // ------------------------------------------------------------------------
1814         // https://github.com/viralpatel/jquery.shorten/blob/master/src/jquery.shorten.js
1815         $.fn.shorten = function(settings) {
1816             "use strict";
1817
1818             var config = {
1819                 showChars: 750,
1820                 minHideChars: 10,
1821                 ellipsesText: "...",
1822                 moreText: '<i class="fa fa-expand" aria-hidden="true"></i> show more information',
1823                 lessText: '<i class="fa fa-compress" aria-hidden="true"></i> show less information',
1824                 onLess: function() { NETDATA.onscroll(); },
1825                 onMore: function() { NETDATA.onscroll(); },
1826                 errMsg: null,
1827                 force: false
1828             };
1829
1830             if (settings) {
1831                 $.extend(config, settings);
1832             }
1833
1834             if ($(this).data('jquery.shorten') && !config.force) {
1835                 return false;
1836             }
1837             $(this).data('jquery.shorten', true);
1838
1839             $(document).off("click", '.morelink');
1840
1841             $(document).on({
1842                 click: function() {
1843
1844                     var $this = $(this);
1845                     if ($this.hasClass('less')) {
1846                         $this.removeClass('less');
1847                         $this.html(config.moreText);
1848                         $this.parent().prev().animate({'height':'0'+'%'}, 0, function () { $this.parent().prev().prev().show(); }).hide(0, function() {
1849                             config.onLess();
1850                         });
1851
1852                     } else {
1853                         $this.addClass('less');
1854                         $this.html(config.lessText);
1855                         $this.parent().prev().animate({'height':'100'+'%'}, 0, function () { $this.parent().prev().prev().hide(); }).show(0, function() {
1856                             config.onMore();
1857                         });
1858                     }
1859                     return false;
1860                 }
1861             }, '.morelink');
1862
1863             return this.each(function() {
1864                 var $this = $(this);
1865
1866                 var content = $this.html();
1867                 var contentlen = $this.text().length;
1868                 if (contentlen > config.showChars + config.minHideChars) {
1869                     var c = content.substr(0, config.showChars);
1870                     if (c.indexOf('<') >= 0) // If there's HTML don't want to cut it
1871                     {
1872                         var inTag = false; // I'm in a tag?
1873                         var bag = ''; // Put the characters to be shown here
1874                         var countChars = 0; // Current bag size
1875                         var openTags = []; // Stack for opened tags, so I can close them later
1876                         var tagName = null;
1877
1878                         for (var i = 0, r = 0; r <= config.showChars; i++) {
1879                             if (content[i] == '<' && !inTag) {
1880                                 inTag = true;
1881
1882                                 // This could be "tag" or "/tag"
1883                                 tagName = content.substring(i + 1, content.indexOf('>', i));
1884
1885                                 // If its a closing tag
1886                                 if (tagName[0] == '/') {
1887
1888
1889                                     if (tagName != '/' + openTags[0]) {
1890                                         config.errMsg = 'ERROR en HTML: the top of the stack should be the tag that closes';
1891                                     } else {
1892                                         openTags.shift(); // Pops the last tag from the open tag stack (the tag is closed in the retult HTML!)
1893                                     }
1894
1895                                 } else {
1896                                     // There are some nasty tags that don't have a close tag like <br/>
1897                                     if (tagName.toLowerCase() != 'br') {
1898                                         openTags.unshift(tagName); // Add to start the name of the tag that opens
1899                                     }
1900                                 }
1901                             }
1902                             if (inTag && content[i] == '>') {
1903                                 inTag = false;
1904                             }
1905
1906                             if (inTag) { bag += content.charAt(i); } // Add tag name chars to the result
1907                             else {
1908                                 r++;
1909                                 if (countChars <= config.showChars) {
1910                                     bag += content.charAt(i); // Fix to ie 7 not allowing you to reference string characters using the []
1911                                     countChars++;
1912                                 } else // Now I have the characters needed
1913                                 {
1914                                     if (openTags.length > 0) // I have unclosed tags
1915                                     {
1916                                         //console.log('They were open tags');
1917                                         //console.log(openTags);
1918                                         for (j = 0; j < openTags.length; j++) {
1919                                             //console.log('Cierro tag ' + openTags[j]);
1920                                             bag += '</' + openTags[j] + '>'; // Close all tags that were opened
1921
1922                                             // 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
1923                                         }
1924                                         break;
1925                                     }
1926                                 }
1927                             }
1928                         }
1929                         c = $('<div/>').html(bag + '<span class="ellip">' + config.ellipsesText + '</span>').html();
1930                     }else{
1931                         c+=config.ellipsesText;
1932                     }
1933
1934                     var html = '<div class="shortcontent">' + c +
1935                             '</div><div class="allcontent">' + content +
1936                             '</div><span><a href="javascript://nop/" class="morelink">' + config.moreText + '</a></span>';
1937
1938                     $this.html(html);
1939                     $this.find(".allcontent").hide(); // Hide all text
1940                     $('.shortcontent p:last', $this).css('margin-bottom', 0); //Remove bottom margin on last paragraph as it's likely shortened
1941                 }
1942             });
1943
1944         };
1945         $(".chart-message").shorten();
1946         // ------------------------------------------------------------------------
1947
1948         // callback for us to track PanAndZoom operations
1949         NETDATA.globalPanAndZoom.callback = netdataPanAndZoomCallback;
1950
1951         // let it run (update the charts)
1952         NETDATA.unpause();
1953
1954         // check if we have to jump to a specific section
1955         scrollToId(urlOptions.hash.replace('#',''));
1956
1957         if(urlOptions.chart !== null) {
1958             NETDATA.alarms.scrollToChart(urlOptions.chart);
1959             //urlOptions.hash = '#' + NETDATA.name2id('menu_' + charts[c].menu + '_submenu_' + charts[c].submenu);
1960             //urlOptions.hash = '#chart_' + NETDATA.name2id(urlOptions.chart);
1961             //console.log('hash = ' + urlOptions.hash);
1962         }
1963
1964         /* activate bootstrap sidebar (affix) */
1965         $('#sidebar').affix({
1966             offset: {
1967                 top: (isdemo())?150:0,
1968                 bottom: 0
1969             }
1970         });
1971
1972         /* fix scrolling of very long affix lists
1973            http://stackoverflow.com/questions/21691585/bootstrap-3-1-0-affix-too-long
1974          */
1975         $('#sidebar').on('affixed.bs.affix', function() {
1976             $(this).removeAttr('style');
1977         });
1978
1979         /* activate bootstrap scrollspy (needed for sidebar) */
1980         $(document.body).scrollspy({
1981             target: '#sidebar',
1982             offset: $(window).height() / 5 // controls the diff of the <hX> element to the top, to select it
1983         });
1984
1985         // change the URL based on the current position of the screen
1986         $('#sidebar').on('activate.bs.scrollspy', function (e) {
1987             // console.log(e);
1988             var el = $(e.target);
1989             //if(el.find('ul').size() == 0) {
1990             var hash = el.find('a').attr('href');
1991             if(typeof hash === 'string' && hash.substring(0, 1) === '#' && urlOptions.hash.startsWith(hash + '_submenu_') === false) {
1992                 urlOptions.hash = hash;
1993                 //console.log(urlOptions.hash);
1994                 netdataHashUpdate();
1995             }
1996             //else console.log('hash: not accepting ' + hash);
1997             //}
1998             //else console.log('el.find(): not found');
1999         });
2000
2001         document.getElementById('footer').style.display = 'block';
2002
2003         var update_options_modal = function() {
2004             // console.log('update_options_modal');
2005
2006             var sync_option = function(option) {
2007                 var self = $('#' + option);
2008
2009                 if(self.prop('checked') !== NETDATA.getOption(option)) {
2010                     // console.log('switching ' + option.toString());
2011                     self.bootstrapToggle(NETDATA.getOption(option)?'on':'off');
2012                 }
2013             }
2014
2015             var theme_sync_option = function(option) {
2016                 var self = $('#' + option);
2017
2018                 self.bootstrapToggle(netdataTheme === 'slate'?'on':'off');
2019             }
2020
2021             sync_option('eliminate_zero_dimensions');
2022             sync_option('destroy_on_hide');
2023             sync_option('parallel_refresher');
2024             sync_option('concurrent_refreshes');
2025             sync_option('sync_selection');
2026             sync_option('sync_pan_and_zoom');
2027             sync_option('stop_updates_when_focus_is_lost');
2028             sync_option('smooth_plot');
2029             sync_option('pan_and_zoom_data_padding');
2030             sync_option('show_help');
2031             theme_sync_option('netdata_theme_control');
2032
2033             if(NETDATA.getOption('parallel_refresher') === false) {
2034                 $('#concurrent_refreshes_row').hide();
2035             }
2036             else {
2037                 $('#concurrent_refreshes_row').show();
2038             }
2039         };
2040         NETDATA.setOption('setOptionCallback', update_options_modal);
2041
2042         // handle options changes
2043         $('#eliminate_zero_dimensions').change(function()       { NETDATA.setOption('eliminate_zero_dimensions', $(this).prop('checked')); });
2044         $('#destroy_on_hide').change(function()                 { NETDATA.setOption('destroy_on_hide', $(this).prop('checked')); });
2045         $('#parallel_refresher').change(function()              { NETDATA.setOption('parallel_refresher', $(this).prop('checked')); });
2046         $('#concurrent_refreshes').change(function()            { NETDATA.setOption('concurrent_refreshes', $(this).prop('checked')); });
2047         $('#sync_selection').change(function()                  { NETDATA.setOption('sync_selection', $(this).prop('checked')); });
2048         $('#sync_pan_and_zoom').change(function()               { NETDATA.setOption('sync_pan_and_zoom', $(this).prop('checked')); });
2049         $('#stop_updates_when_focus_is_lost').change(function() { NETDATA.setOption('stop_updates_when_focus_is_lost', $(this).prop('checked')); });
2050         $('#smooth_plot').change(function()                     { NETDATA.setOption('smooth_plot', $(this).prop('checked')); });
2051         $('#pan_and_zoom_data_padding').change(function()       { NETDATA.setOption('pan_and_zoom_data_padding', $(this).prop('checked')); });
2052         $('#show_help').change(function()                       {
2053             urlOptions.help = $(this).prop('checked');
2054             NETDATA.setOption('show_help', urlOptions.help);
2055             netdataReload();
2056         });
2057
2058         // this has to be the last
2059         // it reloads the page
2060         $('#netdata_theme_control').change(function() {
2061             urlOptions.theme = $(this).prop('checked')?'slate':'white';
2062             if(setTheme(urlOptions.theme))
2063                 netdataReload();
2064         });
2065
2066         $('#updateModal').on('shown.bs.modal', function() {
2067             notifyForUpdate(true);
2068         });
2069
2070         $('#alarmsModal').on('shown.bs.modal', function() {
2071             NETDATA.pause(alarmsUpdateModal);
2072         });
2073
2074         $('#alarmsModal').on('hidden.bs.modal', function() {
2075             NETDATA.unpause();
2076             document.getElementById('alarms_active').innerHTML =
2077                     document.getElementById('alarms_all').innerHTML =
2078                     document.getElementById('alarms_log').innerHTML =
2079                             'loading...';
2080         });
2081
2082         $('#deleteRegistryModal').on('hidden.bs.modal', function() {
2083             deleteRegistryGuid = null;
2084         });
2085
2086         if(isdemo()) {
2087             if(urlOptions.nowelcome !== true) {
2088                 setTimeout(function() {
2089                     $('#welcomeModal').modal();
2090                 }, 1000);
2091             }
2092
2093             // google analytics when this is used for the home page of the demo sites
2094             // this does not run on user's installations
2095             setTimeout(function() {
2096                 (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
2097                 (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
2098                 m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
2099                 })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
2100
2101                 ga('create', 'UA-64295674-3', 'auto');
2102                 ga('send', 'pageview');
2103             }, 2000);
2104         }
2105         else notifyForUpdate();
2106
2107         if(urlOptions.show_alarms === true)
2108             setTimeout(function() { $('#alarmsModal').modal('show'); }, 1000);
2109     }
2110
2111     function resetDashboardOptions() {
2112         var help = NETDATA.options.current.show_help;
2113
2114         NETDATA.resetOptions();
2115         if(setTheme('slate'))
2116             netdataReload();
2117
2118         if(help !== NETDATA.options.current.show_help)
2119             netdataReload();
2120     }
2121
2122     // callback to add the dashboard info to the
2123     // parallel javascript downloader in netdata
2124     var netdataPrepCallback = function() {
2125         NETDATA.requiredJs.push({
2126             url: NETDATA.serverDefault + 'dashboard_info.js',
2127             isAlreadyLoaded: function() { return false; }
2128         })
2129     }
2130
2131     // our entry point
2132     var netdataCallback = initializeDynamicDashboard;
2133
2134 </script>
2135
2136 <body data-spy="scroll" data-target="#sidebar">
2137     <div id="loadOverlay" class="loadOverlay" style="background-color: #888; color: #888;">
2138         netdata<br/><div style="font-size: 3vh;">Real-time performance monitoring, done right!</div>
2139     </div>
2140     <script type="text/javascript">
2141         // change the loadOverlay colors ASAP to match the theme
2142         document.getElementById('loadOverlay').style = (urlOptions.theme === 'slate')?"background-color:#272b30; color: #373b40;":"background-color:#fff; color: #ddd;";
2143     </script>
2144     <nav class="navbar navbar-default navbar-fixed-top" role="banner">
2145         <div class="container">
2146             <nav id="mynetdata_nav" class="collapse navbar-collapse navbar-left hidden-sm hidden-xs" role="navigation" style="padding-right: 20px;">
2147                 <ul class="nav navbar-nav">
2148                     <li class="dropdown">
2149                         <a href="#" class="dropdown-toggle" data-toggle="dropdown" id="current_view">my-netdata <strong class="caret"></strong></a>
2150                         <ul class="dropdown-menu scrollable-menu inpagemenu multi-column columns-2" role="menu">
2151                             <div class="row">
2152                                 <div class="col-sm-6" style="width: 85%; padding-right: 0;">
2153                                     <ul id="mynetdata_servers" class="multi-column-dropdown">
2154                                         <li><a href="#" onclick="return false;" style="color: #999;">loading...</a></li>
2155                                     </ul>
2156                                 </div>
2157                                 <div class="col-sm-3 hidden-xs" style="width: 15%; padding-left: 0;">
2158                                     <ul id="mynetdata_actions1" class="multi-column-dropdown">
2159                                     <li style="color: #999;">&nbsp;</li>
2160                                     </ul>
2161                                 </div>
2162                             </div>
2163                         </ul>
2164                     </li>
2165                 </ul>
2166             </nav>
2167             <div class="navbar-header">
2168                 <button class="navbar-toggle" type="button" data-toggle="collapse" data-target=".navbar-collapse">
2169                     <span class="sr-only">Toggle navigation</span>
2170                     <span class="icon-bar"></span>
2171                     <span class="icon-bar"></span>
2172                     <span class="icon-bar"></span>
2173                 </button>
2174                 <a href="/" class="navbar-brand" id="hostname" title="reload the dashboard">netdata</a>
2175             </div>
2176             <nav class="collapse navbar-collapse navbar-right" role="navigation">
2177                 <ul class="nav navbar-nav">
2178                     <li><a href="#" class="btn" data-toggle="modal" data-target="#alarmsModal" title="alarms"><i class="fa fa-bell"></i></span>&nbsp;<span class="hidden-sm">Alarms&nbsp;</span><span id="alarms_count_badge" class="badge"></a></li>
2179                     <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>
2180                     <li><a href="https://github.com/firehol/netdata/wiki" class="btn" target="_blank" title="netdata community"><i class="fa fa-github"></i>&nbsp;<span class="hidden-sm hidden-md">Community</span></a></li>
2181                     <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 id="update_badge" class="badge"></span>&nbsp;<span class="hidden-sm hidden-md">Update</span></a></li>
2182                     <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>
2183                     <!--
2184                     <li class="dropdown hidden-md hidden-lg hidden-xs">
2185                         <a href="#" class="dropdown-toggle" data-toggle="dropdown" id="current_view">Menu <strong class="caret"></strong></a>
2186                         <ul class="dropdown-menu scrollable-menu inpagemenu" role="menu">
2187                             <li><a href="#" class="btn" data-toggle="modal" data-target="#alarmsModal"><i class="fa fa-bell"></i> alarms</a></li>
2188                             <li><a href="#" class="btn" data-toggle="modal" data-target="#optionsModal"><i class="fa fa-sliders"></i> settings</a></li>
2189                             <li><a href="https://github.com/firehol/netdata/wiki" class="btn" target="_blank"><i class="fa fa-github"></i> community</a></li>
2190                             <li><a href="#" class="btn" data-toggle="modal" data-target="#helpModal"><i class="fa fa-question-circle"></i> help</a></li>
2191                         </ul>
2192                     </li>
2193                     -->
2194                     <li class="dropdown hidden-sm hidden-md hidden-lg">
2195                         <a href="#" class="dropdown-toggle" data-toggle="dropdown" id="current_view">my-netdata <strong class="caret"></strong></a>
2196                         <ul id="mynetdata_servers2" class="dropdown-menu scrollable-menu inpagemenu" role="menu">
2197                             <li><a href="#" onclick="return false;" style="color: #999;">loading...</a></li>
2198                         </ul>
2199                     </li>
2200                 </ul>
2201             </nav>
2202     </nav>
2203         </div>
2204     </nav>
2205
2206     <div id="masthead" style="display: none;">
2207         <div class="container">
2208             <div class="row">
2209                 <div class="col-md-7">
2210                     <h1>Netdata
2211                         <p class="lead">Real-time performance monitoring, in the greatest possible detail</p>
2212                     </h1>
2213                 </div>
2214                 <div class="col-md-5">
2215                     <div class="well well-lg">
2216                         <div class="row">
2217                         <div class="col-md-6">
2218                             <b>Drag</b> charts to pan.
2219                             <b>Shift + wheel</b> on them, to zoom in and out.
2220                             <b>Double-click</b> on them, to reset.
2221                             <b>Hover</b> on them too!
2222                             </div>
2223                         <div class="col-md-6">
2224                             <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>
2225                             </div>
2226                         </div>
2227                     </div>
2228                 </div>
2229             </div>
2230         </div>
2231     </div>
2232
2233     <div class="container">
2234         <div class="row">
2235             <div class="charts-body" role="main">
2236                 <div id="charts_div"></div>
2237             </div>
2238             <div class="sidebar-body hidden-xs hidden-sm" role="complementary">
2239                 <nav class="dashboard-sidebar hidden-print hidden-xs hidden-sm" id="sidebar" role="menu"></nav>
2240             </div>
2241         </div>
2242     </div>
2243
2244     <div id="footer" class="container" style="display: none;">
2245         <div class="row">
2246             <div class="col-md-10" role="main">
2247                 <div class="p">
2248                     <big><a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata</a></big><br/>
2249                     <i class="fa fa-copyright"></i> Copyright 2016, Costa Tsaousis.<br/>
2250                     Released under <a href="http://www.gnu.org/licenses/gpl-3.0.en.html" target="_blank">GPL v3 or later</a>.<br/>
2251                 </div>
2252                 <div class="p">
2253                     <small>
2254                         <a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata</a> re-distributes these software tools:
2255
2256                         <i class="fa fa-circle"></i> The excellent <a href="http://dygraphs.com/" target="_blank">Dygraphs.com</a> web chart library,
2257                         <i class="fa fa-copyright"></i> Copyright 2009, Dan Vanderkam, <a href="http://dygraphs.com/legal.html" target="_blank">MIT License</a>
2258
2259                         <i class="fa fa-circle"></i> <a href="http://omnipotent.net/jquery.sparkline/" target="_blank">jQuery Sparklines</a> web chart library,
2260                         <i class="fa fa-copyright"></i> Copyright 2009-2012, Splunk Inc., <a href="http://opensource.org/licenses/BSD-3-Clause" target="_blank">New BSD License</a>
2261
2262                         <i class="fa fa-circle"></i> <a href="http://benpickles.github.io/peity/" target="_blank">Peity</a> web chart library,
2263                         <i class="fa fa-copyright"></i> Copyright 2009-2015, Ben Pickles, <a href="https://github.com/benpickles/peity/blob/master/MIT-LICENCE" target="_blank">MIT License</a>
2264
2265                         <i class="fa fa-circle"></i> <a href="https://rendro.github.io/easy-pie-chart/" target="_blank">Easy Pie Chart</a> web chart library,
2266                         <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>
2267
2268                         <i class="fa fa-circle"></i> <a href="http://bernii.github.io/gauge.js/" target="_blank">Gauge.js</a> web chart library,
2269                         <i class="fa fa-copyright"></i> Copyright, Bernard Kobos, <a href="http://bernii.github.io/gauge.js/" target="_blank">MIT License</a>
2270
2271                         <i class="fa fa-circle"></i> <a href="https://jquery.org/" target="_blank">jQuery</a>,
2272                         <i class="fa fa-copyright"></i> Copyright 2015, jQuery Foundation, <a href="https://jquery.org/license/" target="_blank">MIT License</a>
2273
2274                         <i class="fa fa-circle"></i> <a href="http://getbootstrap.com/getting-started/" target="_blank">Bootstrap</a>,
2275                         <i class="fa fa-copyright"></i> Copyright 2015, Twitter, <a href="http://getbootstrap.com/getting-started/#license-faqs" target="_blank">MIT License</a>
2276
2277                         <i class="fa fa-circle"></i> <a href="http://www.bootstraptoggle.com/" target="_blank">Bootstrap Toggle</a>,
2278                         <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>
2279
2280                         <i class="fa fa-circle"></i> <a href="https://jamesflorentino.github.io/nanoScrollerJS/" target="_blank">NanoScroller</a>,
2281                         <i class="fa fa-copyright"></i> Copyright 2012, James Florentino, <a href="https://github.com/jamesflorentino/nanoScrollerJS/blob/master/LICENSE" target="_blank">MIT License</a>
2282
2283                         <i class="fa fa-circle"></i> <a href="https://github.com/marcj/css-element-queries" target="_blank">CSS Element Queries</a>,
2284                         <i class="fa fa-copyright"></i> Copyright Marc J. Schmidt, <a href="https://github.com/marcj/css-element-queries/blob/master/LICENSE" target="_blank">MIT License</a>
2285
2286                         <i class="fa fa-circle"></i> <a href="https://fortawesome.github.io/Font-Awesome/" target="_blank">FontAwesome</a>,
2287                         <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>
2288
2289                         <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.
2290
2291                         <i class="fa fa-circle"></i> <a href="http://morrisjs.github.io/morris.js/" target="_blank">morris.js</a>,
2292                         <i class="fa fa-copyright"></i> Copyright 2013, Olly Smith, <a href="http://morrisjs.github.io/morris.js/" target="_blank">Simplified BSD License</a>
2293
2294                         <i class="fa fa-circle"></i> <a href="http://raphaeljs.com/" target="_blank">Raphaël</a>,
2295                         <i class="fa fa-copyright"></i> Copyright 2008, Dmitry Baranovskiy, <a href="http://raphaeljs.com/license.html" target="_blank">MIT License</a>
2296
2297                         <i class="fa fa-circle"></i> <a href="http://C3js.org/" target="_blank">C3</a>,
2298                         <i class="fa fa-copyright"></i> Copyright 2013, Masayuki Tanaka, <a href="https://github.com/masayuki0812/c3/blob/master/LICENSE" target="_blank">MIT License</a>
2299
2300                         <i class="fa fa-circle"></i> <a href="http://D3js.org/" target="_blank">D3</a>,
2301                         <i class="fa fa-copyright"></i> Copyright 2015, Mike Bostock, <a href="http://opensource.org/licenses/BSD-3-Clause" target="_blank">BSD License</a>
2302
2303                     </small>
2304                 </div>
2305             </div>
2306         </div>
2307     </div>
2308
2309     <div class="modal fade" id="welcomeModal" tabindex="-1" role="dialog" aria-labelledby="welcomeModalLabel">
2310         <div class="modal-dialog modal-lg" role="document">
2311             <div class="modal-content">
2312                 <div class="modal-header">
2313                     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
2314                     <h4 class="modal-title" id="welcomeModalLabel">Welcome!</h4>
2315                 </div>
2316                 <div class="modal-body">
2317                         <div class="p">
2318                         <b><a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata</a></b> is the fastest way to visualize metrics. It is a resource efficient, highly optimized system for collecting and visualizing any type of real-time time series data, from CPU usage, disk activity, SQL queries, API calls, web site visitors, etc.
2319                         </div>
2320                         <div class="p">
2321                         <b><a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata</a></b> tries to visualize the truth of <b>now</b>, in its <b>greatest detail</b>, so that you can get insights of what is happening now and what just happened, on your systems and applications.
2322                         </div>
2323                         <div class="p">
2324                         To make a chart in <b><a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata</a></b>, you just need a <b>number</b>. Just a number you can read somehow. <b><a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata</a></b> will turn this number to a real time, interactive, web chart. For collecting these numbers, it supports <a href="https://github.com/firehol/netdata/wiki/External-Plugins" target="_blank">external plugins</a>, even <a href="https://github.com/firehol/netdata/wiki/General-Info---charts.d" target="_blank">shell</a> or <a href="https://github.com/firehol/netdata/wiki/General-Info---charts.d" target="_blank">node.js</a> plugins. Any computer program, in any language, that can print a few lines of text on its standard output, can be a netdata data collector.
2325                         </div>
2326                         <div class="p">
2327                         <b><a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata</a></b> can embed charts everywhere, like this one <div data-netdata="system.cpu" data-dimensions="system" data-after="-120" data-width="25%" data-height="15px" data-chart-library="dygraph" data-dygraph-theme="sparkline" data-show-value-of-system-at="system.cpu.system.modal.1"></div> (my CPU system usage which is <span id="system.cpu.system.modal.1" style="display: inline-block; width: 40px; text-align: right;"></span>%),
2328                         or this one <div data-netdata="ipv4.tcppackets" data-dimensions="received" data-after="-120" data-width="25%" data-height="15px" data-chart-library="dygraph" data-dygraph-theme="sparkline" data-show-value-of-received-at="ipv4.tcppackets.received.modal.1"></div> (my IPv4 received TCP packets, which are <span id="ipv4.tcppackets.received.modal.1" style="display: inline-block; width: 60px; text-align: right;"></span>/second).
2329                         </div>
2330                         <div class="p">
2331                         You can have <b><a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata</a></b> charts on your site too. Just give it a <code>div</code> and a real time chart, zoomable and draggable will appear (try it even on these tiny ones - <b>drag</b> them to pan horizontally, <b>shift + drag</b> to zoom in, on <b>chrome shift + mouse wheel</b> to zoom in/out, <b>double click</b> on them to reset them - don't be afraid of <b><a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata</a></b> performance - <a href="https://github.com/firehol/netdata/wiki/Performance" target="_blank">a raspberry pi 2 can sustain 300 charts updates per second</a>!).
2332                         </div>
2333                         <div class="p">
2334                         For more information please refer to the <b><a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata wiki</a></b>.
2335                         </div>
2336                 </div>
2337                 <div class="modal-footer">
2338                     <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
2339                 </div>
2340             </div>
2341         </div>
2342     </div>
2343
2344     <div class="modal fade" id="helpModal" tabindex="-1" role="dialog" aria-labelledby="helpModalLabel">
2345         <div class="modal-dialog modal-lg" role="document">
2346             <div class="modal-content">
2347                 <div class="modal-header">
2348                     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
2349                     <h4 class="modal-title" id="helpModalLabel">Dashboard Help</h4>
2350                 </div>
2351                 <div class="modal-body">
2352
2353                     <h4>Dygraphs (line, area and stacked area charts)</h4>
2354
2355                     <!-- Nav tabs -->
2356                     <ul class="nav nav-tabs" role="tablist">
2357                         <li role="presentation" class="active"><a href="#help_mouse" aria-controls="help_mouse" role="tab" data-toggle="tab">Mouse Interface</a></li>
2358                         <li role="presentation"><a href="#help_touch" aria-controls="help_touch" role="tab" data-toggle="tab">Touch Interface</a></li>
2359                     </ul>
2360
2361                     <!-- Tab panes -->
2362                     <div class="tab-content">
2363                         <div role="tabpanel" class="tab-pane active" id="help_mouse">
2364                             <div class="p">
2365                                 <h4>Mouse Over / Hover</h4>
2366                                 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).
2367                                 <br/>
2368                                 All the other visible charts will also show and highlight their values for the same timestamp.
2369                             </div>
2370                             <hr/>
2371                             <div class="p">
2372                                 <h4>Drag Chart Contents</h4>
2373                                 Drag the contents of a chart to pan it horizontally.
2374                                 <br/>
2375                                 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).
2376                                 <br/>
2377                                 Once a chart is panned, auto refreshing stops for all charts. To enable it again, <b>double click</b> a panned chart.
2378                             </div>
2379                             <hr/>
2380                             <div class="p">
2381                                 <h4>Double Click</h4>
2382                                 Double Click a chart to reset all the charts to their default auto-refreshing state.
2383                             </div>
2384                             <hr/>
2385                             <div class="p">
2386                                 <h4>SHIFT + Drag</h4>
2387                                 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:
2388                                 <ul>
2389                                     <li>The already loaded chart contents are zoomed (low resolution)</li>
2390                                     <li>New data are transferred from the netdata server, to refresh the chart with possibly more detail.</li>
2391                                 </ul>
2392                                 Once a chart is zoomed, auto refreshing stops for all charts. To enable it again, <b>double click</b> a zoomed chart.
2393                             </div>
2394                             <hr/>
2395                             <div class="p">
2396                                 <h4>SHIFT + Mouse Wheel <small>(does not work on firefox and IE/Edge)</small></h4>
2397                                 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.
2398                                 <br/>
2399                                 Once a chart is zoomed, auto refreshing stops for all charts. To enable it again, <b>double click</b> a zoomed chart.
2400                             </div>
2401                             <hr/>
2402                             <div class="p">
2403                                 <h4>Legend Operations</h4>
2404                                 Click on the label or value of a dimension, will select / un-select this dimension.
2405                                 <br/>
2406                                 You can press any of the SHIFT or CONTROL keys and then click on legend labels or values, to select / un-select multiple dimensions.
2407                             </div>
2408                         </div>
2409                         <div role="tabpanel" class="tab-pane" id="help_touch">
2410                             <div class="p">
2411                                 <h4>Single Tap</h4>
2412                                 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).
2413                                 <br/>
2414                                 All the other visible charts will also show and highlight their values for the same timestamp.
2415                             </div>
2416                             <hr/>
2417                             <div class="p">
2418                                 <h4>Drag Chart Contents</h4>
2419                                 Touch and Drag the contents of a chart to pan it horizontally.
2420                                 <br/>
2421                                 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).
2422                                 <br/>
2423                                 Once a chart is panned, auto refreshing stops for all charts. To enable it again, <b>double tap</b> a panned chart.
2424                             </div>
2425                             <hr/>
2426                             <div class="p">
2427                                 <h4>Double Tap</h4>
2428                                 Double tap a chart to reset all the charts to their default auto-refreshing state.
2429                             </div>
2430                             <hr/>
2431                             <div class="p">
2432                                 <h4>Zoom <small>(does not work on firefox and IE/Edge)</small></h4>
2433                                 With two fingers, zoom in or out.
2434                                 <br/>
2435                                 Once a chart is zoomed, auto refreshing stops for all charts. To enable it again, <b>double click</b> a zoomed chart.
2436                             </div>
2437                             <hr/>
2438                             <div class="p">
2439                                 <h4>Legend Operations</h4>
2440                                 Tap on the label or value of a dimension, will select / un-select this dimension.
2441                             </div>
2442                         </div>
2443                     </div>
2444                 </div>
2445                 <div class="modal-footer">
2446                     <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
2447                 </div>
2448             </div>
2449         </div>
2450     </div>
2451
2452     <div class="modal fade" id="alarmsModal" tabindex="-1" role="dialog" aria-labelledby="alarmsModalLabel">
2453         <div class="modal-dialog modal-lg" role="document">
2454             <div class="modal-content">
2455                 <div class="modal-header">
2456                     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
2457                     <h4 class="modal-title" id="alarmsModalLabel">netdata alarms</h4>
2458                 </div>
2459                 <div class="modal-body">
2460                     <!-- Nav tabs -->
2461                     <ul class="nav nav-tabs" role="tablist">
2462                         <li role="presentation" class="active"><a href="#alarms_active" aria-controls="alarms_active" role="tab" data-toggle="tab">Active</a></li>
2463                         <li role="presentation"><a href="#alarms_all" aria-controls="alarms_all" role="tab" data-toggle="tab">All</a></li>
2464                         <li role="presentation"><a href="#alarms_log" aria-controls="alarms_log" role="tab" data-toggle="tab">Log</a></li>
2465                     </ul>
2466
2467                     <!-- Tab panes -->
2468                     <div class="tab-content">
2469                         <div role="tabpanel" class="tab-pane active" id="alarms_active">
2470                             loading...
2471                         </div>
2472                         <div role="tabpanel" class="tab-pane" id="alarms_all">
2473                             loading...
2474                         </div>
2475                         <div role="tabpanel" class="tab-pane" id="alarms_log">
2476                             loading...
2477                         </div>
2478                     </div>
2479                 </div>
2480                 <div class="modal-footer">
2481                     <!-- <a href="#" onclick="alarmsUpdateModal(); return false;" type="button" class="btn btn-default">Update</a> -->
2482                     <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
2483                 </div>
2484             </div>
2485         </div>
2486     </div>
2487
2488     <div class="modal fade" id="optionsModal" tabindex="-1" role="dialog" aria-labelledby="optionsModalLabel">
2489         <div class="modal-dialog modal-lg" role="document">
2490             <div class="modal-content">
2491                 <div class="modal-header">
2492                     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
2493                     <h4 class="modal-title" id="optionsModalLabel">netdata dashboard options</h4>
2494                 </div>
2495                 <div class="modal-body">
2496                     <center>
2497                         <small style="color: #BBBBBB;">These are browser settings. Each viewer has its own. They do not affect the operation of your netdata server.
2498                         <br/>
2499                         Settings take effect immediately and are saved permanently to browser local storage (except the refresh on focus / always option).
2500                         <br/>
2501                         To reset all options (including charts sizes) to their defaults, click <a href="#" onclick="resetDashboardOptions(); return false;">here</a>.</small>
2502                     </center>
2503                     <div style="padding: 10px;"></div>
2504
2505                     <!-- Nav tabs -->
2506                     <ul class="nav nav-tabs" role="tablist">
2507                         <li role="presentation" class="active"><a href="#settings_performance" aria-controls="settings_performance" role="tab" data-toggle="tab">Performance</a></li>
2508                         <li role="presentation"><a href="#settings_sync" aria-controls="settings_sync" role="tab" data-toggle="tab">Synchronization</a></li>
2509                         <li role="presentation"><a href="#settings_visual" aria-controls="settings_visual" role="tab" data-toggle="tab">Visual</a></li>
2510                     </ul>
2511
2512                     <!-- Tab panes -->
2513                     <div class="tab-content">
2514                         <div role="tabpanel" class="tab-pane active" id="settings_performance">
2515                             <form id="optionsForm1" method="get" class="form-horizontal">
2516                                 <div class="form-group">
2517                                     <table>
2518                                     <tr class="option-row">
2519                                         <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>
2520                                         <td class="option-info"><strong>When to refresh the charts?</strong><br/>
2521                                             <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>
2522                                         </td>
2523                                         </tr>
2524                                     <tr class="option-row">
2525                                         <td class="option-control">
2526                                         <input id="eliminate_zero_dimensions" type="checkbox" checked data-toggle="toggle" data-on="Non Zero" data-off="All" data-width="110px">
2527                                         </td>
2528                                         <td class="option-info"><strong>Which dimensions to show?</strong><br/>
2529                                             <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>
2530                                         </td>
2531                                         </tr>
2532                                     <tr class="option-row">
2533                                         <td class="option-control"><input id="destroy_on_hide" type="checkbox" data-toggle="toggle" data-on="Destroy" data-off="Hide" data-width="110px"></td>
2534                                         <td class="option-info"><strong>How to handle hidden charts?</strong><br/>
2535                                             <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 smoother page scrolling.</small>
2536                                         </td>
2537                                         </tr>
2538                                     </table>
2539                                 </div>
2540                             </form>
2541                         </div>
2542                         <div role="tabpanel" class="tab-pane" id="settings_sync">
2543                             <form id="optionsForm2" method="get" class="form-horizontal">
2544                                 <div class="form-group">
2545                                     <table>
2546                                     <tr class="option-row">
2547                                         <td class="option-control"><input id="parallel_refresher" type="checkbox" checked data-toggle="toggle" data-on="Parallel" data-off="Sequential" data-width="110px"></td>
2548                                         <td class="option-info"><strong>Which chart refresh policy to use?</strong><br/>
2549                                             <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>
2550                                         </td>
2551                                         </tr>
2552                                     <tr class="option-row" id="concurrent_refreshes_row">
2553                                         <td class="option-control"></td>
2554                                         <td class="option-info">
2555                                             <table>
2556                                             <tr class="option-row">
2557                                             <td class="option-control">
2558                                             <input id="concurrent_refreshes" type="checkbox" checked data-toggle="toggle" data-on="Resync" data-off="Best Effort" data-width="110px">
2559                                             </td>
2560                                             <td class="option-info">
2561                                             <strong>Shall we re-sync chart refreshes?</strong><br/>
2562                                             <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>
2563                                             </td>
2564                                             </tr>
2565                                             </table>
2566                                         </td>
2567                                         </tr>
2568                                     <tr class="option-row">
2569                                         <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>
2570                                         <td class="option-info"><strong>Sync hover selection on all charts?</strong><br/>
2571                                             <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>
2572                                         </td>
2573                                         </tr>
2574                                     <tr class="option-row">
2575                                         <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>
2576                                         <td class="option-info"><strong>Sync pan and zoom on all charts?</strong><br/>
2577                                             <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>
2578                                         </td>
2579                                         </tr>
2580                                     </table>
2581                                 </div>
2582                             </form>
2583                         </div>
2584                         <div role="tabpanel" class="tab-pane" id="settings_visual">
2585                             <form id="optionsForm3" method="get" class="form-horizontal">
2586                                 <div class="form-group">
2587                                     <table>
2588                                     <tr class="option-row">
2589                                         <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>
2590                                         <td class="option-info"><strong>Which theme to use?</strong><br/>
2591                                             <small>Netdata comes with two themes: <b>Dark</b> (the default) and <b>White</b>.
2592                                             <br/>
2593                                             <b>Switching this will reload the dashboard</b>.
2594                                             </small>
2595                                         </td>
2596                                         </tr>
2597                                     <tr class="option-row">
2598                                         <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>
2599                                         <td class="option-info"><strong>Do you need help?</strong><br/>
2600                                             <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.
2601                                             <br/>
2602                                             <b>Switching this will reload the dashboard</b>.
2603                                             </small>
2604                                         </td>
2605                                         </tr>
2606                                     <tr class="option-row">
2607                                         <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>
2608                                         <td class="option-info"><strong>Enable data padding when panning and zooming?</strong><br/>
2609                                             <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>
2610                                         </td>
2611                                         </tr>
2612                                     <tr class="option-row">
2613                                         <td class="option-control"><input id="smooth_plot" type="checkbox" checked data-toggle="toggle"  data-on="Smooth" data-off="Rough" data-width="110px"></td>
2614                                         <td class="option-info"><strong>Enable Bézier lines on charts?</strong><br/>
2615                                             <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.
2616                                             <br/>
2617                                             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>
2618                                         </td>
2619                                         </tr>
2620                                     </table>
2621                                 </div>
2622                             </form>
2623                         </div>
2624                     </div>
2625                 </div>
2626                 <div class="modal-footer">
2627                     <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
2628                 </div>
2629             </div>
2630         </div>
2631     </div>
2632
2633
2634     <div class="modal fade" id="updateModal" tabindex="-1" role="dialog" aria-labelledby="updateModalLabel">
2635         <div class="modal-dialog" role="document">
2636             <div class="modal-content">
2637                 <div class="modal-header">
2638                     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
2639                     <h4 class="modal-title" id="updateModalLabel">Update Check</h4>
2640                 </div>
2641                 <div class="modal-body">
2642                     Your netdata version: <b><code><span id="netdataVersion">Unknown</span></code></b>
2643                     <br/>
2644                     <div style="padding: 10px;"></div>
2645                     <div id="versionCheckLog">Not checked yet. Please press the Check Now button.</div>
2646                 </div>
2647                 <div class="modal-footer">
2648                     <a href="#" onclick="notifyForUpdate(true); return false;" type="button" class="btn btn-default">Check Now</a>
2649                     <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
2650                 </div>
2651             </div>
2652         </div>
2653     </div>
2654
2655     <div class="modal fade" id="deleteRegistryModal" tabindex="-1" role="dialog" aria-labelledby="deleteRegistryModalLabel">
2656         <div class="modal-dialog" role="document">
2657             <div class="modal-content">
2658                 <div class="modal-header">
2659                     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
2660                     <h4 class="modal-title" id="deleteRegistryModalLabel">Delete <span id="deleteRegistryServerName"></span>?</h4>
2661                 </div>
2662                 <div class="modal-body">
2663                     You are about to delete, from your personal list of netdata servers, the following server:
2664                     <p style="text-align: center; padding-top: 10px; padding-bottom: 10px; line-height: 2;">
2665                     <b><span id="deleteRegistryServerName2"></span></b>
2666                     <br/>
2667                     <b><span id="deleteRegistryServerURL"></span></b>
2668                     </p>
2669                     Are you sure you want to do this?
2670                     <br/>
2671                     <div style="padding: 10px;"></div>
2672                     <small>Keep in mind, this server will be added back if and when you visit it again.</small>
2673                     <br/>
2674                     <div id="deleteRegistryResponse" style="display: block; width: 100%; text-align: center; padding-top: 20px;"></div>
2675                 </div>
2676                 <div class="modal-footer">
2677                     <button type="button" class="btn btn-success" data-dismiss="modal">keep it</button>
2678                     <a href="#" onclick="notifyForDeleteRegistry(true); return false;" type="button" class="btn btn-danger">delete it</a>
2679                 </div>
2680             </div>
2681         </div>
2682     </div>
2683
2684     <div class="modal fade" id="switchRegistryModal" tabindex="-1" role="dialog" aria-labelledby="switchRegistryModalLabel">
2685         <div class="modal-dialog" role="document">
2686             <div class="modal-content">
2687                 <div class="modal-header">
2688                     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
2689                     <h4 class="modal-title" id="switchRegistryModalLabel">Switch Netdata Registry Identity</h4>
2690                 </div>
2691                 <div class="modal-body">
2692                     You can copy and paste the following ID to all your browsers (e.g. work and home).
2693                     <br/>
2694                     All the browsers with the same ID will identify <b>you</b>, so please don't share this with others.
2695                     <p style="text-align: center; padding-top: 10px; padding-bottom: 10px; line-height: 2;">
2696                     <form action="#">
2697                     <input type="text" class="form-control" id="switchRegistryPersonGUID" placeholder="your personal ID" maxlength="36" autocomplete="off" style="text-align: center; font-size: 1.4em;">
2698                     </form>
2699                     </p>
2700                     Either copy this ID and paste it to another browser, or paste here the ID you have taken from another browser.
2701                     <p style="padding-top: 10px;"><small>
2702                         Keep in mind that:
2703                         <ul>
2704                             <li>when you switch ID, your previous ID will be lost forever - this is irreversible.</li>
2705                             <li>both IDs (your old and the new) must list this netdata at their personal lists.</li>
2706                             <li>both IDs have to be known by the registry: <b><span id="switchRegistryURL"></span></b>.</li>
2707                             <li>to get a new ID, just clear your browser cookies.</li>
2708                         </ul>
2709                     </small></p>
2710                     <div id="switchRegistryResponse" style="display: block; width: 100%; text-align: center; padding-top: 20px;"></div>
2711                 </div>
2712                 <div class="modal-footer">
2713                     <button type="button" class="btn btn-success" data-dismiss="modal">cancel</button>
2714                     <a href="#" onclick="notifyForSwitchRegistry(true); return false;" type="button" class="btn btn-danger">impersonate</a>
2715                 </div>
2716             </div>
2717         </div>
2718     </div>
2719
2720     <div class="modal fade" id="gotoServerModal" tabindex="-1" role="dialog" aria-labelledby="gotoServerModalLabel">
2721         <div class="modal-dialog" role="document">
2722             <div class="modal-content">
2723                 <div class="modal-header">
2724                     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
2725                     <h4 class="modal-title" id="gotoServerModalLabel"><span id="gotoServerName"></span></h4>
2726                 </div>
2727                 <div class="modal-body">
2728                     Checking known URLs for this server...
2729                     <div  style="padding-top: 20px;">
2730                         <table id="gotoServerList">
2731                         </table>
2732                     </div>
2733                     <p style="padding-top: 10px;"><small>
2734                         Checks may fail if you are viewing an HTTPS page and the server to be checked is HTTP only.
2735                     </small></p>
2736                     <div id="gotoServerResponse" style="display: block; width: 100%; text-align: center; padding-top: 20px;"></div>
2737                 </div>
2738                 <div class="modal-footer">
2739                     <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
2740                 </div>
2741             </div>
2742         </div>
2743     </div>
2744 </body>
2745 </html>
2746 <script async type="text/javascript" src="dashboard.js?v54"></script>