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