src/jquery.nstSlider.js
function (histogram) {
            var $this = this;

            $this.data('last_step_histogram', histogram);

            if (typeof histogram === 'undefined') {
                $.error('got an undefined histogram in set_step_histogram');
                _methods.unset_step_histogram.call($this);
            }

            var sliderWidthPx = _methods.getSliderWidthPx.call($this) - $this.data('left_grip_width'),
                nbuckets = histogram.length;

            if (sliderWidthPx <= 0) {
                // that means the slider is not visible...
                return;
            }

            //
            // we need to transform this pdf into a cdf, and use it to obtain
            // two mappings: pixel to value and value to pixel.
            //
            // 1) normalize the pdf to sum to sliderWidthPx first
            var i;
            var histogram_sum = 0;
            for (i=0; i<nbuckets; i++) {
                histogram_sum += histogram[i]; 
            }

            //
            // if the sum of the histogram is 0 it means that all is 0 in the 
            // histogram! (i.e, flat histogram). In this case we already know
            // what's going to be the answer...
            //
            if (histogram_sum === 0) {
                // ... and the answer is: a linear scale between min_range and
                // max range!
                methods.unset_step_histogram.call($this);

                return $this;
            }

            // coefficient for normalization
            var coeff = parseFloat(histogram_sum)/sliderWidthPx;

            // go normalize the histogram using this coefficient!
            for (i=0; i<nbuckets; i++) {
                histogram[i] = histogram[i]/coeff;
            }

            // 2) now that the histogram is normalized, extract the cumulative
            // distribution function (CDF). This is an always increasing function
            // that ranges between 0 and sliderWidthPx;
            //
            // We also build the inverted cdf, just the cdf read the other way
            // around.
            //
            var cdf = [ histogram[0] ];  // points to pixels
            for (i=1; i<nbuckets; i++) {
                var cdf_x = cdf[i-1] + histogram[i];
                cdf.push(cdf_x);
            }
            cdf.push(sliderWidthPx);


            // the first value here is always min_range as the cdf is supposed
            // to start from 0 (also first pixel = min_range)
            var pixel_to_value_lookup = [ $this.data('range_min') ];

            var last_filled = 0; // we've already filled 0

            // now stretch over the rest of the cdf
            var last_price_for_cdf_bucket = pixel_to_value_lookup[0];

            var cdf_bucket_count = 0;
            while (last_filled <= sliderWidthPx) { // do until all pixels are filled

                // get next item from cdf
                var fill_up_to_px = parseInt(cdf.shift(), 10);
                var price_for_cdf_bucket = 
                    _methods.inverse_rangemap_0_to_n.call($this, cdf_bucket_count+1, nbuckets+1);

                cdf_bucket_count++;

                // how many pixels do we have to fill
                var fill_tot = fill_up_to_px - last_filled;

                // interpolate and fill
                var diff = price_for_cdf_bucket - last_price_for_cdf_bucket;
                for (i = last_filled; i < fill_up_to_px; i++) {
                    var next_price_for_cdf_bucket = 
                        last_price_for_cdf_bucket + (diff * (i-last_filled+1) / fill_tot);

                    pixel_to_value_lookup.push(next_price_for_cdf_bucket);

                    last_filled++;

                    last_price_for_cdf_bucket = next_price_for_cdf_bucket;
                }

                if (last_filled === sliderWidthPx) {
                    break;
                }
            }
            pixel_to_value_lookup[pixel_to_value_lookup.length-1] = $this.data('range_max');

            // 3) build lookup functions to extract pixels and values from the
            // cdf and the inverted cdf.
            //
            var pixel_to_value_mapping = function (pixel) {
                return pixel_to_value_lookup[parseInt(pixel, 10)];
            };

            var value_to_pixel_mapping = function (value) {
                //
                // Binary search into the array of pixels, returns always the
                // rightmost pixel if there is no exact match.
                //
                var suggestedPixel = _methods.binarySearch.call($this, pixel_to_value_lookup, value, 
                    function(a, i) { return a[i]; },  // access a value in the array
                    _methods.binarySearchValueToPxCompareFunc
                );

                // exact match
                if (pixel_to_value_lookup[suggestedPixel] === value) {
                    return suggestedPixel;
                }

                // approx match: we need to check if it's closer to the value
                // at suggestedPixel or the value at suggestedPixel-1
                if ( Math.abs(pixel_to_value_lookup[suggestedPixel-1] - value) <
                     Math.abs(pixel_to_value_lookup[suggestedPixel] - value) ) {

                     return suggestedPixel-1;
                }
                return suggestedPixel;
            };

            //
            // these two functions will be stored and then used internally to
            // decide what value to display given a certain pixel, and what
            // pixel to put the slider on given a certain value.
            //
            $this.data('pixel_to_value_mapping', pixel_to_value_mapping);
            $this.data('value_to_pixel_mapping', value_to_pixel_mapping);

            return $this;
        }
