Greasy Fork

My Function library

enter something useful

目前为 2016-09-24 提交的版本。查看 最新版本

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.greasyfork.cloud/scripts/9160/149090/My%20Function%20library.js

"use strict";
//// ==UserScript==
// @name            My Function library
// @namespace       http://use.i.E.your.homepage/
// @version         0.45
// @description     enter something useful
// @grant           GM_getValue
// @grant           GM_setValue
// @grant           GM_deleteValue
// @grant           GM_listValues
// @grant           GM_xmlhttpRequest
// @run-at          document-start

// @created         2015-04-06
// @released        2014-00-00
// @updated         2014-00-00
// @history         @version 0.25 - first version: public@released - 2015-04-12
// @history         @version 0.30 - Second version: public@released - 2015-12-10
// @history         @version 0.35 - Second version: public@released - 2016-03-04
// @history         @version 0.45 - Second version: public@released - 2016-09-24
// @compatible      Greasemonkey, Tampermonkey
// @license         GNU GPL v3 (http://www.gnu.org/copyleft/gpl.html)
// @copyright       2014+, Magnus Fohlström
// ==/UserScript==

/*global $, jQuery*/
/*jshint -W014, -W030, -W082*/
// -W014, laxbreak, Bad line breaking before '+'
// -W030, Expected assignment or function call instead saw an expression
// -W082, a function declaration inside a block statement

/*
$("li").not(function() {
    // returns true for those elements with at least one span as child element
    return $(this).children('span').length > 0
}).each(function() { /* ...  })
*/
//noinspection JSUnresolvedFunction,JSUnresolvedVariable,BadExpressionStatementJS
    performance;

function setGM(){
    console.log('setGM' );
    window.GM_getValue      = function( key, def ){
        return localStorage[key] || def;
    };
    window.GM_setValue      = function( key, value ){
        localStorage[key] = value;
    };
    window.GM_deleteValue   = function( key ){
        delete localStorage[ key ];
    };
    window.GM_listValues    = function( ){
        return Object.keys( localStorage );
    };
    window.GM_lister        = function( remove, item ){
        var keys = window.GM_listValues(), i = 0, val;
        for ( i; i <= keys.length; i++ ) {
            val = keys[i];
            val !== undefined && (
                console.log( 'GM_ListItem: ' + val + ':', window.GM_getValue( val ) ),
                ( ( item !== undefined && val.inElem( item ) ) || item === undefined )
                && Boolean.parse( remove ) && window.GM_deleteValue( val ) );
        }
    };
}

console.log('isFunction( GM_getValue() )', $.isFunction( window.GM_getValue ) );

!!$.isFunction( window.GM_getValue ) || setGM();

