$.fn.bopacity = function () {
    var options = {
        off: .3,
        on: 1,
        step: 100,
        p: .4
    }



var round = function (value, precision, mode) {
    // Returns the number rounded to specified precision  
    // 
    // version: 1009.820
    // discuss at: http://phpjs.org/functions/round    // +   original by: Philip Peterson
    // +    revised by: Onno Marsman
    // +      input by: Greenseed
    // +    revised by: T.Wild
    // +      input by: meo    // +      input by: William
    // +   bugfixed by: Brett Zamir (http://brett-zamir.me)
    // +      input by: Josep Sanz (http://www.ws3.es/)
    // +    revised by: Rafa Kukawski (http://blog.kukawski.pl/)
    // %        note 1: Great work. Ideas for improvement:    // %        note 1:  - code more compliant with developer guidelines
    // %        note 1:  - for implementing PHP constant arguments look at
    // %        note 1:  the pathinfo() function, it offers the greatest
    // %        note 1:  flexibility & compatibility possible
    // *     example 1: round(1241757, -3);    // *     returns 1: 1242000
    // *     example 2: round(3.6);
    // *     returns 2: 4
    // *     example 3: round(2.835, 2);
    // *     returns 3: 2.84    // *     example 4: round(1.1749999999999, 2);
    // *     returns 4: 1.17
    // *     example 5: round(58551.799999999996, 2);
    // *     returns 5: 58551.8
        var m, f, isHalf, sgn; // helper variables        precision |= 0; // making sure precision is integer
        m = Math.pow(10, precision);
        value *= m;
        sgn = (value>0)|-(value<0); // sign of the number
        isHalf = value % 1 === 0.5 * sgn;
        f = Math.floor(value);
        
        if(isHalf){
                switch(mode){
                        case 'PHP_ROUND_HALF_DOWN':                                value = f + (sgn < 0); // rounds .5 toward zero
                                break;
                        case 'PHP_ROUND_HALF_EVEN':
                                value = f + (f % 2 * sgn); // rouds .5 towards the next even integer
                                break;                        case 'PHP_ROUND_HALF_ODD':
                                value = f + !(f % 2); // rounds .5 towards the next odd integer
                                break;
                        default:
                                value = f + (sgn > 0); // rounds .5 away from zero
                }
        }
        
        return (isHalf ? value : Math.round(value)) / m;
}


    var over = $('<div></div>')
        .css({
            'background-color': '#fff',
            'opacity': '.7',
            'color': '#B22D42',
            'font-size': '13px',
            'padding': '0px',
            'text-align': 'left'
        })

    $(this)
        .css('opacity', options.off)
        .each(function () {
            // setTimeout y su callback
            var sto = null
            var sto_function = null

            $(this)
                .mouseover(function () {
                    if($(this).data('__bopacity') == -1)
                        return

                    var t = null;
                    var img = $(this).find('img')

                    if((t = img.attr('title')) != '') {
                        img.attr('title', '')

                        if(over[0].parentNode && $(over[0].parentNode).data('__bopacity') == -1) {
                            $(over[0].parentNode)
                                .data('__bopacity', 0)
                                .css('opacity', options.off)
                        }
/*
                        over
                            .html($('<div style="padding: 3px 5px; ">' + t + '</div>'))
                            .appendTo(this)
*/
                        $(this).data('pzoom_title', t)
/*
                        over
                            .css({
                                'display': 'block',
                                'position': 'absolute',
                                'bottom': '0px',
                                'left': '0px',
                                'width': '100%'
                            })
*/
                    }
    
                    if(sto) {
                        clearTimeout(sto)
                        sto = null
                    }
    
                    $(this).data('__bopacity', -1)
        
                    // progresion
                    sto_function = (function (target) { return function () {
                        if(!$(target).data('__bopacity'))
                            return
    
                        var a_o = $(target).css('opacity')

                        var p =  options.p;
                        var n_o = 0;

                        var iterations = 50;
                        do {
                            
                            n_o = round((options.on - a_o) * p + parseFloat(a_o), 2);
                            p += .1;
                            iterations--

                        }while(a_o - n_o < 0.01 && iterations > 0);

                        if(n_o >= options.on || iterations == 0) {
                            $(target).css('opacity', options.on);
                            return;
                        }

                        $(target).css('opacity', n_o);
    
                        sto = setTimeout(sto_function, options.step)
    
                    }})(this)
    
                    sto_function();
        
                })
                .mouseout(function () {
                    if($(this).data('__bopacity') == 1)
                        return;

                    var t = $(this).data('pzoom_title');
                    var img = $(this).find('img')
                    if(t != '' && img.attr('title') == '') {
//                        over.css('display', 'none')
                        img.attr('title', t)
                        $(this).data('pzoom_title', '')
                    }
    
                    if(sto) {
                        clearTimeout(sto)
                        sto = null
                    }
    
                    $(this).data('__bopacity', 1)
    
                    sto_function = (function (target) { return function () {
                        if(!$(target).data('__bopacity'))
                            return
    
                        var a_o = $(target).css('opacity')

                        var p =  options.p;
                        var n_o = 0;
                        var iterations = 50;
                        do {
                            
                            n_o = round(a_o - (a_o - options.off) * p, 2);
                            p += .1;
                            iterations--;

                        }while(a_o - n_o < 0.01 && iterations > 0);

                        if(n_o <= options.off || iterations == 0) {
                            $(target).css('opacity', options.off);
                            $(target).data('__bopacity', 0)

                            return;
                        }
    
                        $(target).css('opacity', n_o);
    
                        sto = setTimeout(sto_function, options.step)
    
                    }})(this)
                    
                    sto_function();
                })
    })

    return this;   
}