function (histogram) {
            var $this = this;

            $this.data('last_step_histogram', histogram);

            if (typeof histogram === 'undefined') {
                $.error('got an undefined histogram in set_step_histogram');
                _methods.unset_step_histogram.call($this);
            }

            var sliderWidthPx = _methods.getSliderWidthPx.call($this) - $this.data('left_grip_width'),
                nbuckets = histogram.length;

            if (sliderWidthPx <= 0) {
                // that means the slider is not visible...
                return;
            }

            //
            // we need to transform this pdf into a cdf, and use it to obtain
            // two mappings: pixel to value and value to pixel.
            //
            // 1) normalize the pdf to sum to sliderWidthPx first
            var i;
            var histogram_sum = 0;
            for (i=0; i<nbuckets; i++) {
                histogram_sum += histogram[i]; 
            }

            //
            // if the sum of the histogram is 0 it means that all is 0 in the 
            // histogram! (i.e, flat histogram). In this case we already know
            // what's going to be the answer...
            //
            if (histogram_sum === 0) {
                // ... and the answer is: a linear scale between min_range and
                // max range!
                methods.unset_step_histogram.call($this);

                return $this;
            }

            // coefficient for normalization
            var coeff = parseFloat(histogram_sum)/sliderWidthPx;

            // go normalize the histogram using this coefficient!
            for (i=0; i<nbuckets; i++) {
                histogram[i] = histogram[i]/coeff;
            }

            // 2) now that the histogram is normalized, extract the cumulative
            // distribution function (CDF). This is an always increasing function
            // that ranges between 0 and sliderWidthPx;
            //
            // We also build the inverted cdf, just the cdf read the other way
            // around.
            //
            var cdf = [ histogram[0] ];  // points to pixels
            for (i=1; i<nbuckets; i++) {
                var cdf_x = cdf[i-1] + histogram[i];
                cdf.push(cdf_x);
            }
            cdf.push(sliderWidthPx);


            // the first value here is always min_range as the cdf is supposed
            // to start from 0 (also first pixel = min_range)
            var pixel_to_value_lookup = [ $this.data('range_min') ];

            var last_filled = 0; // we've already filled 0

            // now stretch over the rest of the cdf
            var last_price_for_cdf_bucket = pixel_to_value_lookup[0];

            var cdf_bucket_count = 0;
            while (last_filled <= sliderWidthPx) { // do until all pixels are filled

                // get next item from cdf
                var fill_up_to_px = parseInt(cdf.shift(), 10);
                var price_for_cdf_bucket = 
                    _methods.inverse_rangemap_0_to_n.call($this, cdf_bucket_count+1, nbuckets+1);

                cdf_bucket_count++;

                // how many pixels do we have to fill
                var fill_tot = fill_up_to_px - last_filled;

                // interpolate and fill
                var diff = price_for_cdf_bucket - last_price_for_cdf_bucket;
                for (i = last_filled; i < fill_up_to_px; i++) {
                    var next_price_for_cdf_bucket = 
                        last_price_for_cdf_bucket + (diff * (i-last_filled+1) / fill_tot);

                    pixel_to_value_lookup.push(next_price_for_cdf_bucket);

                    last_filled++;

                    last_price_for_cdf_bucket = next_price_for_cdf_bucket;
                }

                if (last_filled === sliderWidthPx) {
                    break;
                }
            }
            pixel_to_value_lookup[pixel_to_value_lookup.length-1] = $this.data('range_max');

            // 3) build lookup functions to extract pixels and values from the
            // cdf and the inverted cdf.
            //
            var pixel_to_value_mapping = function (pixel) {
                return pixel_to_value_lookup[parseInt(pixel, 10)];
            };

            var value_to_pixel_mapping = function (value) {
                //
                // Binary search into the array of pixels, returns always the
                // rightmost pixel if there is no exact match.
                //
                var suggestedPixel = _methods.binarySearch.call($this, pixel_to_value_lookup, value, 
                    function(a, i) { return a[i]; },  // access a value in the array
                    _methods.binarySearchValueToPxCompareFunc
                );

                // exact match
                if (pixel_to_value_lookup[suggestedPixel] === value) {
                    return suggestedPixel;
                }

                // approx match: we need to check if it's closer to the value
                // at suggestedPixel or the value at suggestedPixel-1
                if ( Math.abs(pixel_to_value_lookup[suggestedPixel-1] - value) <
                     Math.abs(pixel_to_value_lookup[suggestedPixel] - value) ) {

                     return suggestedPixel-1;
                }
                return suggestedPixel;
            };

            //
            // these two functions will be stored and then used internally to
            // decide what value to display given a certain pixel, and what
            // pixel to put the slider on given a certain value.
            //
            $this.data('pixel_to_value_mapping', pixel_to_value_mapping);
            $this.data('value_to_pixel_mapping', value_to_pixel_mapping);

            return $this;
        }
/*
This tells the slider to increment its step non linearly over the
current range, based on the histogram on where results are.

the input parameter 'histogram' identifies an empirical probability
density function (PDF).