(function(){

    var eventMatchers = {
        'HTMLEvents': /^(?:load|unload|abort|error|select|change|submit|reset|focus|blur|resize|scroll)$/,
        'MouseEvents': /^(?:click|mouse(?:down|up|over|move|enter|out))$/
    };

    var defaultOptions = {
        pointerX: 0,
        pointerY: 0,
        button: 0,
        ctrlKey: false,
        altKey: false,
        shiftKey: false,
        metaKey: false,
        bubbles: true,
        cancelable: true
    };

    jQuery.fn.simulate = function(eventName) {
        var element = this[0];
        var options = $.extend(true, defaultOptions, arguments[2] || { });
        var oEvent, eventType = null;

        for (var name in eventMatchers) {
            if (eventMatchers[name].test(eventName)) { eventType = name; break; }
        }

        if (!eventType)
            throw new SyntaxError('Only HTMLEvents and MouseEvents interfaces are supported');

        if (document.createEvent) {
            oEvent = document.createEvent(eventType);
            if (eventType == 'HTMLEvents') {
                oEvent.initEvent(eventName, options.bubbles, options.cancelable);
            }
            else {
                oEvent.initMouseEvent(eventName, options.bubbles, options.cancelable, document.defaultView,
                    options.button, options.pointerX, options.pointerY, options.pointerX, options.pointerY,
                    options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.button, element);
            }
            element.dispatchEvent(oEvent);
        }
        else {
            options.clientX = options.pointerX;
            options.clientY = options.pointerY;
            oEvent = $.extend(document.createEventObject(), options);
            element.fireEvent('on' + eventName, oEvent);
        }
        return element;
    };
})();

    window.onerror = function (errorMsg, url, lineNumber, column, errorObj) {
        console.debug('Error: ' + errorMsg + '\nScript: ' + url + '\nLine: ' + lineNumber
        + '\nColumn: ' + column + '\nStackTrace: ' +  errorObj);
    };
    /**
    *  @namespace waitUntilExists_Intervals
    */
    $.fn.waitUntilExists = function (handler, shouldRunHandlerOnce, isChild){
        var found	= 'found',
            $this	= $(this.selector),
            $elements	= $this.not(function () { return $(this).data(found); }).each(handler).data(found, true);
        if( !isChild ) {
            (window.waitUntilExists_Intervals = window.waitUntilExists_Intervals || {})[this.selector] =
                window.setInterval(function () {
                    $this.waitUntilExists(
                        handler, shouldRunHandlerOnce, true);
                }, 500);
        }
        else if (shouldRunHandlerOnce && $elements.length){
            window.clearInterval(window.waitUntilExists_Intervals[this.selector]);
        }
        return $this;
    };

    $.extend( $.easing,{
        easeOutBounceSmall : function(x, t, b, c, d) {
            var ts=(t/=d)*t;
            var tc=ts*t;
            return b+c*(-16.195*tc*ts + 49.935*ts*ts + -53.785*tc + 21.795*ts + -0.75*t);
        },
        easeOutSmoothBounce : function(x, t, b, c, d) {
            var ts=(t/=d)*t;
            var tc=ts*t;
            return b+c*(-19.4293*tc*ts + 53.3838*ts*ts + -49.8485*tc + 15.8081*ts + 1.08586*t);
        }
    });

    $.extend( $.fn, {
        // Name of our method & one argument (the parent selector)
        /**
         * Suppress all rules containing "unused" in this
         * class
         *
         * @SuppressWarnings("unused")
         */
        //noinspection JSUnusedProperty
        within: function( pSelector ) {
            // Returns a subset of items using jQuery.filter
            return this.filter(function(){
                // Return truthy/falsey based on presence in parent
                return $(this).closest( pSelector ).length;
            });
            /* Example
                $("li").within(".x").css("background", "red");

                This selects all list items on the document, and then filters to only
                those that have .x as an ancestor. Because this uses jQuery internally,
                you could pass in a more complicated selector:

                $("li").within(".x, .y").css("background", "red");

                http://stackoverflow.com/questions/2389540/jquery-hasparent
                http://stackoverflow.com/a/2389549
             */
        }
    });

    $.fn.extend({
        exists              : function () {
            return !!this.length;
        },
        Exists              : function ( callback ) {
            var self = this;
            var wrapper = (function(){
                function notExists(){}
                //noinspection JSPotentiallyInvalidConstructorUsage
                notExists.prototype.ExistsNot = function( fallback ){
                    !self.length && fallback.call(); };
                //noinspection JSPotentiallyInvalidConstructorUsage
                return new notExists;
            })();
            self.length && callback.call();
            return wrapper;

            /*  And now i can write code like this -
                $("#elem").Exists(function(){
                    alert ("it exists");
                }).ExistsNot(function(){
                    alert ("it doesn't exist");
                });
             */
        },
        ifExists            : function ( fn ) {
            this.length && fn( this );
            /*
                 $("#element").ifExists( function( $this ){
                    $this.addClass('someClass').animate({marginTop:20},function(){alert('ok')});
                 });
             */
        },
        swapClass           : function ( replace, newClass) {
            this.className.replace(replace, newClass);
        },
        toggleClasses       : function ( add, remove, if_none) {
            var $this = $(this.selector);
            if_none !== undefined && !$this.hasClass(add) && !$this.hasClass(remove) && $this.addClass(if_none);
            $this.addClass(add).removeClass(remove);
        },
        thisCompStyle       : function ( cssStyle ) {
            return cssStyle !== undefined ? this.getComputedStyle().getPropertyValue( cssStyle ) : this.getComputedStyle();
        },
        refreshElement      : function ( speed, parentBoolean ) {
            var $elem = parentBoolean ? this.parent() : this, data = $elem.html();
            $elem.hide( speed / 2 ).empty().html( data ).fadeIn( speed );
        },
        hasId               : function ( id ) {
            return id === this.attr('id');
        },
        hasClasses          : function ( classes, any ) {
            classes = classes.split( classes.inElem(',') ? ',' : ' ' );
            var check = 0, i = 0;
            for ( i; i < classes.length; i++ ) {
                this.hasClass( classes[ i ] ) && check++;
                if ( any !== undefined && check !== 0 ) return true;
            }
            return check === classes.length;
        },
        hasNoChildren       : function ( selection ) {
            return $( this ).filter( function(){
                return $( this ).children( selection ).length === 0;
            });
        },
        /*        hasParent       : function( parentSelection ){
         return parentSelection.inElem('#')
            ? this.parent().hasId( parentSelection.split('#').shift() )
            : this.parent().hasClass( parentSelection.split('.').shift() );
         },
         */
        hasAncestor         : function ( Ancestor ) {
            return this.filter(function() {
                return !!$( this ).closest( Ancestor ).length;
            });
            //$('.element').hasAncestor('.container').myAction();
        },
        hasParent           : function ( selection ) {
            return !!$( this ).parent( selection ).length;
        },
        hasParents          : function ( selection ) {
            return !!$( this ).parents( selection ).length;
        },
        hasQuery            : function ( query ) {
            return d.querySelector(query).length;
        },
        hasAttr             : function ( name, val ) {
            var thisAttr = $( this ).attr( name );
            thisAttr =
                val !== undefined
                    ? thisAttr === val
                    : thisAttr;
            return ( typeof thisAttr !== "undefined" && thisAttr !== false && thisAttr !== null );

            //return val !== undefined
            //    ? attrName === val
            //    : typeof( attrName ) !== 'undefined';  //$( this )[0].hasAttribute( name );
        },
        isTag               : function ( tag ) {
            var e = this[0] || $('<undefined/>');
            //noinspection JSValidateTypes
            return e.nodeName !== undefined && e.nodeName.toLowerCase() === tag.toLowerCase();
        },
        isNode              : function ( node ) {
            var e = this[0] || $('<undefined/>');
            //noinspection JSValidateTypes
            return e.nodeName !== undefined && e.nodeName.toLowerCase() === node.toLowerCase();
        },
        searchAttr          : function ( search, type, chkLen ) { //bool name value length or 1 2 3 4
            var Attributes = this[0].attributes;
            c.i('Attributes', Attributes);
            if ( arguments.length === 0 ) {
                var obj = {};
                $.each( Attributes, function() {
                    this.specified && ( obj[ this.name ] = this.value );
                });
                return obj;
            } else if( search !== undefined ) {
                var name = '', val = '';
                //noinspection FunctionWithInconsistentReturnsJS
                $.each( Attributes, function() {
                    if( this.specified && type == 'length' ) {
                        if( this.name.length > chkLen ) {
                            name = this.name;
                            return false;
                        }
                    }
                    else if( this.specified && this.name.inElem( search ) ) {
                        name = this.name;
                        val = this.value;
                        return false;
                    }
                });
                return ( type == 'bool' || type == 1 ) ? name.length ? true : false :
                       ( type == 'name' || type == 2 ) ? name :
                       ( type == 'value' || type == 3 ) ? val :
                       ( type == 'length' || type == 4 ) && name;
            }
        },
        findClass           : function ( Class ) {
            return this.find('.' + Class);
        },
        href                : function ( newURL ) {
            return arguments.length === 0 ? this.attr('href') : this.attr('href', newURL);
        },
        src                 : function ( newSRC ) {
            return arguments.length === 0 ? this.attr('src') : this.attr('src', newSRC);
        },
        equals              : function ( compareTo ) {
            if (!compareTo || this.length != compareTo.length)
                return false;

            for (var i = 0; i < this.length; ++i) {
                if (this[i] !== compareTo[i])
                    return false;
            }
            return true;
        },
        justText            : function ( newText, prepend ) {
            var $children = null,
                placement = prepend === undefined ? 'prepend':'append';
            if ( newText ) {
                $children = $( this )
                    .children()
                    .clone();
                $( this )
                    .children()
                    .remove()
                    .end()
                    .text( newText )
                    [ placement ]( $children );
                return $(this);
            }
            else {
                return $.trim( $( this )
                    .clone()
                    .children()
                    .remove()
                    .end()
                    .text());
            }
        },
        uncomment           : function ( recurse ) {
           // <!-- hidden --> // this will reveal, whats inside. In this case it will bi the word hidden
            $( this ).contents().each(function() {
                if ( recurse && this.hasChildNodes() ) {
                    $( this ).uncomment(recurse);
                } else if ( this.nodeType == 8 ) {
                    // Need to "evaluate" the HTML content,
                    // otherwise simple text won't replace
                    var e = $('<span>' + this.nodeValue + '</span>');
                    $( this ).replaceWith( e.contents() );
                }
            });
            // $('#uncomment').uncomment( true );
            // http://stackoverflow.com/a/22439787
        },
        getComment          : function ( getValue ) {
            var COMMENT_NODE = this.contents().filter(function(){
                return this.nodeType == Node.COMMENT_NODE;
            });
            return getValue ?
                   COMMENT_NODE.each(function(){
                       return $( this ).nodeValue.str2html();
                   })
                   : COMMENT_NODE;
        },
        //$.get('defaultComp/foot.html', function(dataContent) {$('#foot').replaceWith(dataContent); });
        getURL          : function ( url, how ) {
            how = how || 'html';
            var that = this;
            $.get( url, function(dataContent) {
                $(that)[ how ](dataContent);
            });
            return this;
        },

        hasEvent            : function ( event ) {
            var eventHandlerType;
            $( this ).on( event, clickEventHandler ).triggerHandler( event );
            function clickEventHandler( e ) {
                eventHandlerType = e.type;
            }
            return eventHandlerType === event;
        },
        scrollTune          : function ( opt  ){
            // $("body").scrollTune({ pps: 1700, pageY: config.pageY, easing:'easeOutSmoothBounce', hsc: true }).promise()
            //          .done( function() { setTimeout(function(){ toggleClassState( config, 'fullPlayer', type ); },100); })

            console.log('scrollTune');

            var position,
                defaults 		= {
                    tune:		0,
                    speed:		0,
                    pps:        false, // pixel per second
                    ppsM:		1000,
                    pageYmini:	0,
                    pageY:      false, //{ pps: 300, pageY: event.pageY }
                    hsc:		false, // height speed compensation
                    animate:	false,
                    // require	http://gsgd.co.uk/sandbox/jquery/easing/jquery.easing.1.3.js or jQueryUI - if other than ' swing or linear '
                    easing:     "easeInOutCubic", // easeInOutCubic  easeInOutQuad  easeInOutElastic http://easings.net/
                    delay:		0,
                    varStore:	'',
                    varAltStore:false,
                    name:		false,
                    start:   	false,
                    startTime: 	0,
                    step:   	false,
                    stepTime: 	0,
                    complete:   false,
                    completeTime: 0,
                    done:   	false,
                    doneTime: 	0,
                    goTo:		$('body')
                },
                heightSpeedComp	= function(){ return opt.hsc ? 1 + ( ( $(document).height() / opt.pageY ) / 1.4 ) : 1 ; },
                varStore = function( action, step ){
                    opt.name !== false
                        ? opt.varAltStore !== false
                            ? (console.log('Store'), opt.varAltStore[opt.name][ action ](step))
                            : (console.log('Store false'), opt.name[ action ](step))
                        : opt.pageYmini < opt.pageY || opt.varStore === config
                            ? (console.log('config'), opt.varStore[ action ](step))
                            : (console.log('config false'), opt.varStore(step));
                };

            console.log('opt.pageY',opt.pageY);
            opt = $.extend( {}, defaults, opt );
            position = ( $( this ).offset().top + opt.tune ) + 'px';

            opt.pps !== false || opt.animate !== false || ( typeof opt.speed === 'string' ? opt.speed.length !== 0 : opt.speed !== 0 )
                ? (
                opt.speed = opt.pps !== false ? parseInt( ( opt.pageY / opt.pps * heightSpeedComp() ) * opt.ppsM ) : opt.speed,
                    opt.goTo.delay( opt.delay ).animate(
                        { scrollTop	: position },
                        { duration	: opt.speed, easing: opt.easing,
                            start		: function(){
                                opt.start && setTimeout(function(){
                                    console.log('start');
                                    varStore('start');
                                }, opt.startTime );
                            },
                            step		: function(i){
                                opt.step && setTimeout(function(){
                                    console.log('step',i);
                                    varStore('step',i);
                                }, opt.stepTime );
                            },
                            complete	: function(){
                                opt.complete && setTimeout(function(){
                                    console.log('complete');
                                    varStore('complete');
                                }, opt.completeTime );
                            },
                            done		: function(){
                                opt.done && setTimeout(function(){
                                    console.log('done');
                                    varStore('done');
                                }, opt.doneTime );
                            }
                        }
                    )
                )
                : opt.goTo.scrollTop( position );

            return this; // for chaining...

        },
        scrollTuneOld       : function ( opt ){

            var position,
                defaults = {
                    tune:		0,
                    speed:		512,
                    animate:	false,
                    goTo:		$('html, body')
                };

            opt = $.extend( {}, defaults, opt );
            position = ( $( this ).offset().top + opt.tune ) + 'px';

            opt.animate !== false || ( typeof opt.speed === 'string' ? opt.speed.length !== 0 : opt.speed !== 0 )
                ? opt.goTo.animate({ scrollTop: position }, opt.speed )
                : opt.goTo.scrollTop( position );

            return this; // for chaining...
        },
        qUnWrap             : function (){
            $( this ).find(':first-child').unwrap();
        }
    });

    $.extend({
        confirm: function (title, message, yesText, noText, yesCallback) {
            //dialog needs jQueryUI
            /*
             $.confirm(
             "CONFIRM", //title
             "Delete " + filename + "?", //message
             "Delete", //button text
             deleteOk //"yes" callback
             );
             */
            $("<div></div>").dialog( {
                buttons: [{
                    text: yesText,
                    click: function() {
                        yesCallback();
                        $( this ).remove();
                    }
                },
                    {
                        text: noText,
                        click: function() {
                            $( this ).remove();
                        }
                    }
                ],
                close: function (event, ui) { $(this).remove(); },
                resizable: false,
                title: title,
                modal: true
            }).text(message).parent().addClass("alert");
        }
    });
    $.extend( $.expr[":"], {
        ldata: function(el, idx, selector) {
            var attr = selector[3].split(", ");
            return el.dataset[attr[0]] === attr[1];
        },
        value: function(el, idx, selector) {
            return el.value === selector[selector.length - 1];
        },
        isEmptyTrimmed: function(el){
            return !$.trim($(el).html());
        },
        data: $.expr.createPseudo
            ? $.expr.createPseudo(function( dataName ) {
                  return function( elem ) {
                      return !!$.data( elem, dataName );
                  };
              })
              // support: jQuery <1.8
            : function( elem, i, match ) {
                  return !!$.data( elem, match[ 3 ] );
              }
        });

    $.isInArray = function( item, array ) {
        return !!~$.inArray(item, array);
    };
    $.allVar = function( array, value, all, atLeast ) {
        var count = 0,
            arrLength = array.length,
            isBool = typeof value === 'boolean';

        $.each( array, function( i, e ){
            value === ( isBool ? !!e : e ) && count++;
        });

        return all ? count === arrLength : count >= atLeast;
    };
