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