From: Costa Tsaousis (ktsaou) Date: Mon, 30 Nov 2015 23:36:34 +0000 (+0200) Subject: minor code cleanups; updated the dashboard to fix inline charts X-Git-Tag: v1.0rc~222 X-Git-Url: https://arthur.barton.de/gitweb/?a=commitdiff_plain;h=f39384e8f93cd395b5c48c406f4ca53753abf7e8;p=netdata.git minor code cleanups; updated the dashboard to fix inline charts --- diff --git a/src/daemon.c b/src/daemon.c index d73a3a46..52884e6c 100755 --- a/src/daemon.c +++ b/src/daemon.c @@ -25,19 +25,6 @@ #include "main.h" #include "daemon.h" -#define BACKTRACE_SIZE 4096 - -void print_backtrace() -{ - void *buffer[BACKTRACE_SIZE]; - int nptrs; - - nptrs = backtrace(buffer, BACKTRACE_SIZE); - fprintf(stderr, "\n\nSTACK TRACE (%d addresses):\n\n", nptrs); - backtrace_symbols_fd(buffer, nptrs, STDERR_FILENO); - fprintf(stderr, "\n\n"); -} - void sig_handler(int signo) { switch(signo) { @@ -51,7 +38,6 @@ void sig_handler(int signo) case SIGXCPU: case SIGXFSZ: info("Death signaled exit (signal %d). Errno: %d (%s)", signo, errno, strerror(errno)); - print_backtrace(); signal(signo, SIG_DFL); break; @@ -63,18 +49,13 @@ void sig_handler(int signo) case SIGUSR1: case SIGUSR2: info("Signaled exit (signal %d). Errno: %d (%s)", signo, errno, strerror(errno)); - print_backtrace(); signal(SIGPIPE, SIG_IGN); signal(SIGTERM, SIG_IGN); signal(SIGQUIT, SIG_IGN); signal(SIGHUP, SIG_IGN); signal(SIGINT, SIG_IGN); signal(SIGCHLD, SIG_IGN); - kill_childs(); - rrdset_free_all(); - //unlink("/var/run/netdata.pid"); - info("NetData exiting. Bye bye..."); - exit(1); + netdata_cleanup_and_exit(1); break; case SIGPIPE: @@ -263,7 +244,7 @@ int become_daemon(int dont_fork, int close_all_files, const char *user, const ch // close all files if(close_all_files) { int i; - for(i = sysconf(_SC_OPEN_MAX); i > 0; i--) + for(i = sysconf(_SC_OPEN_MAX) - 1; i > 0; i--) if( ((access_fd && i != *access_fd) || !access_fd) && i != dev_null diff --git a/src/daemon.h b/src/daemon.h index 9f8694f9..77186daa 100755 --- a/src/daemon.h +++ b/src/daemon.h @@ -9,4 +9,6 @@ extern int become_user(const char *username); extern int become_daemon(int dont_fork, int close_all_files, const char *user, const char *input, const char *output, const char *error, const char *access, int *access_fd, FILE **access_fp); +extern void netdata_cleanup_and_exit(int i); + #endif /* NETDATA_DAEMON_H */ diff --git a/src/main.c b/src/main.c index 328d4ac4..7288d073 100755 --- a/src/main.c +++ b/src/main.c @@ -35,6 +35,17 @@ #include "main.h" +int netdata_exit = 0; + +void netdata_cleanup_and_exit(int ret) +{ + kill_childs(); + rrdset_free_all(); + //unlink("/var/run/netdata.pid"); + info("NetData exiting. Bye bye..."); + exit(ret); +} + struct netdata_static_thread { char *name; @@ -445,7 +456,17 @@ int main(int argc, char **argv) } // for future use - the main thread - while(1) sleep(60); + while(1) { + if(netdata_exit != 0) { + netdata_exit++; + + if(netdata_exit > 5) { + netdata_cleanup_and_exit(0); + exit(0); + } + } + sleep(2); + } exit(0); } diff --git a/src/main.h b/src/main.h index d6b31071..6a90efd9 100755 --- a/src/main.h +++ b/src/main.h @@ -1,7 +1,10 @@ #ifndef NETDATA_MAIN_H #define NETDATA_MAIN_H 1 +extern int netdata_exit; + extern void kill_childs(void); extern int killpid(pid_t pid, int signal); +extern void netdata_cleanup_and_exit(int ret); #endif /* NETDATA_MAIN_H */ diff --git a/src/popen.c b/src/popen.c index 58dc1f54..9449c64f 100755 --- a/src/popen.c +++ b/src/popen.c @@ -78,7 +78,7 @@ FILE *mypopen(const char *command, pid_t *pidptr) // close all files int i; - for(i = sysconf(_SC_OPEN_MAX); i > 0; i--) + for(i = sysconf(_SC_OPEN_MAX) - 1; i > 0; i--) if(i != STDIN_FILENO && i != STDERR_FILENO && i != pipefd[PIPE_WRITE]) close(i); // move the pipe to stdout diff --git a/src/web_client.c b/src/web_client.c index d05ef9ba..b38cff50 100755 --- a/src/web_client.c +++ b/src/web_client.c @@ -34,6 +34,8 @@ int web_client_timeout = DEFAULT_DISCONNECT_IDLE_WEB_CLIENTS_AFTER_SECONDS; int web_enable_gzip = 1; +extern int netdata_exit; + struct web_client *web_clients = NULL; unsigned long long web_clients_count = 0; @@ -975,7 +977,7 @@ void web_client_process(struct web_client *w) { //if(strstr(w->response.data->buffer, "X-DataSource-Auth")) // datasource_type = DATASOURCE_GOOGLE_JSON; - char *buf = w->response.data->buffer; + char *buf = (char *)buffer_tostring(w->response.data); char *tok = strsep(&buf, " \r\n"); char *url = NULL; char *pointer_to_free = NULL; // keep url_decode() allocated buffer @@ -1007,6 +1009,15 @@ void web_client_process(struct web_client *w) { datasource_type = DATASOURCE_JSON; code = web_client_api_request(w, url); } +#ifdef WEB_EXIT + else if(strcmp(tok, "exit") == 0) { + netdata_exit = 1; + code = 200; + w->response.data->contenttype = CT_TEXT_PLAIN; + buffer_flush(w->response.data); + buffer_strcat(w->response.data, "will do"); + } +#endif else if(strcmp(tok, WEB_PATH_DATA) == 0) { // "data" // the client is requesting rrd data datasource_type = DATASOURCE_JSON; diff --git a/web/Makefile.am b/web/Makefile.am index b20279f8..3c0003a9 100644 --- a/web/Makefile.am +++ b/web/Makefile.am @@ -25,4 +25,5 @@ dist_weblib_DATA = \ lib/jquery.sparkline.min.js \ lib/morris.min.js \ lib/raphael-min.js \ + lib/visible.js \ $(NULL) diff --git a/web/dashboard.html b/web/dashboard.html index 2823214a..4c8842b2 100755 --- a/web/dashboard.html +++ b/web/dashboard.html @@ -19,7 +19,7 @@ This is a template for building custom dashboards. To build a dashboard you just data-width="600" data-height="200" data-after="-600" - </div> + ></div> </body> <script type="text/javascript" src="http://netdata.server:19999/dashboard.js"> </html> @@ -47,15 +47,15 @@ This is a template for building custom dashboards. To build a dashboard you just System CPU - Stacked Area Chart -   -
Peity Charts - +   +
Peity Charts + Peity charts do not support 'NULL' values, so the charts cannot indicate that values are missing. Peity charts cannot have multiple dimensions on the charts - so netdata will use 'min2max' to show the total of all dimensions. - +
- +
- +
rendered in X ms rendered in X ms -   -
Sparkline Charts - +   +
Sparkline Charts + Sparkline charts support 'NULL' values, so the charts can indicate that values are missing. Sparkline charts stretch the values to show the variations between values in more detail. They also have mouse-hover support.
Sparklines are fantastic. You can inline charts in text. For example this -
is my current cpu usage, + >
is my current cpu usage,
while this -
is the bandwidth my netdata server is currently transmitting and this + >
is the bandwidth my netdata server is currently transmitting and this -
is the requests/sec it serves. + data-width="360" + data-height="20" + data-after="-180" + >
is the requests/sec it serves. - +
+ >
- +
+ >
- +
+ >
@@ -156,40 +153,40 @@ This is a template for building custom dashboards. To build a dashboard you just rendered in X ms rendered in X ms -   -
Dygraph Charts - +   +
Dygraph Charts + The fastest charting engine that can chart complete charts (not just sparklines). The charts are zoomable (drag their contents to zoom-in, double click to zoom-out). For the moment zooming is just on the presentation layer (the data do not become more detailed when you zoom). - +
+ >
- +
+ >
- +
+ >
@@ -197,39 +194,39 @@ This is a template for building custom dashboards. To build a dashboard you just rendered in X ms rendered in X ms -   -
Google Charts - +   +
Google Charts + NetData was originaly developed with Google Charts. NetData is a complete Google Visualization API provider. - +
+ >
- +
+ >
- +
+ >
@@ -237,39 +234,39 @@ This is a template for building custom dashboards. To build a dashboard you just rendered in X ms rendered in X ms -   -
Morris Charts - +   +
Morris Charts + Unfortunatelly, Morris Charts are veeeeeeeeeeeeeeeery slow! We force them to lower their detail to get acceptable results. And they have issues with negative numbers in area charts... - +
+ >
- +
+ >
- +
+ >
diff --git a/web/dashboard.js b/web/dashboard.js index 9f4945af..d99a53eb 100755 --- a/web/dashboard.js +++ b/web/dashboard.js @@ -67,9 +67,9 @@ NETDATA.morris_js = NETDATA.serverDefault + 'lib/morris.min.js'; NETDATA.morris_css = NETDATA.serverDefault + 'css/morris.css'; NETDATA.google_js = 'https://www.google.com/jsapi'; - NETDATA.colors = [ '#3366CC', '#DC3912', '#FF9900', '#109618', '#990099', '#3B3EAC', '#0099C6', '#DD4477', - '#66AA00', '#B82E2E', '#316395', '#994499', '#22AA99', '#AAAA11', '#6633CC', '#E67300', '#8B0707', - '#329262', '#5574A6', '#3B3EAC' ]; + NETDATA.colors = [ '#3366CC', '#DC3912', '#FF9900', '#109618', '#990099', '#3B3EAC', '#0099C6', + '#DD4477', '#66AA00', '#B82E2E', '#316395', '#994499', '#22AA99', '#AAAA11', + '#6633CC', '#E67300', '#8B0707', '#329262', '#5574A6', '#3B3EAC' ]; // ---------------------------------------------------------------------------------------------------------------- // the defaults for all charts @@ -82,15 +82,23 @@ method: 'average', // the grouping method before: 0, // panning after: -600, // panning - point_width: 1, // the detail of the chart + pixels_per_point: 1, // the detail of the chart } - NETDATA.all_url = 'all2.js'; - NETDATA.idle_between_charts = 50; - NETDATA.idle_between_loops = 100; - NETDATA.debug = 1; + NETDATA.options = { + targets: null, + updated_dom: 1, + debug: 1, - if(NETDATA.debug) console.log('welcome to NETDATA'); + current: { + pixels_per_point: 1, + idle_between_charts: 50, + idle_between_loops: 100, + debug: 1 + } + } + + if(NETDATA.options.debug) console.log('welcome to NETDATA'); // ---------------------------------------------------------------------------------------------------------------- @@ -125,11 +133,19 @@ NETDATA.errorLast.datetime = 0; } - NETDATA.messageInABox = function(div, width, height, message) { - div.innerHTML = '
' + NETDATA.chartContainer = function(element, width, height) { + self = $(element); + self.css('width', width) + .css('height', height) + .css('display', 'inline-block') + .css('overflow', 'hidden'); + } + + NETDATA.messageInABox = function(element, width, height, message) { + NETDATA.chartContainer(element, width, height); + element.innerHTML = '
' + message - + '
'; + + '
'; } // ---------------------------------------------------------------------------------------------------------------- @@ -155,58 +171,63 @@ callback(); } - NETDATA.generateDataURL = function(args) { + NETDATA.generateChartDataURL = function(options) { // build the data URL - var url = args.host + args.url; + var url = options.host + options.url; url += "&points="; - url += args.points.toString(); + url += options.points.toString(); url += "&group="; - url += args.method; + url += options.method; url += "&after="; - url += args.after || "0"; + url += options.after || "0"; url += "&before="; - url += args.before || "0"; - url += "&options=" + NETDATA.chartLibraries[args.library].options + '|'; - url += (args.non_zero)?"nonzero":""; - url += "&format=" + NETDATA.chartLibraries[args.library].format; + url += options.before || "0"; + url += "&options=" + NETDATA.chartLibraries[options.library].options + '|'; + url += (options.non_zero)?"nonzero":""; + url += "&format=" + NETDATA.chartLibraries[options.library].format; - if(args.dimensions) - url += "&dimensions=" + args.dimensions; + if(options.dimensions) + url += "&dimensions=" + options.dimensions; - if(NETDATA.debug) console.log('generateDataURL(' + args + ') = ' + url ); + if(NETDATA.options.debug) console.log('generateChartDataURL(' + options + ') = ' + url ); return url; } - NETDATA.loadCharts = function(targets, index, callback) { - if(NETDATA.debug) console.log('loadCharts( now) { - if(typeof callback == 'function') - callback(); + console.log(self.data('netdata') + ' too soon - skipping.'); + if(typeof callback == 'function') callback(); + } + else if(!self.visible(true)) { + console.log(self.data('netdata') + ' is NOT visible.'); + if(typeof callback == 'function') callback(); } else { - var url = self.data('chart-url'); - - if(NETDATA.debug) console.log('netdataDownloadChartData(): downloading ' + url); - + console.log(self.data('netdata') + ' is visible, downloading data...'); $.ajax( { - url: url, + url: self.data('chart-url'), crossDomain: true }) .then(function(data) { - //var result = $.map(data.rows, function(item) { - // get from the 3rd column the 'v' member - //return item.c[3].v; - //}); - - // since we downloaded the data - // update the last-updated time to prevent - // another download too soon - self.data('last-updated', new Date().getTime()); - - // render it - var created = self.data('created'); - self.trigger((created ? 'update' : 'create'), [data]).data('created', true) - }) - .fail(function() { - console.log('failed to download chart data'); - }) - .always(function() { - var last = self.data('last-updated'); - var now = new Date().getTime(); - var dt = now - last; - self.data('refresh-dt', dt); + var started = new Date().getTime(); + + if(self.data('created')) { + console.log('updating ' + self.data('chart-library') + ' chart ' + self.data('netdata')); + self.trigger('update', [data]); + // NETDATA.chartLibraries[self.data('chart-library')].update(element, data); + } + else { + console.log('creating ' + self.data('chart-library') + ' chart ' + self.data('netdata')); + self.trigger('create', [data]); + //NETDATA.chartLibraries[self.data('chart-library')].create(element, data); + self.data('created', true); + } + var ended = new Date().getTime(); + self.data('updated', ended); + + var dt = ended - started; + + self.data('refresh-dt', dt); var element_name = self.data('dt-element-name') || null; if(element_name) { var element = document.getElementById(element_name) || null; @@ -368,38 +389,46 @@ element.innerHTML = dt.toString(); } } - - if(typeof callback == 'function') - callback(); + }) + .fail(function() { + NETDATA.messageInABox(element, width, height, 'chart "' + id + '" not found on url "' + url + '"'); + }) + .always(function() { + if(typeof callback == 'function') callback(); }); } }; - function netdataRefreshTargets(targets, index) { - // if(NETDATA.debug) console.log('netdataRefreshTargets(
'; + element.innerHTML = '
'; var div = document.getElementById(uuid); self.sparkline(data, options); @@ -623,7 +652,7 @@ if(typeof netdataStopDygraph == 'undefined') { $.getScript(NETDATA.dygraph_js) .done(function() { - NETDATA.registerChartLibrary('dygraph', NETDATA.dygraph_js, 'json', 'ms|flip', 2); + NETDATA.registerChartLibrary('dygraph', NETDATA.dygraph_js); }) .fail(function() { NETDATA.error(100, NETDATA.dygraph_js); @@ -636,8 +665,8 @@ callback(); }; - NETDATA.dygraphChartUpdate = function(event, data) { - var self = $(this); + NETDATA.dygraphChartUpdate = function(element, data) { + var self = $(element); var dygraph = self.data('dygraph-instance'); if(typeof data.update_every != 'undefined') @@ -651,8 +680,8 @@ console.log('not updating dygraphs'); }; - NETDATA.dygraphChartCreate = function(event, data) { - var self = $(this); + NETDATA.dygraphChartCreate = function(element, data) { + var self = $(element); var width = self.data('width') || NETDATA.chartDefaults.width; var height = self.data('height') || NETDATA.chartDefaults.height; var chart = self.data('chart'); @@ -803,7 +832,7 @@ $.getScript(NETDATA.morris_js) .done(function() { - NETDATA.registerChartLibrary('morris', NETDATA.morris_js, 'json', 'objectrows|ms', 10); + NETDATA.registerChartLibrary('morris', NETDATA.morris_js); }) .fail(function() { NETDATA.error(100, NETDATA.morris_js); @@ -817,8 +846,8 @@ callback(); }; - NETDATA.morrisChartUpdate = function(event, data) { - var self = $(this); + NETDATA.morrisChartUpdate = function(element, data) { + var self = $(element); var width = self.data('width') || NETDATA.chartDefaults.width; var height = self.data('height') || NETDATA.chartDefaults.height; var morris = self.data('morris-instance'); @@ -834,8 +863,8 @@ console.log('not updating morris'); }; - NETDATA.morrisChartCreate = function(event, data) { - var self = $(this); + NETDATA.morrisChartCreate = function(element, data) { + var self = $(element); var width = self.data('width') || NETDATA.chartDefaults.width; var height = self.data('height') || NETDATA.chartDefaults.height; var chart = self.data('chart'); @@ -884,7 +913,7 @@ if(typeof netdataStopRaphael == 'undefined') { $.getScript(NETDATA.raphael_js) .done(function() { - NETDATA.registerChartLibrary('raphael', NETDATA.raphael_js, 'json', 'flip|min2max', 1); + NETDATA.registerChartLibrary('raphael', NETDATA.raphael_js); }) .fail(function() { NETDATA.error(100, NETDATA.raphael_js); @@ -898,8 +927,8 @@ callback(); }; - NETDATA.raphaelChartUpdate = function(event, data) { - var self = $(this); + NETDATA.raphaelChartUpdate = function(element, data) { + var self = $(element); var width = self.data('width') || NETDATA.chartDefaults.width; var height = self.data('height') || NETDATA.chartDefaults.height; @@ -909,8 +938,8 @@ }) }; - NETDATA.raphaelChartCreate = function(event, data) { - var self = $(this); + NETDATA.raphaelChartCreate = function(element, data) { + var self = $(element); var width = self.data('width') || NETDATA.chartDefaults.width; var height = self.data('height') || NETDATA.chartDefaults.height; @@ -926,7 +955,7 @@ NETDATA.googleInitialize = function(callback) { if(typeof netdataStopGoogleCharts == 'undefined' && typeof google != 'undefined') { - NETDATA.registerChartLibrary('google', NETDATA.google_js, 'datatable', '', 3); + NETDATA.registerChartLibrary('google', NETDATA.google_js); if(typeof callback == "function") callback(); } @@ -934,8 +963,8 @@ callback(); }; - NETDATA.googleChartUpdate = function(event, data) { - var self = $(this); + NETDATA.googleChartUpdate = function(element, data) { + var self = $(element); var width = self.data('width') || NETDATA.chartDefaults.width; var height = self.data('height') || NETDATA.chartDefaults.height; var gchart = self.data('google-instance'); @@ -949,8 +978,8 @@ gchart.draw(datatable, options); }; - NETDATA.googleChartCreate = function(event, data) { - var self = $(this); + NETDATA.googleChartCreate = function(element, data) { + var self = $(element); var width = self.data('width') || NETDATA.chartDefaults.width; var height = self.data('height') || NETDATA.chartDefaults.height; var chart = self.data('chart'); @@ -1020,7 +1049,7 @@ switch(chart.chart_type) { case "area": options.vAxis.viewWindowMode = 'maximized'; - gchart = new google.visualization.AreaChart(this); + gchart = new google.visualization.AreaChart(element); break; case "stacked": @@ -1029,13 +1058,13 @@ options.vAxis.viewWindowMode = 'maximized'; options.vAxis.minValue = null; options.vAxis.maxValue = null; - gchart = new google.visualization.AreaChart(this); + gchart = new google.visualization.AreaChart(element); break; default: case "line": options.lineWidth = 2; - gchart = new google.visualization.LineChart(this); + gchart = new google.visualization.LineChart(element); break; } @@ -1046,26 +1075,109 @@ .data('created', true); }; + // ---------------------------------------------------------------------------------------------------------------- + // Charts Libraries Registration + + NETDATA.chartLibraries = { + "dygraph": { + initialize: NETDATA.dygraphInitialize, + create: NETDATA.dygraphChartCreate, + update: NETDATA.dygraphChartUpdate, + initialized: false, + enabled: true, + format: 'json', + options: 'ms|flip', + pixels_per_point: 2, + detects_dimensions_on_update: false + }, + "sparkline": { + initialize: NETDATA.sparklineInitialize, + create: NETDATA.sparklineChartCreate, + update: NETDATA.sparklineChartUpdate, + initialized: false, + enabled: true, + format: 'array', + options: 'flip|min2max', + pixels_per_point: 2, + detects_dimensions_on_update: false + }, + "peity": { + initialize: NETDATA.peityInitialize, + create: NETDATA.peityChartCreate, + update: NETDATA.peityChartUpdate, + initialized: false, + enabled: true, + format: 'ssvcomma', + options: 'null2zero|flip|min2max', + pixels_per_point: 2, + detects_dimensions_on_update: false + }, + "morris": { + initialize: NETDATA.morrisInitialize, + create: NETDATA.morrisChartCreate, + update: NETDATA.morrisChartUpdate, + initialized: false, + enabled: true, + format: 'json', + options: 'objectrows|ms', + pixels_per_point: 10, + detects_dimensions_on_update: false + }, + "google": { + initialize: NETDATA.googleInitialize, + create: NETDATA.googleChartCreate, + update: NETDATA.googleChartUpdate, + initialized: false, + enabled: true, + format: 'datatable', + options: '', + pixels_per_point: 2, + detects_dimensions_on_update: true + }, + "raphael": { + initialize: NETDATA.raphaelInitialize, + create: NETDATA.raphaelChartCreate, + update: NETDATA.raphaelChartUpdate, + initialized: false, + enabled: true, + format: 'json', + options: '', + pixels_per_point: 1, + detects_dimensions_on_update: false + } + }; + + NETDATA.registerChartLibrary = function(library, url) { + console.log("registering chart library: " + library); + + NETDATA.chartLibraries[library] + .url = url + .initialized = new Date().getTime(); + + console.log(NETDATA.chartLibraries); + } + // ---------------------------------------------------------------------------------------------------------------- // load all libraries and initialize NETDATA.errorReset(); NETDATA._loadjQuery(function() { - NETDATA.raphaelInitialize(function() { - NETDATA.morrisInitialize(function() { - NETDATA.peityInitialize(function() { - NETDATA.sparklineInitialize(function() { - NETDATA.dygraphInitialize(function() { - NETDATA.googleInitialize(function() { - netdataParsePageCharts(); - }) // google - }) // dygraph.js - }) // sparkline.js - }) // piety.js - }) // morris.js - }) // raphael.js + $.getScript(NETDATA.serverDefault + 'lib/visible.js').then(function() { + NETDATA.raphaelInitialize(function() { + NETDATA.morrisInitialize(function() { + NETDATA.peityInitialize(function() { + NETDATA.sparklineInitialize(function() { + NETDATA.dygraphInitialize(function() { + NETDATA.googleInitialize(function() { + NETDATA.init(); + }) // google + }) // dygraph.js + }) // sparkline.js + }) // piety.js + }) // morris.js + }) // raphael.js + }) }); })(window); - diff --git a/web/lib/visible.js b/web/lib/visible.js new file mode 100755 index 00000000..bfe1624e --- /dev/null +++ b/web/lib/visible.js @@ -0,0 +1,26 @@ +(function($){ + + /** + * Copyright 2012, Digital Fusion + * Licensed under the MIT license. + * http://teamdf.com/jquery-plugins/license/ + * + * @author Sam Sehnert + * @desc A small plugin that checks whether elements are within + * the user visible viewport of a web browser. + * only accounts for vertical position, not horizontal. + */ + $.fn.visible = function(partial){ + + var $t = $(this), + $w = $(window), + viewTop = $w.scrollTop(), + viewBottom = viewTop + $w.height(), + _top = $t.offset().top, + _bottom = _top + $t.height(), + compareTop = partial === true ? _bottom : _top, + compareBottom = partial === true ? _top : _bottom; + + return ((compareBottom <= viewBottom) && (compareTop >= viewTop)); + }; +})(jQuery);