/*
   Object.defineProperty(HTMLMediaElement.prototype, 'playing', {
        //$( selector ).get(0).playing;
        get: function(){
            return !!( this.currentTime > 0 && !this.paused && !this.ended && this.readyState > 2 );
        }
    });
    */
 /*   Object.prototype.hasAttribute   = function( attrName, val ){
        var thisAttr =
                this.attr
                    ? val !== undefined
                        ? this.attr( attrName ) === val
                        : this.attr( attrName )
                    : this.getAttribute( attrName );
        return ( typeof thisAttr !== "undefined" && thisAttr !== false && thisAttr !== null );
    };
*/
    Array.prototype.findArrayObj    = function( findKey, exactValue ){
        return $.grep( this, function( obj ){
            return obj[ findKey ] === exactValue;
        })[0];
        //This prototype doesn't modify the array,
        // it gets the element that contains key with correct value and
        // the returns that element
    };
    Array.prototype.removeArrayObj  = function( findKey, exactValue ){
        //my own example test:  http://jsfiddle.net/aPH7m/82/
        //This prototype doesn't modify the array, needs to be overwritten or put into new var array
        return $.grep( this, function( obj ) {
            return obj[ findKey ] !== exactValue;
        });
    };
    Array.prototype.addKeyToArrayObj = function( findKey, exactValue, newKey, newValue ){
        return $.grep( this, function( obj ){
            return obj[ findKey ] === exactValue ? obj[ newKey ] = newValue : obj[ findKey ] !== exactValue;
        });
        // This prototype doesn't modify the array,
        // it gets the element that contains key with correct value and
        // adds a new key with its value to that element
    };

    Array.prototype.filterArrayObj  = function( doWhat, findKey, exactValue, newKey, newValue ){
        return  doWhat === 'remove'
            ? this.filter(function( obj ) {
                    return obj[ findKey ] !== exactValue;
              })
            : doWhat === 'addKey'
                    ? this.filter(function( obj ){
                            return obj[ findKey ] === exactValue
                                ?  obj[ newKey ]  = newValue
                                :  obj[ findKey ] !== exactValue;
                      })
                    : doWhat === 'find'
                        && this.filter(function( obj ){
                            return obj[ findKey ] === exactValue;
                          })[0];
    };
    Array.prototype.grepArrayObj    = function( doWhat, idKey, uniqueValue, theKey, theValue ){
        doWhat = doWhat === 'updateKey' ? 'addKey' : doWhat;
        return doWhat === 'remove'
            ?     $.grep( this, function( obj ){
                return obj[ idKey ] !== uniqueValue;
            })
            :  doWhat === 'addKey'
                ? $.grep( this, function( obj ){
                    return obj[ idKey ] === uniqueValue
                        ? (
                               obj[ theKey ] = theValue,
                               obj[ idKey ] === uniqueValue
                           )
                        : obj[ idKey ] !== uniqueValue;
                  })
            :  doWhat === 'find'
                ? $.grep( this, function( obj ){
                    return obj[ idKey ] === uniqueValue;
                    })[0]
            :  doWhat === 'deleteKey'
                && $.grep( this, function( obj ){
                    return obj[ idKey ] === uniqueValue
                        ? (
                              delete obj[ theKey ],
                              obj[ idKey ] === uniqueValue
                          )
                            : obj[ idKey ] !== uniqueValue;
                });
    };
    Array.prototype.sortObjArray    = function( key, reverse ){
        this.sort(function(a, b){
            return ( reverse || false ) ? b[key] - a[key] : a[key] - b[key];
        });
    };

    //noinspection JSPrimitiveTypeWrapperUsage
    Boolean.parse                   = function(val) {
    //    http://stackoverflow.com/a/24744599
        var falsely = /^(?:f(?:alse)?|no?|0+)$/i;
        return !falsely.test(val) && !!val;
    };


/*
	Object.prototype.isObjectType   = function( type, showType ){ //"[object Number]"
		var objectString = Object.prototype.toString.call( this );
		return  showType === 'show' ? objectString :
				showType === 'exact' ? objectString === type :
				showType === 'search' && objectString.toLowerCase().inElem( type.toLowerCase() );
	};
*/

    String.prototype.splitEvery     = function( splitter, every ){
        var array = this.split( splitter ), returnString = '';
        $.each( array, function( index, elem ){
            returnString += elem + ( index < array.length - 1 || index % every === 0 ) ? '' : splitter;
        });
        return returnString;
    };
    String.prototype.advSplit       = function( chr, nbr ){
            var str = this.split(chr),
                strLen = str.length,
                chrLen = chr.length,
                returnStr = ['',''],
                newArr = [];

            $.each( str, function( index ){
                returnStr[ index < nbr ? 0 : 1 ] += str[ index ] + chr;
            });

            $.each( returnStr, function( index ){
                returnStr[ index ] = returnStr[ index ].slice(0, - chrLen);
                returnStr[ index ].length > 0 && newArr.push( returnStr[ index]  );
            });

            return newArr;
        };
    String.prototype.advSplitJoin   = function( chr, nbr, ips ){

        var str = this.split(chr),
            strLen = str.length,
            ipsLen = ips.length,
            returnStr = '',
            returnStrLen;

        $.each( str, function( index ) {
            var add = index < strLen - 1
                ? chr
                : '';
            returnStr += index + 1 === nbr
                ? str[index] + ips
                : str[index] + add;
        });

        returnStrLen = returnStr.length;
        returnStr.slice( returnStrLen - ipsLen ) === ips
            && ( returnStr = returnStr.slice( 0, returnStrLen - ipsLen ) );

        return returnStr;
    };
    String.prototype.extract        = function( start, end, inside, newWay ){
        var str = this,
            myArray = [ true, 1, 'yes', 'inside' ],
            startCharIndex = str.indexOf( start ),
            endCharIndex = str.indexOf( end );

        newWay = newWay !== undefined ? $.inArray( newWay, myArray ) !== -1 : false;
        inside = inside !== undefined ? $.inArray( inside, myArray ) !== -1 : false;

        function simpler() {
            return inside
                ? str.split( start ).pop().split( end ).shift()
                : start + str.split( start ).pop().split( end ).shift() + end;
        }
        function older() {
            return inside //old buggy way, some old scripts may depends on it
                ? str.replace( start, '').replace( end, '')
                : str.substr( startCharIndex, endCharIndex );
        }
        return newWay ? simpler() : older()
    };
    String.prototype.extractNew     = function( start, end, inside ){
        var str = this;
        return inside !== undefined && inside
            ? str.split( start ).pop().split( end ).shift()
            : inside
               || start + str.split( start ).pop().split( end ).shift() + end;
    };

    String.prototype.charTrim       = function( char ){
        // alert("...their.here.".charTrim('.'));
        var first_pos = 0,
            last_pos = this.length- 1, i ;
        //find first non needle char position
        for( i = 0; i < this.length; i++ ){
            if( this.charAt( i ) !== char ){
                first_pos = ( i == 0 ? 0 : i );
                break;
            }
        }
        //find last non needle char position
        for( i = this.length - 1; i > 0; i-- ){
            if( this.charAt( i ) !== char ){
                last_pos = ( i == this.length ? this.length: i + 1 );
                break;
            }
        }
        return this.substring( first_pos, last_pos );
    };
    String.prototype.reduceWhiteSpace = function(){
        return this.replace(/\s+/g, ' ');
    };
    String.prototype.formatString   = function(){

        var inputStr = this.toString().reduceWhiteSpace()
                .split('!').join(' !').split('!;').join("!important;")
                .split(/\s+/g).join(' ')
                .split('{').join('{\n\t')
                .split('; ').join(';')



                .split('( ').join('(')
                .split(' )').join(')')

                .split(' :').join(':')

                .split(';').join(';\n\t')
                .split('*/').join('*/\n')
                .split(')*(').join(') * (')
                .split('}').join('}\n'),
            returnStr = '\t', pop;

        $.each( inputStr.split('\n'), function ( i, elem ) {

            elem.search( '{' ) === -1 && elem.search( ': ' ) === -1
	            && ( elem.search( ':' ) > 1
	                ? ( pop = elem.split(': ').join(':').split( ':' ).pop(), elem = elem.split( pop ).shift() + ' ' + pop )
	                : elem.search(':') === 1 && ( elem = elem.split(': ').join(':').split( ':' ).join( ': ' ) ) );
            //    : elem.search( '{' ) === 1 && ( elem.search( ': ' ) !== -1 || elem.search( ' :' ) !== -1 || elem.search( ' : ' ) !== -1 )
            //        && ( elem = elem.split( ': ' ).join( ' :' ).split( ' :' ).join( ':' ).split( ' : ' ).join( ': ' ) );

            returnStr += elem + '\n\t';
        });
	    returnStr = returnStr.split('>').join(' > ').split('  >  ').join(' > ').split( ': //' ).join( '://' ).split( ':url' ).join( ': url' );
        return returnStr.slice( 0, returnStr.lastIndexOf('}') ) + '}';
};

	/**
	 * Parses mixed type values into booleans. This is the same function as filter_var in PHP using boolean validation
	 * //@returny {Boolean|Null}
	 */
	String.prototype.parseBooleanStyle = function( nullOnFailure ){
		nullOnFailure = nullOnFailure || false;
		var bool, $this = this.toString().toLowerCase();
		switch( $this ){
			case 'true':
			case '1':
			case parseInt( $this ) > 0:
			case 'on':
			case 'yes':
				bool = true;
				break;
			case 'false':
			case '0':
			case 'off':
			case 'no':
				bool = false;
				break;
			default:
				bool = nullOnFailure ? null : false;
				break;
		}
		return bool;
	};
	String.prototype.parseBool      = function(){
		var thisStr = parseInt( this ) ? this === 0 ? 'false' : 'true' : '' + this,
			trueArray = [ 'on', 'yes','y', 'j', 'true', true ],
			falseArray = [ 'off', 'no', 'n', 'false', false ];

		thisStr = thisStr.toLowerCase().trim();

		return  $.inArray( thisStr, trueArray ) !== -1 ? true :
			$.inArray( thisStr, falseArray ) !== -1 ? false : this;
	};
    String.prototype.isType         = function( type ){
        return !!$.type( this ) === type;
    };
    String.prototype.undef          = function( replace ){
        return this === undefined ? replace : this;
    };
    String.prototype.isUndefined    = function( state, replace ){
        state = state !== undefined ? state : true;
        replace = replace !== undefined ? replace : true;
        return state ? this === undefined ? replace : this : state;
    };

    String.prototype.inURL          = function(){
        var winLoc = window.location.href;
        return winLoc.search(this) !== -1;
    };
    String.prototype.inString       = function( string ){
        return string !== undefined ? string.search(this) !== -1 : false;
    };
    String.prototype.inElem         = function( search ){
        return this !== undefined ? this.search(search) !== -1 : false;
    };
    String.prototype.count          = function( char, UpperCase ){
        var numberOf = this.toString().match( new RegExp( char, ( UpperCase ? "gi" : "g" ) ) );
        return numberOf != null ? numberOf.length : 0;
    };
    String.prototype.startsWith     = function( str ){
        return this.slice(0, str.length) == str;
    };
    String.prototype.removeStarts   = function( many ){
        return this.substring( many - 1, this.length );
    };
    String.prototype.removeEnds     = function( many ){
        return this.substring( 0, this.length - many );
    };
    String.prototype.endsWith       = function( str ){
        return this.slice( -str.length ) == str;
    };
    String.prototype.capitalizeFirst = function(){
        return this.charAt(0).toUpperCase() + this.slice(1);
    };
    String.prototype.lpad           = function( padString, length ){
        var str = this;
        while ( str.length < length ) {
            str = padString + str; }
        return str;
    };

    // use full to convert String URL, so that you can use location commands
    String.prototype.toLocation     = function(){
        var a = document.createElement('a');
        a.href = this;
        return a;
    };
    String.prototype.str2html       = function(){
        return $('<div/>').html( this ).contents();
    };
    String.prototype.toStyle        = function( styleId ){
        var cssID,
            cssSplit = this.split('¤'),
            cssStyled = cssSplit.pop().formatString();
        styleId = styleId !== undefined ? styleId : cssSplit.shift();
        cssID = $( 'head #' + styleId );
        cssID.length
            ? cssID.html( cssStyled )
            : $( $( '<style/>',{ id: styleId, class:'mySuperStyles', html: cssStyled } ) ).appendTo('head');
    };

    //HTMLObjectElement.prototype.obj2Str = function(){var objArr = $.makeArray( this ); return objArr[0].outerHTML;};
    /*
    String.prototype.replaceAll = function( target, replacement ) {
        return this.split(target).join(replacement);
    };
*/
    function ScrollZoomTune( selection, zooms, tune, ani, speed ){
        //ScrollZoomTune("div.thumb .title a",1,-25,1,'slow');
        var body = $('body'), sel = $( selection), position;
        //noinspection JSValidateTypes
        sel.size() !== 0 && (
            body.css('zoom',zooms),
                position = sel.position().top + tune,
                ani === 1
                    ? body.animate({ scrollTop: position * zooms }, speed )
                    : body.scrollTop( position * zooms )
        );
    }
    function refreshElement( elem , speed ){ //refreshElement('.videoPlayer','slow');
        var $elem = $( elem ), data = $elem.html();
        $elem.empty().html( data ).fadeIn( speed );
    }
    function autoCopyToClipboard( input ){
        var $copyThis = $( '#copyThis' );
        $( 'body' ).append( $('<textarea/>',{ id:'copyThis', rows:"4", cols:"50", type:"text", value: input }) );
        $copyThis.focus().select();
        document.execCommand("copy");
        $copyThis.remove();
    }
    function toStyle( styleId, str ){
        var $id = $( 'head #' + styleId ),
            cssID = str.formatString();
        $id.length
            ? $id.html( cssID )
            : $( $( '<style/>',{ id: styleId, class:'mySuperStyles', html: cssID } ) ).appendTo('head');
    }
    function obj2Str( obj ){
        var objArr = $.makeArray(obj);
        return objArr[0].outerHTML;
    }

    function sortBy(key, reverse) {
        // Usage: array.sort( sortBy( key, reverse ) )

        // Move smaller items towards the front
        // or back of the array depending on if
        // we want to sort the array in reverse
        // order or not.
        var moveSmaller = reverse ? 1 : -1;
            // Move larger items towards the front
            // or back of the array depending on if
            // we want to sort the array in reverse
            // order or not.
        var moveLarger = reverse ? -1 : 1;
        /**
         * @param  {*} a
         * @param  {*} b
         * @return {Number}
         */
        return function (a, b) {
            if (a[key] < b[key]) {
                return moveSmaller;
            }
            if (a[key] > b[key]) {
                return moveLarger;
            }
            return 0;
        };
    }

    function VideoTitleA( elem , state ){
        //VideoTitleA("div.thumb .title a",'on');
        $( elem ).each(function(){
            var $this    = $(this),
                strTitle = $this.attr('title'),
                strText  = $this.attr('data-text'),
                strHtml  = $this.text();
            state === 'on' ? $this.text(strTitle).attr('data-text',strHtml) : $this.text(strText);
        });
    }
    /**
     * @return {string}
     */
    function MultiString( f ){
        return f.toString().split('\n').slice(1, -1).join('\n');
    }
    function wrapWithTag( tag, text, selection ){
        var thisAttr = selection !== undefined && selection.startsWith('.') ? 'class' : selection.startsWith('#') && 'id',
            thisTag = $('<' + tag + '/>', { text: text });
        return thisAttr.length ? thisTag.attr( thisAttr, selection.splice( 1 ) ) : thisTag;
    }

    function clean( node ) {
        /*
         So to clean those unwanted nodes from inside the <body> element, you would simply do this:

         clean(document.body);
         Alternatively, to clean the entire document, you could do this:

         clean(document);
         */
        for( var n = 0; n < node.childNodes.length; n ++ ){
            var child = node.childNodes[ n ];
            ( child.nodeType === 8 || ( child.nodeType === 3 && !/\S/.test( child.nodeValue ) ) )
                ? (
                    node.removeChild( child ),
                    n --
                )
                : child.nodeType === 1 && clean( child );
        }
    }
    function commentsCleaner( array ){
        array = array === undefined ? [ '*', document, 'html' ] : array;

        // https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
        // http://stackoverflow.com/a/2364760
        $.each( array, function( i, e ) {
            $( e ).contents().each( function() {
                this.nodeType === Node.COMMENT_NODE  && $( this ).remove(); }); });
    }

    function newUrlNoReload( title, url ){
        window.history.pushState("string", title, url );
    }
    function inURL( search, exact ){
        exact = exact || false;
        var winLoc = window.location.href;

        
        return exact ? winLoc === search : winLoc.search( search ) !== -1;
    }
    function loadDoc( href ){
        $( location ).attr('href', href );
    }

    function isPrimitiveType( value ){
        // will return true if the value is a primitive value
        switch ( typeof value ) {
            case 'string': case 'number': case 'boolean': case 'undefined': {
            return true;
        }
            case 'object': {
                return !value;
            }
        }
        return false;
    }
    function checkDividedIsInteger( num, div ){
        return ( num % div === 0 );
    }
    function isEven( value ){
        return ( value % 2 === 0 );
    }
    function inDom( array, onElement ) {
        var found = false,
            isArrayFN = function(){
                $.each( array, function( i, value ) {
                    value = onElement !== undefined
                        ? onElement + value
                        : value;
                    if( $( value ).length ) {
                        found = true;
                        return false;
                    }
                });
            };

        $.isArray( array )
            ? isArrayFN()
            : $( array ).length && ( found = true );

        /**
         * @return {boolean}
         */
        return found;
    }
    function isHTMLObject( obj ){
        obj = typeof obj == 'string' ? obj : $( obj );
        return obj.length
            ? !!( obj instanceof HTMLElement || obj[0] instanceof HTMLElement)
            : !!( obj && ( obj.nodeName || ( obj.prop && obj.attr && obj.find ) ) );
    }

    function isFunction( functionToCheck ){
        var getType = {};
        return functionToCheck && getType.toString.call( functionToCheck ) === '[object Function]';
    }
    function isNumeric( value ){
        return /^\d+$/.test( value );
    }

    function parseBoolean( Boolean , Type ) {
        //    http://stackoverflow.com/a/24744599
        Type = Type || false;
        var falsely = /^(?:f(?:alse)?|no?|0+)$/i,
            truely = /^(?:t(?:rue)?|yes?|1+)$/i;
        return Type ? !truely.test( Boolean ) && !!Boolean : !falsely.test( Boolean ) && !!Boolean;
    }
	function parseBooleanStyle( str, nullOnFailure ){
		nullOnFailure = nullOnFailure || false;
		var bool, $this = str.toString().toLowerCase();
		$this = parseInt( $this ) > 0 ? parseInt( $this ) : $this;
		console.log('parseBooleanStyle',$this);
		switch( $this ){
			case 'true':
			case '1':
			case parseInt( $this ) > 0:
			case 'on':
			case 'yes':
				bool = true;
				break;
			case 'false':
			case '0':
			case 'off':
			case 'no':
				bool = false;
				break;
			default:
				bool = nullOnFailure ? null : false;
				break;
		}
		return bool;
	}
    function getsComputedStyle( style, elem ) {
        elem = elem || 'body';
        return window.getComputedStyle( document[ elem ] )[ style ] !== undefined;
    }
    function isPropertySupported( property, elem ){
        elem = elem || 'body';
        return property in document[ elem ].style;
    }
    function cssPropertyValueSupported( prop, value, elem ) {
        //cssPropertyValueSupported('width', '1px');
        elem = elem || 'div';
        var d = document.createElement( elem );
        d.style[ prop ] = value;
        return d.style[ prop ] === value;
    }

    var cssSupports = (function(){
        // http://code.tutsplus.com/tutorials/quick-tip-detect-css3-support-in-browsers-with-javascript--net-16444
        var div = document.createElement('div'),
            vendors = 'Khtml Ms O Moz Webkit'.split(' '),
            len = vendors.length;

        return function(prop) {
            if ( prop in div.style ) return true;

            prop = prop.replace(/^[a-z]/, function(val) {
                return val.toUpperCase();
            });

            while(len--) {
                if ( vendors[len] + prop in div.style ) {
                    // browser supports box-shadow. Do what you need.
                    // Or use a bang (!) to test if the browser doesn't.
                    return true;
                }
            }
            return false;
        };
    })();

    function toggleClassState( config, Class, state, elem ){

        config === undefined ? window.config = {} : config;
        config = config || ( window.config = {} );
        
        config[ Class ] = typeof state === 'string' ? !config[ Class ] : state;
        $( elem || 'html' )[ config[ Class ] ? 'addClass' : 'removeClass' ]( Class );

    }
    function filterClick( e, $this ){
        return e.which == 1 && e.target == $this;
    }
    function dispatchEventResize() {
        //noinspection JSClosureCompilerSyntax,JSUnresolvedFunction
        window.dispatchEvent(new Event('resize'));
    }

    /**
     * @return {string}
     */
    function Undefined( check, replace ){
        return check === undefined ? replace.toString() : check.toString();
    }

    function getGlobal(){
        return (function(){
            return this;
        })();
    }
    function GM_lister( remove, item ){
        var keys = GM_listValues();
        for (var i = 0, key = null; key = keys[i]; i++) {
            GM_listValues()[i] !== undefined && (
                c.i('GM_ListItem: ' + GM_listValues()[i] + ':', GM_getValue(key)),
              ( ( item !== undefined && GM_listValues()[i].inElem( item ) ) || item === undefined )
                    && ( remove === true || remove === 'yes' || remove === 1 ) && GM_deleteValue(key));
        }
    }

    function roundFloat( num, dec ){
        var d = 1;
        for ( var i=0; i<dec; i++ ){
            d += "0";
        }
        return Math.round(num * d) / d;
    }
    function randomFloatBetween( min, max, dec ){
        dec = typeof( dec ) == 'undefined' ? 2 : dec;
        return parseFloat( Math.min( min + ( Math.random() * ( max - min ) ), max ).toFixed( dec ) );
    }
    function random( max ) {
        var min = 1,
            rand = function(){
                return Math.floor( Math.random() * ( max - min + 1 ) + min );
            },
            num1 = rand(),
            num2 = rand();

        return ( num1 > num2 ? num2/num1 : num1/num2 ) * max;
    }
    function roundNearPeace( number, peaces, dec ) {
        return ( Math.round( number * peaces ) / peaces ).toFixed( dec );
    }

    var w = window,
        glob = w,
        $w = $( w ),
        $l = $( location ),
        locDoc = window.location.href,
        d = document,
        $d = $( d ),

        c = {
            defaultState: 3,
            cute : function( type, msg, color ) {
                color = color || "black";
                var newColor, bgc = "White";
                switch ( color ) {
                    case "success":  newColor = "Green";      bgc = "LimeGreen";       break;
                    case "info":     newColor = "DodgerBlue"; bgc = "Turquoise";       break;
                    case "error":    newColor = "Red";        bgc = "Black";           break;
                    case "start":    newColor = "OliveDrab";  bgc = "PaleGreen";       break;
                    case "warning":  newColor = "Tomato";     bgc = "Black";           break;
                    case "end":      newColor = "Orchid";     bgc = "MediumVioletRed"; break;
                    default: //noinspection SillyAssignmentJS
                        newColor = color;
                }

                typeof msg == "object" ?
                    window.console[ type ]( msg )
                : typeof color == "object" ? (
                        window.console[ type ]("%c" + msg, "color: PowderBlue;font-weight:bold; background-color: RoyalBlue;"),
                        window.console[ type ]( newColor )
                    ) :
                    window.console[ type ]("%c" + msg, "color:" + newColor + "; background-color: " + bgc + ";");
            },
            show: function( showThis, type ){
                var State = GM_getValue( type + 'StateValue' ) || this.defaultState;
                return showThis !== 0 && State !== 0 && State === ( showThis || State ) || State === 'all';
            },
            pre: function( type, name, fn, line, color ){
                line = line == undefined ? '' : line + ': ';
                /**
                 * @return {string}
                 */
                var Fn = function(){ return fn !== undefined ? fn : ''; };
                typeof fn == "object" 
                    ? window.console[ type ]( name, Fn() ) 
                    : c.cute( type, line + name + ': ' + Fn(), color );
            },
            type: function( type, name, fn, line, color, showThis ){
                this.show( showThis, type ) && this.pre( type, name, fn, line, color );
            },
            l: function( name, fn, line, color, showThis ){
                this.type( 'log', name, fn, line, color, showThis );
            },
            h: function( name, fn, line, color, showThis ){
                this.type( 'handled', name, fn, line, color, showThis );
            },
            //c.l('name', 'fn'=='fn', 'line', 'blue')
            i: function( name, fn, line, color, showThis ){
                this.type( 'info', name, fn, line, color, showThis );
            },
            d: function( name, fn, line, color, showThis ){
                this.type( 'debug', name, fn, line, color, showThis );
            }
        },
        localStorageObj = {
            name        : 'setName', //important
            localArray  : function(){
                return window.localStorage.getItem( this.name );
            },
            getArray    : function(){
                return this.localArray() === null ? [] : JSON.parse( this.localArray() );
            },
            stringify   : function( array ){
                c.i('[stringify]', JSON.stringify(array) );
                window.localStorage.setItem( this.name, JSON.stringify(array) );
            },
            check       : function( key, value ){
                var array = this.getArray();
                return array.grepArrayObj('find', key, value );
            },
            viewConsole : function( json ){
                var array = this.getArray();
                // $.toJSON() --- https://github.com/Krinkle/jquery-json/blob/master/src/jquery.json.js
                // array.join('\n');
                c.d( this.name, array ); //debug mode important to make this work
                c.i( this.name, json ? isFunction( $.toJSON() ) ? $.toJSON( array ) : JSON.stringify( array ) : array.toSource() );
            },
            addTo       : function() {
                
            },
            add         : function( key, value, obj ){
                var array = this.getArray(),
                    inA = array;
                c.i('[check array 1]', inA );
                this.check( array, key, value )
                    || (
                        array.push( obj ),
                        c.i('[Added Object into array]', obj ),
                        c.i('[check array 2]', array )
                );
                this.stringify( array );
            },
            remove      : function( key, value, obj ){
                var array = this.getArray();
                this.check( array, key, value )
                    && (
                        array = array.grepArrayObj('remove', key, value ),
                        c.i('[Removed Object from array]', obj )
                    );
                this.stringify( array );
            }
        },
        booleanTimer = {
            timers  : [],
            start   : function( name, ms ){
                var that = this, value = name,
                    stop = setTimeout(function(){
                        that.stop( value );
                    }, ms );
                this.timers.push( { 'name': value, stop:stop } );
                //setTimeout(function(){that.stop( value );}, ms );
            },
            check   : function( value ){
                return this.timers.grepArrayObj( 'find', 'name', value ) !== undefined;
            },
            stop    : function( value ){
                this.timers = this.timers.grepArrayObj( 'remove', 'name', value );
            }
        },
        advTimer = {
            timers  : [],
            start   : function( name, ms ){
                var that = this, value = name,
                    stop = setTimeout(function(){
                        that.stop( value );
                    }, ms );
                //noinspection JSUnresolvedVariable
                this.timers.push({ 'name':value, start:window.performance.now(), timeout:ms, stop:stop });
            },
            check   : function( value ){
                var findObj = this.timers.grepArrayObj( 'find', 'name', value );
                //noinspection JSUnresolvedVariable
                return findObj !== undefined
                    ? findObj.timeout - ( window.performance.now() - findObj.start )
                    : false;
            },
            stop    : function( value ){
                this.timers = this.timers.grepArrayObj( 'remove', 'name', value );
            }
        },
        lap     = {
            data : {},
            tid  : function(){
                //noinspection JSUnresolvedVariable
                return performance.now();
            },
            set  : function(name){
                this.data[name] = this.tid();
            },
            get  : function(name){
                return this.tid() - this.data[name];
            },
            end  : function(name){
                this.print(name);
                this.del(name);
            },
            del  : function(name){
                delete this.data[name];
            },
            print: function(name){
                var get = this.get( name );
                c.i( 'Lap: ' + name,  isNaN( get ) ? 'There is no such a name ' : get + 'ms' );
            }
        },
        timer   = {
            ms  : 0,
            set : function(ms){
                var that = this;
                this.ms = ms;
                setTimeout(function(){
                    that.ms = 0;
                }, ms );
            }
        },
        counter = {
            data    : {},
            set     : function(name, start, base){
                this.data[name] = start || 0;
                this.data[name+'Default'] = base || 1;
            },
            get     : function(name){
                return this.data[name];
            },
            is      : function(name, count){
                return this.data[name] === count;
            },
            lessThen: function(name, count, equal ){
                return ( equal || false ) ? this.data[name] <= count : this.data[name] < count;
            },
            moreThen: function(name, count, equal){
                return ( equal || false ) ? this.data[name] >= count : this.data[name] > count;
            },
            del     : function(name){
                delete this.data[name];
            },
            exists  : function(name) {
                return this.data[name] !== undefined;
            },
            plus    : function(name, num){
                this.exists(name) || this.set(name);
                this.data[name] = this.data[name] + ( num === undefined ? this.data[name+'Default'] : num );
            },
            minus   : function(name, num){
                this.exists(name) || this.set(name);
                this.data[name] = this.data[name] - ( num === undefined ? this.data[name+'Default'] : num );
            },
            increase: function (name, num) {
                this.plus(name, num);
            },
            decrease: function (name, num) {
                this.minus(name, num);
            },
            '+'     : function (name, num) {
                this.plus(name, num);
            },
            '-'     : function (name, num) {
                this.minus(name, num);
            },
            up      : function (name, num) {
                this.plus(name, num);
            },
            down    : function (name, num) {
                this.minus(name, num);
            },
            add     : function (name, num) {
                this.plus(name, num);
            },
            subtract: function (name, num) {
                this.minus(name, num);
            },
            withdraw: function (name, num) {
                this.minus(name, num);
            }
        },
        g       = {
            locDoc  : window.location.href,
            ms      : 0,
            timer   : function(ms){
                g.ms = ms;
                setTimeout(function(){ g.ms = 0; }, ms );
            },

            GM      : {
                engine : function( mode, val, range ){
                    switch (mode){
                        case 'set':     GM_setValue( val.name, val.default );
                            break;
                        case 'get':     range ? config[ val.name ] = GM_getValue( val.name ):
                                                ui.config[ val.name ] = GM_getValue( val.name );
                            break;
                        case 'del':     GM_deleteValue( val.name );
                    }
                },
                manager : function( mode, array, range ){
                    $.each( array, function( i, val ){ this.engine( mode, val, range === undefined ); });
                    mode === 'del' && ( GM_deleteValue( 'firstRun' ), GM_deleteValue( 'yourVer' ) );
                }
            }
        },

        testPerformance = function( name, fn, testCycles ) {
            lap.set( name );
            var i = 0;
            for ( i ; i < testCycles; i++ ){
                fn();
            }
            lap.end( name );
        },
        perf = function (testName, fn) {
            var startTime = new Date().getTime();
            fn();
            var endTime = new Date().getTime();
            console.log(testName + ": " + (endTime - startTime) + "ms");
        };

$(document).on('click','*',function(e){
    this == e.target && c.i('target:', $(this)[0]
    ); });

c.i('my Function Library ö');
/*
isScrolledIntoView = (elem) ->
    docViewTop = $(window).scrollTop()
docViewBottom = docViewTop + $(window).height()
elemTop = $(elem).offset().top
elemBottom = elemTop + $(elem).height()

    (elemBottom - 200 < docViewBottom) and (elemBottom + $(elem).height() > docViewBottom )
*/