<commit_before>;( function( window ) {

	'use strict';

	function mobilecheck() {
		var check = false;
		(function(a){if(/(android|ipad|playbook|silk|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))check = true})(navigator.userAgent||navigator.vendor||window.opera);
		return check;
	}

	function gnMenu( el, options ) {
		this.el = el;
		this._init();
	}

	gnMenu.prototype = {
		_init : function() {
			this.trigger = this.el.querySelector( 'a.gn-icon-menu' );
			this.menu = this.el.querySelector( 'nav.gn-menu-wrapper' );
			this.isMenuOpen = false;
			this.eventtype = mobilecheck() ? 'touchstart' : 'click';
			this._initEvents();

			var self = this;
			this.bodyClickFn = function() {
				self._closeMenu();
				this.removeEventListener( self.eventtype, self.bodyClickFn );
			};
		},
		_initEvents : function() {
			var self = this;

			if( !mobilecheck() ) {
				this.trigger.addEventListener( 'mouseover', function(ev) { self._openIconMenu(); } );
				this.trigger.addEventListener( 'mouseout', function(ev) { self._closeIconMenu(); } );

				this.menu.addEventListener( 'mouseover', function(ev) {
					self._openMenu();
					document.addEventListener( self.eventtype, self.bodyClickFn );
				} );
			}
			this.trigger.addEventListener( this.eventtype, function( ev ) {
				ev.stopPropagation();
				ev.preventDefault();
				if( self.isMenuOpen ) {
					self._closeMenu();
					document.removeEventListener( self.eventtype, self.bodyClickFn );
				}
				else {
					self._openMenu();
					document.addEventListener( self.eventtype, self.bodyClickFn );
				}
			} );
<commit_msg>Update gnmenu.js<commit_after>;( function( window ) {

	'use strict';

	function mobilecheck() {
		var check = false;
		(function(a){if(/(android|ipad|playbook|silk|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))check = true})(navigator.userAgent||navigator.vendor||window.opera);
		return check;
	}

	function gnMenu( el, options ) {
		this.el = el;
		this._init();
	}

	gnMenu.prototype = {
		_init : function() {
			this.trigger = this.el.querySelector( 'a.gn-icon-menu' );
			this.menu = this.el.querySelector( 'nav.gn-menu-wrapper' );
			this.isMenuOpen = false;
			this.eventtype = mobilecheck() ? 'touchstart' : 'click';
			this._initEvents();

			var self = this;
			this.bodyClickFn = function() {
				self._closeMenu();
				this.removeEventListener( self.eventtype, self.bodyClickFn );
			};
		},
		_initEvents : function() {
			var self = this;

			if( !mobilecheck() ) {
				this.trigger.addEventListener( 'mouseover', function(ev) { self._openIconMenu(); } );
				this.trigger.addEventListener( 'mouseout', function(ev) { self._closeIconMenu(); } );

				this.menu.addEventListener( 'mouseover', function(ev) {
					self._openMenu();
					document.addEventListener( self.eventtype, self.bodyClickFn );
				} );
			}
			this.trigger.addEventListener( this.eventtype, function( ev ) {
				ev.stopPropagation();
				ev.preventDefault();
				if( self.isMenuOpen ) {
					self._closeMenu();
					document.removeEventListener( self.eventtype, self.bodyClickFn );
				}
				else {
					self._openMenu();
					document.addEventListener( self.eventtype, self.bodyClickFn );
				}
			} );

		this.menu.addEventListener( this.eventtype, function(ev) { ev.stopPropagation(); } );
		},
		_openIconMenu : function() {
			classie.add( this.menu, 'gn-open-part' );
		},
		_closeIconMenu : function() {
			classie.remove( this.menu, 'gn-open-part' );
		},
		_openMenu : function() {
			if( this.isMenuOpen ) return;
			classie.add( this.trigger, 'gn-selected' );
			this.isMenuOpen = true;
			classie.add( this.menu, 'gn-open-all' );
			this._closeIconMenu();
		},
		_closeMenu : function() {
			if( !this.isMenuOpen ) return;
			classie.remove( this.trigger, 'gn-selected' );
			this.isMenuOpen = false;
			classie.remove( this.menu, 'gn-open-all' );
			this._closeIconMenu();
		}
	}

	window.gnMenu = gnMenu;

} )( window );
<|endoftext|>


<commit_before>/*#ifndef(UMD)*/
"use strict";
/*global _gpfEmptyFunc*/
/*#endif*/

gpf.interfaces = {

    /**
     * Verify that the object implements the current interface
     *
     * @param {Object} objectInstance object to inspect
     * @param {gpf.interfaces.Interface} interfaceDefinition reference
     * interface
     * @return {Boolean}
     */
    isImplementedBy: function (objectInstance, interfaceDefinition) {
        var member;
        /*
         * IMPORTANT note: we test the object itself (i.e. own members and
         * the prototype). That's why the hasOwnProperty is skipped
         */
        /*jslint forin:false*/
        for (member in interfaceDefinition.prototype) {
            if ("constructor" === member                           // Object
                || "extend" === member) {                       // gpf.Class
                continue;
            }
            if (typeof interfaceDefinition.prototype[member]
                !== typeof objectInstance[member]) {
                return false;
            }
        }
        /*jslint forin:true*/
        return true;
    },

/*#ifdef(DEBUG)*/

    /**
     * Used to remove warnings about unused parameters
     */
    ignoreParameter: function /*gpf:ignore*/ (value) {
        return value;
    },

/*#endif*/

    /**
     * Retrieve an object implementing the expected interface from an
     * object.
     * This is done in two passes:
     * - Either the object implements the interface, it is returned
     * - Or the object implements IUnknown, then queryInterface is used
     *
     * @param {Object} objectInstance object to inspect
     * @param {gpf.interfaces.Interface} interfaceDefinition reference
     * interface
     * @param {Boolean} [throwError=false] throwError Throws an error if the
     * interface is not found (otherwise, null is returned)
     * @return {Object|null}
     */
    query: function (objectInstance, interfaceDefinition, throwError) {
        var result = null;
        if (gpf.interfaces.isImplementedBy(objectInstance,
            interfaceDefinition)) {
            return objectInstance;
        } else if (gpf.interfaces.isImplementedBy(objectInstance,
            gpf.interfaces.IUnknown)) {
            result = objectInstance.queryInterface(interfaceDefinition);
        }
        if (null === result && throwError) {
            throw gpf.Error.InterfaceExpected({
                name: gpf.classDef(interfaceDefinition).name()
            });
        }
        return result;
    }

};

/*#ifndef(DEBUG)*/

if (!gpf.interfaces.ignoreParameter) {

    gpf.interfaces.ignoreParameter = function /*gpf:inline*/ () {};

}

/*#endif*/

/**
 * Defines an interface (relies on gpf.define)
 *
 * @param {String} name Interface name. If it contains a dot, it is
 * treated as absolute contextual. Otherwise, it is relative to
 * "gpf.interfaces"
 * @param {Function|string} [base=undefined] base Base interface
 * (or contextual name)
 * @param {Object} [definition=undefined] definition Interface definition
 * @return {Function}
 * @private
 */
gpf._defIntrf = gpf._genDefHandler("gpf.interfaces", "Interface");

gpf._defIntrf("Interface");

//region IEventTarget

gpf._defIntrf("IEventTarget", {

    /**
     * Add an event listener to the target
     *
     * @param {String} event name
     * @param {Function|gpf.Callback} callback
     * @param {Object|Boolean} scope scope of callback or useCapture
     * parameter. NOTE: if a gpf.Callback object is used and a scope
     * specified, a new gpf.Callback object is created.
     * @param {Boolean} [useCapture=false] useCapture push it on top of the
     * triggering queue
     * @return {gpf.interfaces.IEventTarget}
     * @chainable
     */
    addEventListener: function (event, callback, scope, useCapture) {
        gpf.interfaces.ignoreParameter(event);
        gpf.interfaces.ignoreParameter(callback);
        gpf.interfaces.ignoreParameter(scope);
        gpf.interfaces.ignoreParameter(useCapture);
    },

    /**
     * Remove an event listener to the target
     *
     * @param {String} event name
     * @param {Function|gpf.Callback} callback
     * @param {Object} [scope=undefined] scope scope of callback
     * @return {gpf.interfaces.IEventTarget}
     * @chainable
     */
    removeEventListener: function (event, callback, scope) {
        gpf.interfaces.ignoreParameter(event);
        gpf.interfaces.ignoreParameter(callback);
        gpf.interfaces.ignoreParameter(scope);
    }

});

//endregion

//region IUnknown

/**
 * Provide a way for any object to implement an interface using an
 * intermediate object (this avoids overloading the object with temporary
 * / useless members)
 */
gpf._defIntrf("IUnknown", {

    /**
     * Retrieves an object supporting the provided interface
     * (maybe the object itself)
     *
     * @param {gpf.interfaces.Interface} interfaceDefinition The expected
     * interface
     * @return {Object|null} The object supporting the interface (or null)
     */
    queryInterface: function (interfaceDefinition) {
        gpf.interfaces.ignoreParameter(interfaceDefinition);
        return null;
    }

});

//endregion

//region InterfaceImplement attribute

/**
 * Retrieves an object supporting the provided interface
 * (maybe the object itself). This function (added to any object declaring
 * the attribute InterfaceImplementAttribute with a builder) uses the
 * InterfaceImplementAttribute attribute list to see if the one
 * corresponding to the interface provides a builder and calls it
 *
 * @param {gpf.interfaces.Interface} interfaceDefinition The expected
 * interface
 * @return {Object|null} The object supporting the interface (or null)
 */
function _queryInterface (interfaceDefinition) {
    /*jslint -W040*/
    var
        array = (new gpf.attributes.Map(this))
            .member("Class")
            .filter(gpf.attributes.InterfaceImplementAttribute),
        idx,
        attribute;
    for (idx = 0; idx < array.length(); ++idx) {
        attribute = array.get(idx);
        if (attribute._interfaceDefinition === interfaceDefinition) {
            if (attribute._builder) {
                return attribute._builder(this);
            }
            break;
        }
    }
    // Otherwise
    return null;
    /*jslint +W040*/
}

/**
 * Creates a wrapper calling _queryInterface and, if no result is built, the
 * original one defined in the object prototype.
 *
 * @param {Function} orgQueryInterface
 * @private
 * @closure
 */
function _wrapQueryInterface (orgQueryInterface) {
    return function () {
        var result = _queryInterface.apply(this, arguments);
        if (null === result) {
            result = orgQueryInterface.apply(this, arguments);
        }
        return result;
    };
}

/**
 * Extend the class to provide an array-like interface
 *
 * @param {Function} interfaceDefinition Implemented interface definition
 * @param {Function} [queryInterfaceBuilder=undefined] queryInterfaceBuilder
 * Function applied if the implemented interface is requested
 *
 * @class gpf.attributes.ClassArrayInterfaceAttribute
 * @extends gpf.attributes.ClassAttribute
 * @alias gpf.$ClassIArray
 */
gpf._defAttr("$InterfaceImplement", {

    private: {

        /**
         * Interface definition
         *
         * @type {Function}
         * @private
         */
        "[_interfaceDefinition]": [gpf.$ClassProperty(false, "which")],
        _interfaceDefinition: _gpfEmptyFunc,

        /**
         * Builder function
         *
         * @type {Function|null}
         * @private
         */
        "[_builder]": [gpf.$ClassProperty(false, "how")],
        _builder: null

    },

    protected: {

        /**
         * @inheritdoc gpf.attributes.Attribute:_alterPrototype
         */
        _alterPrototype: function (objPrototype) {
            var
                iProto = this._interfaceDefinition.prototype,
                iClassDef = gpf.classDef(this._interfaceDefinition),
                member,
                attributes;
            // Get the interface's attributes apply them to the obj
            attributes = new gpf.attributes.Map();
            attributes.fillFromClassDef(iClassDef);
            attributes.addTo(objPrototype.constructor);
            if (!this._builder) {
                // Fill the missing methods
                /*jshint -W089*/ // Because I also want inherited ones
                for (member in iProto) {
                    if (!(member in objPrototype)) {
                        objPrototype[member] = iProto[member];
                    }
                }
                return;
            }
            // Handle the queryInterface logic
            if (undefined !== objPrototype.queryInterface) {
                /*
                 * Two situations here:
                 * - Either the class (or one of its parent) already owns
                 *   the $InterfaceImplement attribute
                 * - Or the class (or one of its parent) implements its
                 *   own queryInterface
                 * In that last case, wrap it to use the attribute version
                 * first
                 *
                 * In both case, we take the assumption that the class
                 * already owns
                 * gpf.$InterfaceImplement(gpf.interfaces.IUnknown)
                 */
                if (_queryInterface !== objPrototype.queryInterface) {
                    objPrototype.queryInterface =
                        _wrapQueryInterface(objPrototype.queryInterface);
                }
            } else {
                objPrototype.queryInterface = _queryInterface;
                gpf.attributes.add(objPrototype.constructor, "Class",
                    [gpf.$InterfaceImplement(gpf.interfaces.IUnknown)]);
            }
        }
        /*jshint +W089*/

    },

    public: {

        /**
         * @param {Function} interfaceDefinition Interface definition
         * @param {Function|null} [queryInterfaceBuilder=null]
         * queryInterfaceBuilder Builder function
         * @constructor
         */
        constructor: function (interfaceDefinition, queryInterfaceBuilder) {
            this._interfaceDefinition = interfaceDefinition;
            if (queryInterfaceBuilder) {
                this._builder = queryInterfaceBuilder;
            }
        }

    }

});

//endregion<commit_msg>Documentation<commit_after>/*#ifndef(UMD)*/
"use strict";
/*global _gpfEmptyFunc*/ // An empty function
/*#endif*/

gpf.interfaces = {

    /**
     * Verify that the object implements the current interface
     *
     * @param {Object} objectInstance object to inspect
     * @param {gpf.interfaces.Interface} interfaceDefinition reference
     * interface
     * @return {Boolean}
     */
    isImplementedBy: function (objectInstance, interfaceDefinition) {
        var member;
        /*
         * IMPORTANT note: we test the object itself (i.e. own members and
         * the prototype). That's why the hasOwnProperty is skipped
         */
        /*jslint forin:false*/
        for (member in interfaceDefinition.prototype) {
            if ("constructor" === member                           // Object
                || "extend" === member) {                       // gpf.Class
                continue;
            }
            if (typeof interfaceDefinition.prototype[member]
                !== typeof objectInstance[member]) {
                return false;
            }
        }
        /*jslint forin:true*/
        return true;
    },

/*#ifdef(DEBUG)*/

    /**
     * Used to remove warnings about unused parameters
     */
    ignoreParameter: function /*gpf:ignore*/ (value) {
        return value;
    },

/*#endif*/

    /**
     * Retrieve an object implementing the expected interface from an
     * object.
     * This is done in two passes:
     * - Either the object implements the interface, it is returned
     * - Or the object implements IUnknown, then queryInterface is used
     *
     * @param {Object} objectInstance object to inspect
     * @param {gpf.interfaces.Interface} interfaceDefinition reference
     * interface
     * @param {Boolean} [throwError=false] throwError Throws an error if the
     * interface is not found (otherwise, null is returned)
     * @return {Object|null}
     */
    query: function (objectInstance, interfaceDefinition, throwError) {
        var result = null;
        if (gpf.interfaces.isImplementedBy(objectInstance,
            interfaceDefinition)) {
            return objectInstance;
        } else if (gpf.interfaces.isImplementedBy(objectInstance,
            gpf.interfaces.IUnknown)) {
            result = objectInstance.queryInterface(interfaceDefinition);
        }
        if (null === result && throwError) {
            throw gpf.Error.InterfaceExpected({
                name: gpf.classDef(interfaceDefinition).name()
            });
        }
        return result;
    }

};

/*#ifndef(DEBUG)*/

if (!gpf.interfaces.ignoreParameter) {

    gpf.interfaces.ignoreParameter = function /*gpf:inline*/ () {};

}

/*#endif*/

/**
 * Defines an interface (relies on gpf.define)
 *
 * @param {String} name Interface name. If it contains a dot, it is
 * treated as absolute contextual. Otherwise, it is relative to
 * "gpf.interfaces"
 * @param {Function|string} [base=undefined] base Base interface
 * (or contextual name)
 * @param {Object} [definition=undefined] definition Interface definition
 * @return {Function}
 * @private
 */
gpf._defIntrf = gpf._genDefHandler("gpf.interfaces", "Interface");

gpf._defIntrf("Interface");

//region IEventTarget

gpf._defIntrf("IEventTarget", {

    /**
     * Add an event listener to the target
     *
     * @param {String} event name
     * @param {Function|gpf.Callback} callback
     * @param {Object|Boolean} scope scope of callback or useCapture
     * parameter. NOTE: if a gpf.Callback object is used and a scope
     * specified, a new gpf.Callback object is created.
     * @param {Boolean} [useCapture=false] useCapture push it on top of the
     * triggering queue
     * @return {gpf.interfaces.IEventTarget}
     * @chainable
     */
    addEventListener: function (event, callback, scope, useCapture) {
        gpf.interfaces.ignoreParameter(event);
        gpf.interfaces.ignoreParameter(callback);
        gpf.interfaces.ignoreParameter(scope);
        gpf.interfaces.ignoreParameter(useCapture);
    },

    /**
     * Remove an event listener to the target
     *
     * @param {String} event name
     * @param {Function|gpf.Callback} callback
     * @param {Object} [scope=undefined] scope scope of callback
     * @return {gpf.interfaces.IEventTarget}
     * @chainable
     */
    removeEventListener: function (event, callback, scope) {
        gpf.interfaces.ignoreParameter(event);
        gpf.interfaces.ignoreParameter(callback);
        gpf.interfaces.ignoreParameter(scope);
    }

});

//endregion

//region IUnknown

/**
 * Provide a way for any object to implement an interface using an
 * intermediate object (this avoids overloading the object with temporary
 * / useless members)
 */
gpf._defIntrf("IUnknown", {

    /**
     * Retrieves an object supporting the provided interface
     * (maybe the object itself)
     *
     * @param {gpf.interfaces.Interface} interfaceDefinition The expected
     * interface
     * @return {Object|null} The object supporting the interface (or null)
     */
    queryInterface: function (interfaceDefinition) {
        gpf.interfaces.ignoreParameter(interfaceDefinition);
        return null;
    }

});

//endregion

//region InterfaceImplement attribute

/**
 * Retrieves an object supporting the provided interface
 * (maybe the object itself). This function (added to any object declaring
 * the attribute InterfaceImplementAttribute with a builder) uses the
 * InterfaceImplementAttribute attribute list to see if the one
 * corresponding to the interface provides a builder and calls it
 *
 * @param {gpf.interfaces.Interface} interfaceDefinition The expected
 * interface
 * @return {Object|null} The object supporting the interface (or null)
 */
function _queryInterface (interfaceDefinition) {
    /*jslint -W040*/
    var
        array = (new gpf.attributes.Map(this))
            .member("Class")
            .filter(gpf.attributes.InterfaceImplementAttribute),
        idx,
        attribute;
    for (idx = 0; idx < array.length(); ++idx) {
        attribute = array.get(idx);
        if (attribute._interfaceDefinition === interfaceDefinition) {
            if (attribute._builder) {
                return attribute._builder(this);
            }
            break;
        }
    }
    // Otherwise
    return null;
    /*jslint +W040*/
}

/**
 * Creates a wrapper calling _queryInterface and, if no result is built, the
 * original one defined in the object prototype.
 *
 * @param {Function} orgQueryInterface
 * @private
 * @closure
 */
function _wrapQueryInterface (orgQueryInterface) {
    return function () {
        var result = _queryInterface.apply(this, arguments);
        if (null === result) {
            result = orgQueryInterface.apply(this, arguments);
        }
        return result;
    };
}

/**
 * Extend the class to provide an array-like interface
 *
 * @param {Function} interfaceDefinition Implemented interface definition
 * @param {Function} [queryInterfaceBuilder=undefined] queryInterfaceBuilder
 * Function applied if the implemented interface is requested
 *
 * @class gpf.attributes.ClassArrayInterfaceAttribute
 * @extends gpf.attributes.ClassAttribute
 * @alias gpf.$ClassIArray
 */
gpf._defAttr("$InterfaceImplement", {

    private: {

        /**
         * Interface definition
         *
         * @type {Function}
         * @private
         */
        "[_interfaceDefinition]": [gpf.$ClassProperty(false, "which")],
        _interfaceDefinition: _gpfEmptyFunc,

        /**
         * Builder function
         *
         * @type {Function|null}
         * @private
         */
        "[_builder]": [gpf.$ClassProperty(false, "how")],
        _builder: null

    },

    protected: {

        /**
         * @inheritdoc gpf.attributes.Attribute:_alterPrototype
         */
        _alterPrototype: function (objPrototype) {
            var
                iProto = this._interfaceDefinition.prototype,
                iClassDef = gpf.classDef(this._interfaceDefinition),
                member,
                attributes;
            // Get the interface's attributes apply them to the obj
            attributes = new gpf.attributes.Map();
            attributes.fillFromClassDef(iClassDef);
            attributes.addTo(objPrototype.constructor);
            if (!this._builder) {
                // Fill the missing methods
                /*jshint -W089*/ // Because I also want inherited ones
                for (member in iProto) {
                    if (!(member in objPrototype)) {
                        objPrototype[member] = iProto[member];
                    }
                }
                return;
            }
            // Handle the queryInterface logic
            if (undefined !== objPrototype.queryInterface) {
                /*
                 * Two situations here:
                 * - Either the class (or one of its parent) already owns
                 *   the $InterfaceImplement attribute
                 * - Or the class (or one of its parent) implements its
                 *   own queryInterface
                 * In that last case, wrap it to use the attribute version
                 * first
                 *
                 * In both case, we take the assumption that the class
                 * already owns
                 * gpf.$InterfaceImplement(gpf.interfaces.IUnknown)
                 */
                if (_queryInterface !== objPrototype.queryInterface) {
                    objPrototype.queryInterface =
                        _wrapQueryInterface(objPrototype.queryInterface);
                }
            } else {
                objPrototype.queryInterface = _queryInterface;
                gpf.attributes.add(objPrototype.constructor, "Class",
                    [gpf.$InterfaceImplement(gpf.interfaces.IUnknown)]);
            }
        }
        /*jshint +W089*/

    },

    public: {

        /**
         * @param {Function} interfaceDefinition Interface definition
         * @param {Function|null} [queryInterfaceBuilder=null]
         * queryInterfaceBuilder Builder function
         * @constructor
         */
        constructor: function (interfaceDefinition, queryInterfaceBuilder) {
            this._interfaceDefinition = interfaceDefinition;
            if (queryInterfaceBuilder) {
                this._builder = queryInterfaceBuilder;
            }
        }

    }

});

//endregion<|endoftext|>


<commit_before>var usersBlocked = 0,
    usersFound = 0,
    usersAlreadyBlocked = 0,
    usersSkipped = 0,
    totalCount = 0,
    errors = 0;
var batchBlockCount = 5;
var scrollerInterval = false,
    finderInterval = false,
    blockerInterval = false;
var userQueue = new Queue();

chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
    if (request.blockChainStart) {
        if ($(".GridTimeline .ProfileCard").length > 0) {
            sendResponse({ack: true});
            startBlockChain();
        }
        else {
            sendResponse({error: true, error_description: 'Navigate to a twitter following or followers page.'});
        }
    }
});
$("#blockAllUsers").click(startBlockChain);
function startBlockChain() {
    var result = confirm("Are you sure you want to block all users on this page that you aren't following?");
    if (!result)
        return;
    showDialog();
    scrollerInterval = setInterval(function() {
        window.scroll(0, $(document).height());
        if ($(".GridTimeline-end.has-more-items").length==0) {
            clearInterval(scrollerInterval);
            scrollerInterval = false;
            doBlocking();
            totalCount = $(".ProfileCard").length;
            $("#blockchain-dialog .totalCount").text(totalCount);
        }
    },500);
    finderInterval = setInterval(function() {
        doBlocking();
        if (usersFound==totalCount && totalCount > 0) {
            clearInterval(finderInterval);
            finderInterval = false;
        }
    },1000);
    blockerInterval = setInterval(function() {
        for (var i=0;i<batchBlockCount;i++) {
            var user = userQueue.dequeue();
            if (typeof user !== "undefined") {
                $.ajax({
                    url: "https://twitter.com/i/user/block",
                    method: "POST",
                    dataType: 'json',
                    data: {
                        authenticity_token: $("#signout-form input.authenticity_token").val(),
                        block_user: true,
                        impression_id: "",
                        report_type: "",
                        screen_name: user.name,
                        user_id: user.id
                    }
                }).done(function(response) {
                    //console.log(response);
                }).fail(function(xhr, text, err) {
                    errors++;
                    $("#blockchain-dialog .errorCount").text(errors);
                    //console.log(xhr);
                }).always(function() {
                    usersBlocked++;
                    $("#blockchain-dialog .usersBlocked").text(usersBlocked);
                    if ((usersBlocked == totalCount || usersBlocked == usersFound) && totalCount > 0) {
                        clearInterval(blockerInterval);
                        blockerInterval = false;
                    }
                });
            }
        }
    },40);
}

function doBlocking() {
    $(".ProfileCard:not(.blockchain-added)").each(function(i,e) {
        $(e).addClass("blockchain-added");
        if ($(e).find('.user-actions.following').length > 0) {
            usersSkipped++;
            $("#blockchain-dialog .usersSkipped").text(usersSkipped);
            return true;
        }
        if ($(e).find('.user-actions.blocked').length > 0) {
            usersAlreadyBlocked++;
            $("#blockchain-dialog .usersAlreadyBlocked").text(usersAlreadyBlocked);
            return true;
        }
        usersFound++;
        $("#blockchain-dialog .usersFound").text(usersFound);
        userQueue.enqueue({
            name: $(e).data('screen-name'),
            id: $(e).data('user-id')
        });
    });
}

function showDialog() {
    $("body").append(
'
'+
	'

'+
	'

'+
	'
'+
		'
'+
			'
Twitter Block Chain
'+
		'
'+
		'
'+
            '
Found:
'+
            '
Skipped:
'+
            '
Already Blocked:
'+
            '
Blocked:
'+
            '
Total:
'+
            '
Errors:
'+
		'
'+
		'
'+
			'
'+
				'<button id="done" class="btn primary-btn report-tweet-next-button" type="button">Done</button>'+
			'
'+
		'
'+
	'
'+
	'<button type="button" class="modal-btn modal-close js-close" aria-controls="block-or-report-dialog-dialog">'+
		''+
			'Close'+
		''+
	'</button>'+
	'

'+
'
'
    );
    $("#blockchain-dialog").show().find("button").click(function() {
        clearInterval(blockerInterval);
        clearInterval(scrollerInterval);
        clearInterval(finderInterval);
        $("#blockchain-dialog").hide();
    });
}<commit_msg>clear fields and reset dialog when closing<commit_after>var usersBlocked = 0,
    usersFound = 0,
    usersAlreadyBlocked = 0,
    usersSkipped = 0,
    totalCount = 0,
    errors = 0;
var batchBlockCount = 5;
var scrollerInterval = false,
    finderInterval = false,
    blockerInterval = false;
var userQueue = new Queue();

chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
    if (request.blockChainStart) {
        if ($(".GridTimeline .ProfileCard").length > 0) {
            sendResponse({ack: true});
            startBlockChain();
        }
        else {
            sendResponse({error: true, error_description: 'Navigate to a twitter following or followers page.'});
        }
    }
});
$("#blockAllUsers").click(startBlockChain);
function startBlockChain() {
    var result = confirm("Are you sure you want to block all users on this page that you aren't following?");
    if (!result)
        return;
    showDialog();
    scrollerInterval = setInterval(function() {
        window.scroll(0, $(document).height());
        if ($(".GridTimeline-end.has-more-items").length==0) {
            clearInterval(scrollerInterval);
            scrollerInterval = false;
            doBlocking();
            totalCount = $(".ProfileCard").length;
            $("#blockchain-dialog .totalCount").text(totalCount);
        }
    },500);
    finderInterval = setInterval(function() {
        doBlocking();
        if (usersFound==totalCount && totalCount > 0) {
            clearInterval(finderInterval);
            finderInterval = false;
        }
    },1000);
    blockerInterval = setInterval(function() {
        for (var i=0;i<batchBlockCount;i++) {
            var user = userQueue.dequeue();
            if (typeof user !== "undefined") {
                $.ajax({
                    url: "https://twitter.com/i/user/block",
                    method: "POST",
                    dataType: 'json',
                    data: {
                        authenticity_token: $("#signout-form input.authenticity_token").val(),
                        block_user: true,
                        impression_id: "",
                        report_type: "",
                        screen_name: user.name,
                        user_id: user.id
                    }
                }).done(function(response) {
                    //console.log(response);
                }).fail(function(xhr, text, err) {
                    errors++;
                    $("#blockchain-dialog .errorCount").text(errors);
                    //console.log(xhr);
                }).always(function() {
                    usersBlocked++;
                    $("#blockchain-dialog .usersBlocked").text(usersBlocked);
                    if ((usersBlocked == totalCount || usersBlocked == usersFound) && totalCount > 0) {
                        clearInterval(blockerInterval);
                        blockerInterval = false;
                    }
                });
            }
        }
    },40);
}

function doBlocking() {
    $(".ProfileCard:not(.blockchain-added)").each(function(i,e) {
        $(e).addClass("blockchain-added");
        if ($(e).find('.user-actions.following').length > 0) {
            usersSkipped++;
            $("#blockchain-dialog .usersSkipped").text(usersSkipped);
            return true;
        }
        if ($(e).find('.user-actions.blocked').length > 0) {
            usersAlreadyBlocked++;
            $("#blockchain-dialog .usersAlreadyBlocked").text(usersAlreadyBlocked);
            return true;
        }
        usersFound++;
        $("#blockchain-dialog .usersFound").text(usersFound);
        userQueue.enqueue({
            name: $(e).data('screen-name'),
            id: $(e).data('user-id')
        });
    });
}

function showDialog() {
    $("body").append(
'
'+
	'

'+
	'

'+
	'
'+
		'
'+
			'
Twitter Block Chain
'+
		'
'+
		'
'+
            '
Found:
'+
            '
Skipped:
'+
            '
Already Blocked:
'+
            '
Blocked:
'+
            '
Total:
'+
            '
Errors:
'+
		'
'+
		'
'+
			'
'+
				'<button id="done" class="btn primary-btn report-tweet-next-button" type="button">Done</button>'+
			'
'+
		'
'+
	'
'+
	'<button type="button" class="modal-btn modal-close js-close" aria-controls="block-or-report-dialog-dialog">'+
		''+
			'Close'+
		''+
	'</button>'+
	'

'+
'
'
    );
    $("#blockchain-dialog").show().find("button").click(function() {
        clearInterval(blockerInterval);
        clearInterval(scrollerInterval);
        clearInterval(finderInterval);
        usersBlocked = 0;
        usersFound = 0;
        usersAlreadyBlocked = 0;
        usersSkipped = 0;
        totalCount = 0;
        errors = 0;
        $("#blockchain-dialog .usersFound").text(usersFound);
        $("#blockchain-dialog .usersSkipped").text(usersSkipped);
        $("#blockchain-dialog .usersAlreadyBlocked").text(usersAlreadyBlocked);
        $("#blockchain-dialog .usersBlocked").text(usersBlocked);
        $("#blockchain-dialog .totalCount").text(totalCount);
        $("#blockchain-dialog .errorCount").text(errors);
        $("#blockchain-dialog").hide();
    });
}<|endoftext|>


<commit_before>window.livedesk.i18n = {
	'no_avatar': 'true',
	'show_current_date': 'true',
	'HH:MM:ss': 'HH:MM',
	'HH:MM:ss TT': 'HH:MM',
	'ddd mmm dd yyyy HH:MM:ss TT': 'dddd, dd. mmmm yyyy HH:MM',
	'day_names': [
		"So", "Mo", "Di", "Mi", "Do", "Fr", "Sa",
		"Sonnabend", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"
	],
	'month_names': [
		"Jän", "Feb", "März", "Apr", "Mai", "Juni", "Juli", "Aug", "Sep", "Okt", "Nov", "Dez",
		"Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"
	],
	'updating...': 'Wird aktualisiert...',
	'by': 'von',
	'updated on ': 'Zuletzt aktualisiert um '
};<commit_msg>tw implementation<commit_after>window.livedesk.i18n = {
	'no_avatar': 'true',
	'show_current_date': 'true',
	'HH:MM:ss': 'HH:MM',
	'HH:MM:ss TT': 'HH:MM',
	'ddd mmm dd yyyy HH:MM:ss TT': 'dd. mmmm yyyy, HH:MM',
	'day_names': [
		"So", "Mo", "Di", "Mi", "Do", "Fr", "Sa",
		"Sonnabend", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"
	],
	'month_names': [
		"Jän", "Feb", "März", "Apr", "Mai", "Juni", "Juli", "Aug", "Sep", "Okt", "Nov", "Dez",
		"Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"
	],
	'updating...': 'Wird aktualisiert...',
	'by': 'von',
	'updated on ': 'Zuletzt aktualisiert um '
};<|endoftext|>


<commit_before>import {postJSON} from "../utils.js";

/**
 * @typedef {Object} FACounts
 * @property {number} value count
 * @property {string} name  The name of the GO/EC number
 * @property {string} code  The code of the GO/EC number
 */

const BATCH_SIZE = 1000;
const NAMESPACES = ["biological process", "cellular component", "molecular function"];

/**
 * Class that helps organizing GO terms
 */
export default class GOTerms {
    /**
     * Static cache of GO term information
     * @access private
     */
    static goData = new Map();

    /**
     * Creates a new GOTerms
     * TODO
     * @param  {[FACounts]} [go=[]] list of GO terms with their counts
     * @param {bool} [ensureData=true] fetch names for this resultset in the background,ss
     *                                 if false, you must call `ensureData()` on this object.
     * @param {bool} [clone=false] *for internal use*
     */
    constructor({numAnnotatedProteins = null, data = []}, ensureData = true, clone = false) {
        if (clone) return;
        this.numTotalSet = numAnnotatedProteins;
        this.go = new Map();
        Object.values(data).forEach(v => v.forEach(goTerm => this.go.set(goTerm.code, goTerm)));
        GOTerms.addData(Array.from(this.go.values()));

        // Sort values to store and have every namespace
        this.data = {};
        for (const namespace of NAMESPACES) {
            if (namespace in data) {
                this.data[namespace] = Array.from(data[namespace]).sort((a, b) => (b.value - a.value));
            } else {
                this.data[namespace] = [];
            }
        }

        if (ensureData) {
            this.ensureData();
        }
    }

    /**
     * Make a new GOTerms form a clone
     * @param {GOTerms} other
     * @param {GOTerms} [base=null] optional GoTerms instance to reuse
     * @return {GOTerms} filled GOTerms instance
     */
    static clone(other, base = null) {
        let go = base;
        if (base === null) {
            go = new GOTerms({}, true, true);
        }
        go.numTotalSet = other.numTotalSet;
        go.data = other.data;
        go.go = other.go;
        return go;
    }

    /**
    /**
     * Fetch the names of the GO terms and await them
     */
    async ensureData() {
        await GOTerms.addMissingNames(Array.from(this.go.keys()));
    }

    /**
     * @return {int} number of annotated peptides
     */
    getTotalSetSize() {
        return this.numTotalSet;
    }

    /**
     * Returns the originally supplied set of GO Terms
     * sorted by value for a specific namespace
     * @param  {String} namespace The namespace (one of GOTerms.NAMESPACES)
     * @return {[FACounts]} Sorted GO Terms
     */
    sortedTerms(namespace) {
        return this.data[namespace];
    }

    /**
     * Get the count of the GO term in the data set
     * @param  {string} goTerm the GO term (form "GO:0005886")
     * @return {number}        count of the GO term
     */
    getValueOf(goTerm) {
        if (this.go.has(goTerm)) {
            return this.go.get(goTerm).value;
        }
        return 0;
    }

    /**
     * Get the count of the GO term in the data set as fraction of the total size
     * of the set
     * @param  {string} goTerm the GO term (form "GO:0005886")
     * @return {number}        fraction of the GO term
     */
    getFractionOf(goTerm) {
        return this.getValueOf(goTerm) / this.numTotalSet;
    }

    /**
     * Gets the name of associated with an GO Term
     *
     * @param  {string} goTerm The code of the GO Term (like "GO:0006423")
     * @return {string}       The name of the GO Term
     */
    static nameOf(goTerm) {
        if (this.goData.has(goTerm)) {
            return this.goData.get(goTerm).name;
        }
        return "Unknown";
    }

    /**
     * Give the namespace of a GO term
     *
     * @param  {string} goTerm The code of the GO Term
     * @return {[string]}  Ancestors of the GO Term (from specific to generic)
     */
    static namespaceOf(goTerm) {
        if (this.goData.has(goTerm)) {
            return this.goData.get(goTerm).namespace;
        }
        return "Unknown";
    }

    /**
     * Add GO terms to the global map
     * @param {[FACounts]} newTerms list of new GO Terms
     */
    static addData(newTerms) {
        newTerms.forEach(go => {
            if (!this.goData.has(go.code) && go.namespace && go.name) {
                this.goData.set(go.code, go);
            }
        });
    }

    /**
     * Fetch the names and data of the GO terms that are not yet in the static map of
     * names
     * @param {[string]} codes array of GO terms that should be in the cache
     */
    static async addMissingNames(codes) {
        const todo = codes.filter(c => !this.goData.has(c));
        if (todo.length > 0) {
            for (let i = 0; i < todo.length; i += BATCH_SIZE) {
                const res = await postJSON("/private_api/goterms", JSON.stringify({
                    goterms: todo.slice(i, i + BATCH_SIZE),
                }));
                GOTerms.addData(res);
            }
        }
    }

    /**
     * Cone the GO Term information into the current GOTerm static value
     *
     * Needed to work properly with WebWorkers that do not share these statics
     *
     * @param {iteratable<FAInfo>} data inforamtion about GO Terms
     */
    static ingestData(data) {
        GOTerms.goData = data;
    }

    /**
     * @param {[string]} terms the terms to show in the chart (at least one)
     * @return {string} The QuickGo chart URL of the given GO terms
     */
    static quickGOChartURL(terms) {
        return `https://www.ebi.ac.uk/QuickGO/services/ontology/go/terms/${terms.join(",")}/chart`;
    }

    /**
     * Get a list of the 3 root namespaces of the Gene Ontology
     */
    static get NAMESPACES() {
        return NAMESPACES;
    }
}
<commit_msg>perf(goterms): increase likelyhood that a GOTerm is cached<commit_after>import {postJSON} from "../utils.js";

/**
 * @typedef {Object} FACounts
 * @property {number} value count
 * @property {string} name  The name of the GO/EC number
 * @property {string} code  The code of the GO/EC number
 */

const BATCH_SIZE = 1000;
const NAMESPACES = ["biological process", "cellular component", "molecular function"];

/**
 * Class that helps organizing GO terms
 */
export default class GOTerms {
    /**
     * Static cache of GO term information
     * @access private
     */
    static goData = new Map();

    /**
     * Creates a new GOTerms
     * TODO
     * @param  {[FACounts]} [go=[]] list of GO terms with their counts
     * @param {bool} [ensureData=true] fetch names for this resultset in the background,ss
     *                                 if false, you must call `ensureData()` on this object.
     * @param {bool} [clone=false] *for internal use*
     */
    constructor({numAnnotatedProteins = null, data = []}, ensureData = true, clone = false) {
        if (clone) return;
        this.numTotalSet = numAnnotatedProteins;
        this.go = new Map();
        Object.entries(data).forEach(([ns, v]) => v.forEach(goTerm => {
            this.go.set(goTerm.code, Object.assign({namespace: ns}, goTerm));
        }));
        GOTerms.addData(Array.from(this.go.values()));

        // Sort values to store and have every namespace
        this.data = {};
        for (const namespace of NAMESPACES) {
            if (namespace in data) {
                this.data[namespace] = Array.from(data[namespace]).sort((a, b) => (b.value - a.value));
            } else {
                this.data[namespace] = [];
            }
        }

        if (ensureData) {
            this.ensureData();
        }
    }

    /**
     * Make a new GOTerms form a clone
     * @param {GOTerms} other
     * @param {GOTerms} [base=null] optional GoTerms instance to reuse
     * @return {GOTerms} filled GOTerms instance
     */
    static clone(other, base = null) {
        let go = base;
        if (base === null) {
            go = new GOTerms({}, true, true);
        }
        go.numTotalSet = other.numTotalSet;
        go.data = other.data;
        go.go = other.go;
        return go;
    }

    /**
    /**
     * Fetch the names of the GO terms and await them
     */
    async ensureData() {
        await GOTerms.addMissingNames(Array.from(this.go.keys()));
    }

    /**
     * @return {int} number of annotated peptides
     */
    getTotalSetSize() {
        return this.numTotalSet;
    }

    /**
     * Returns the originally supplied set of GO Terms
     * sorted by value for a specific namespace
     * @param  {String} namespace The namespace (one of GOTerms.NAMESPACES)
     * @return {[FACounts]} Sorted GO Terms
     */
    sortedTerms(namespace) {
        return this.data[namespace];
    }

    /**
     * Get the count of the GO term in the data set
     * @param  {string} goTerm the GO term (form "GO:0005886")
     * @return {number}        count of the GO term
     */
    getValueOf(goTerm) {
        if (this.go.has(goTerm)) {
            return this.go.get(goTerm).value;
        }
        return 0;
    }

    /**
     * Get the count of the GO term in the data set as fraction of the total size
     * of the set
     * @param  {string} goTerm the GO term (form "GO:0005886")
     * @return {number}        fraction of the GO term
     */
    getFractionOf(goTerm) {
        return this.getValueOf(goTerm) / this.numTotalSet;
    }

    /**
     * Gets the name of associated with an GO Term
     *
     * @param  {string} goTerm The code of the GO Term (like "GO:0006423")
     * @return {string}       The name of the GO Term
     */
    static nameOf(goTerm) {
        if (this.goData.has(goTerm)) {
            return this.goData.get(goTerm).name;
        }
        return "Unknown";
    }

    /**
     * Give the namespace of a GO term
     *
     * @param  {string} goTerm The code of the GO Term
     * @return {[string]}  Ancestors of the GO Term (from specific to generic)
     */
    static namespaceOf(goTerm) {
        if (this.goData.has(goTerm)) {
            return this.goData.get(goTerm).namespace;
        }
        return "Unknown";
    }

    /**
     * Add GO terms to the global map
     * @param {[FACounts]} newTerms list of new GO Terms
     * @access private
     */
    static addData(newTerms) {
        newTerms.forEach(go => {
            if (!this.goData.has(go.code) && go.namespace && go.name) {
                this.goData.set(go.code, go);
            }
        });
    }

    /**
     * Fetch the names and data of the GO terms that are not yet in the static map of
     * names
     * @param {[string]} codes array of GO terms that should be in the cache
     */
    static async addMissingNames(codes) {
        const todo = codes.filter(c => !this.goData.has(c));
        if (todo.length > 0) {
            for (let i = 0; i < todo.length; i += BATCH_SIZE) {
                const res = await postJSON("/private_api/goterms", JSON.stringify({
                    goterms: todo.slice(i, i + BATCH_SIZE),
                }));
                GOTerms.addData(res);
            }
        }
    }

    /**
     * Cone the GO Term information into the current GOTerm static value
     *
     * Needed to work properly with WebWorkers that do not share these statics
     *
     * @param {iteratable<FAInfo>} data inforamtion about GO Terms
     */
    static ingestData(data) {
        GOTerms.goData = data;
    }

    /**
     * @param {[string]} terms the terms to show in the chart (at least one)
     * @return {string} The QuickGo chart URL of the given GO terms
     */
    static quickGOChartURL(terms) {
        return `https://www.ebi.ac.uk/QuickGO/services/ontology/go/terms/${terms.join(",")}/chart`;
    }

    /**
     * Get a list of the 3 root namespaces of the Gene Ontology
     */
    static get NAMESPACES() {
        return NAMESPACES;
    }
}
<|endoftext|>


<commit_before>const calculatePieceValue = (pieceType, color) => {
  let score;
  switch (pieceType) {
    case 'p':
      score = 100;
      break;
    case 'n':
      score = 320;
      break;
    case 'b':
      score = 325;
      break;
    case 'r':
      score = 500;
      break;
    case 'q':
      score = 975;
      break;
    case 'k':
      score = 32767;
      break;
    default:
      return;
  }
  if (color === 'b') {
    score = -score;
  }
  return score;
};

const calculatePositionValue = (pieceType, color, i, j, numRounds) => {
  let chessTable;
  switch (pieceType) {
    case 'p':
      chessTable = [[  0,  0,  0,  0,  0,  0,  0,  0],
                    [ 50, 50, 50, 50, 50, 50, 50, 50],
                    [ 10, 10, 20, 30, 30, 20, 10, 10],
                    [  5,  5, 10, 27, 27, 10,  5,  5],
                    [  0,  0,  0, 25, 25,  0,  0,  0],
                    [  5, -5,-10,  0,  0,-10, -5,  5],
                    [  5, 10, 10,-25,-25, 10, 10,  5],
                    [  0,  0,  0,  0,  0,  0,  0,  0]];
      break;
    case 'n':
      chessTable = [[-50,-40,-30,-30,-30,-30,-40,-50],
                    [-40,-20,  0,  0,  0,  0,-20,-40],
                    [-30,  0, 10, 15, 15, 10,  0,-30],
                    [-30,  5, 15, 20, 20, 15,  5,-30],
                    [-30,  0, 15, 20, 20, 15,  0,-30],
                    [-30,  5, 10, 15, 15, 10,  5,-30],
                    [-40,-20,  0,  5,  5,  0,-20,-40],
                    [-50,-40,-20,-30,-30,-20,-40,-50]];
      break;
    case 'b':
      chessTable = [[-20,-10,-10,-10,-10,-10,-10,-20],
                    [-10,  0,  0,  0,  0,  0,  0,-10],
                    [-10,  0,  5, 10, 10,  5,  0,-10],
                    [-10,  5,  5, 10, 10,  5,  5,-10],
                    [-10,  0, 10, 10, 10, 10,  0,-10],
                    [-10, 10, 10, 10, 10, 10, 10,-10],
                    [-10,  5,  0,  0,  0,  0,  5,-10],
                    [-20,-10,-40,-10,-10,-40,-10,-20]];
      break;
    case 'k':
      chessTable = [[-30,-40,-40,-50,-50,-40,-40,-30],
                    [-30,-40,-40,-50,-50,-40,-40,-30],
                    [-30,-40,-40,-50,-50,-40,-40,-30],
                    [-30,-40,-40,-50,-50,-40,-40,-30],
                    [-20,-30,-30,-40,-40,-30,-30,-20],
                    [-10,-20,-20,-20,-20,-20,-20,-10],
                    [ 20, 20,  0,  0,  0,  0, 20, 20],
                    [ 20, 30, 10,  0,  0, 10, 30, 20]];
      break;
    case 'q':
      chessTable = [[-20,-10,-10,-50,-50,-10,-10,-20],
                    [-10,  0,  0,  0,  0,  0,  0,-10],
                    [-10,  0,  5,  5,  5,  5,  0, 10],
                    [ -5,  0,  5,  5,  5,  5,  0, -5],
                    [  0,  0,  5,  5,  5,  5,  0, -5],
                    [-10,  5,  5,  5,  5,  5,  0,-10],
                    [-10,  0,  5,  0,  0,  0,  0,-10],
                    [-20,-10,-10,-50,-50,-10,-10,-20]];
      break;
    case 'r':
      chessTable = [[  0,  0,  0,  0,  0,  0,  0,  0],
                    [  5, 10, 10, 10, 10, 10, 10,  5],
                    [ -5,  0,  0,  0,  0,  0,  0, -5],
                    [ -5,  0,  5,  5,  5,  5,  0, -5],
                    [ -5,  0,  0,  0,  0,  0,  0, -5],
                    [ -5,  0,  0,  0,  0,  0,  0, -5],
                    [ -5,  0,  0,  0,  0,  0,  0, -5],
                    [  0,  0,  0,  5,  5,  0,  0,  0]];
    default:
      return;
  }
  // late game strategy for king
  if (pieceType === 'k' && numRounds > 20) {
    chessTable = [[-50,-40,-30,-20,-20,-30,-40,-50],
                  [-30,-20,-10,  0,  0,-10,-20,-30],
                  [-30,-10, 20, 30, 30, 20,-10,-30],
                  [-30,-10, 30, 40, 40, 30,-10,-30],
                  [-30,-10, 30, 40, 40, 30,-10,-30],
                  [-30,-10, 20, 30, 30, 20,-10,-30],
                  [-30,-30,  0,  0,  0,  0,-30,-30],
                  [-50,-30,-30,-30,-30,-30,-30,-50]];
  }
  let positionValue = chessTable[i][j];
  if (color === 'b') {
    positionValue = -1 * chessTable[7 - i][7 - j];
  }
  return positionValue;
};

const sumBoardValue = (board, numRounds) => {
  let value = 0;
  for (let i = 0; i < 8; i++) {
    for (let j = 0; j < 8; j++) {
      if (board[i][j]) {
        value += calculatePieceValue(board[i][j].type, board[i][j].color);
        if (['r', 'q'].indexOf(board[i][j].type) === -1) {
          // no special late game strategy for now
          value += calculatePositionValue(board[i][j].type, board[i][j].color, i, j, numRounds);
        }
      }
    }
  }
  return value;
};

const YellowSubsAction = (depth, game, isMaximizingPlayer, numRounds) => {
  const newGameMoves = game.moves();
  let bestMove = -9999;
  let bestMoveFound;

  for (let i = 0; i < newGameMoves.length; i++) {
    const newGameMove = newGameMoves[i];
    game.move(newGameMove);
    const value = minimax(depth - 1, game, -10000, 10000, !isMaximizingPlayer, numRounds);
    game.undo();
    if (value >= bestMove) {
      bestMove = value;
      bestMoveFound = newGameMove;
    }
  }
  return bestMoveFound;
};

const minimax = (depth, game, alpha, beta, isMaximizingPlayer, numRounds) => {
  if (depth === 0) {
    return -sumBoardValue(game.board(), numRounds);
  }

  const newGameMoves = game.moves();

  if (isMaximizingPlayer) {
    let bestMove = -9999;
    for (let i = 0; i < newGameMoves.length; i++) {
      game.move(newGameMoves[i]);
      bestMove = Math.max(bestMove, minimax(depth - 1, game, alpha, beta, !isMaximizingPlayer));
      game.undo();
      alpha = Math.max(alpha, bestMove);
      if (beta <= alpha) {
        return bestMove;
      }
    }
    return bestMove;
  }
  let bestMove = 9999;
  for (let i = 0; i < newGameMoves.length; i++) {
    game.move(newGameMoves[i]);
    bestMove = Math.min(bestMove, minimax(depth - 1, game, alpha, beta, !isMaximizingPlayer));
    game.undo();
    beta = Math.min(beta, bestMove);
    if (beta <= alpha) {
      return bestMove;
    }
  }
  return bestMove;
};

// export { YellowSubsAction };
module.exports = YellowSubsAction;
<commit_msg>V2.5 AI<commit_after>const calculatePieceValue = (pieceType, color) => {
  let score;
  switch (pieceType) {
    case 'p':
      score = 10;
      break;
    case 'n':
      score = 32;
      break;
    case 'b':
      score = 35;
      break;
    case 'r':
      score = 50;
      break;
    case 'q':
      score = 90;
      break;
    case 'k':
      score = 900;
      break;
    default:
      return;
  }
  if (color === 'b') {
    score = -score;
  }
  return score;
};

const calculatePositionValue = (pieceType, color, i, j, numRounds) => {
  let chessTable;
  switch (pieceType) {
    case 'p':
      chessTable = [
        [0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0],
        [5.0,  5.0,  5.0,  5.0,  5.0,  5.0,  5.0,  5.0],
        [1.0,  1.0,  2.0,  3.0,  3.0,  2.0,  1.0,  1.0],
        [0.5,  0.5,  1.0,  2.5,  2.5,  1.0,  0.5,  0.5],
        [0.0,  0.0,  0.0,  2.0,  2.0,  0.0,  0.0,  0.0],
        [0.5, -0.5, -1.0,  0.0,  0.0, -1.0, -0.5,  0.5],
        [0.5,  1.0, 1.0,  -2.0, -2.0,  1.0,  1.0,  0.5],
        [0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0]];
      break;
    case 'n':
      chessTable = [
        [-5.0, -4.0, -3.0, -3.0, -3.0, -3.0, -4.0, -5.0],
        [-4.0, -2.0,  0.0,  0.0,  0.0,  0.0, -2.0, -4.0],
        [-3.0,  0.0,  1.0,  1.5,  1.5,  1.0,  0.0, -3.0],
        [-3.0,  0.5,  1.5,  2.0,  2.0,  1.5,  0.5, -3.0],
        [-3.0,  0.0,  1.5,  2.0,  2.0,  1.5,  0.0, -3.0],
        [-3.0,  0.5,  1.0,  1.5,  1.5,  1.0,  0.5, -3.0],
        [-4.0, -2.0,  0.0,  0.5,  0.5,  0.0, -2.0, -4.0],
        [-5.0, -4.0, -3.0, -3.0, -3.0, -3.0, -4.0, -5.0]
      ];
      break;
    case 'b':
      chessTable = [
        [ -2.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -2.0],
        [ -1.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0, -1.0],
        [ -1.0,  0.0,  0.5,  1.0,  1.0,  0.5,  0.0, -1.0],
        [ -1.0,  0.5,  0.5,  1.0,  1.0,  0.5,  0.5, -1.0],
        [ -1.0,  0.0,  1.0,  1.0,  1.0,  1.0,  0.0, -1.0],
        [ -1.0,  1.0,  1.0,  1.0,  1.0,  1.0,  1.0, -1.0],
        [ -1.0,  0.5,  0.0,  0.0,  0.0,  0.0,  0.5, -1.0],
        [ -2.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -2.0]
      ];
      break;
    case 'k':
      chessTable = [
        [ -3.0, -4.0, -4.0, -5.0, -5.0, -4.0, -4.0, -3.0],
        [ -3.0, -4.0, -4.0, -5.0, -5.0, -4.0, -4.0, -3.0],
        [ -3.0, -4.0, -4.0, -5.0, -5.0, -4.0, -4.0, -3.0],
        [ -3.0, -4.0, -4.0, -5.0, -5.0, -4.0, -4.0, -3.0],
        [ -2.0, -3.0, -3.0, -4.0, -4.0, -3.0, -3.0, -2.0],
        [ -1.0, -2.0, -2.0, -2.0, -2.0, -2.0, -2.0, -1.0],
        [  2.0,  2.0,  0.0,  0.0,  0.0,  0.0,  2.0,  2.0],
        [  2.0,  3.0,  1.0,  0.0,  0.0,  1.0,  3.0,  2.0]
      ];
      break;
    case 'q':
      chessTable = [
        [ -2.0, -1.0, -1.0, -0.5, -0.5, -1.0, -1.0, -2.0],
        [ -1.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0, -1.0],
        [ -1.0,  0.0,  0.5,  0.5,  0.5,  0.5,  0.0, -1.0],
        [ -0.5,  0.0,  0.5,  0.5,  0.5,  0.5,  0.0, -0.5],
        [  0.0,  0.0,  0.5,  0.5,  0.5,  0.5,  0.0, -0.5],
        [ -1.0,  0.5,  0.5,  0.5,  0.5,  0.5,  0.0, -1.0],
        [ -1.0,  0.0,  0.5,  0.0,  0.0,  0.0,  0.0, -1.0],
        [ -2.0, -1.0, -1.0, -0.5, -0.5, -1.0, -1.0, -2.0]
      ];
      break;
    case 'r':
      chessTable = [
        [  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0],
        [  0.5,  1.0,  1.0,  1.0,  1.0,  1.0,  1.0,  0.5],
        [ -0.5,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0, -0.5],
        [ -0.5,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0, -0.5],
        [ -0.5,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0, -0.5],
        [ -0.5,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0, -0.5],
        [ -0.5,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0, -0.5],
        [  0.0,  0.0, 0.0,  0.5,  0.5,  0.0,  0.0,  0.0]
      ];
      break;
    default:
      return;
  }
  // late game strategy for king
  if (pieceType === 'k' && numRounds > 20) {
    chessTable = [
      [ -5.0, -4.0, -3.0, -2.0, -2.0, -3.0, -4.0, -5.0],
      [ -3.0, -2.0, -1.0,  0.0,  0.0, -1.0, -2.0, -3.0],
      [ -3.0, -1.0,  2.0,  3.0,  3.0,  2.0, -1.0, -3.0],
      [ -3.0, -1.0,  3.0,  4.0,  4.0,  3.0, -1.0, -3.0],
      [ -3.0, -1.0,  3.0,  4.0,  4.0,  3.0, -1.0, -3.0],
      [ -3.0, -1.0,  2.0,  3.0,  3.0,  2.0, -1.0, -3.0],
      [ -3.0, -3.0,  0.0,  0.0,  0.0,  0.0, -3.0, -3.0],
      [ -5.0, -3.0, -3.0, -3.0, -3.0, -3.0, -3.0, -5.0]
    ];
  }
  let positionValue = chessTable[i][j];
  if (color === 'b') {
    positionValue = -1 * chessTable[7 - i][7 - j];
  }
  return positionValue;
};

const sumBoardValue = (board, numRounds) => {
  let value = 0;
  for (let i = 0; i < 8; i++) {
    for (let j = 0; j < 8; j++) {
      if (board[i][j]) {
        value += calculatePieceValue(board[i][j].type, board[i][j].color);
        if (['r', 'q'].indexOf(board[i][j].type) === -1) {
          // no special late game strategy for now besides king
          value += calculatePositionValue(board[i][j].type, board[i][j].color, i, j, numRounds);
        }
      }
    }
  }
  return value;
};

const minimax = (depth, game, alpha, beta, isMaximizingPlayer, numRounds) => {
  if (depth === 0) {
    return -sumBoardValue(game.board(), numRounds);
  }

  const newGameMoves = game.moves();

  if (isMaximizingPlayer) {
    let bestMove = -9999;
    for (let i = 0; i < newGameMoves.length; i++) {
      game.move(newGameMoves[i]);
      bestMove = Math.max(bestMove, minimax(depth - 1, game, alpha, beta, !isMaximizingPlayer));
      game.undo();
      alpha = Math.max(alpha, bestMove);
      if (beta <= alpha) {
        return bestMove;
      }
    }
    return bestMove;
  }
  let bestMove = 9999;
  for (let i = 0; i < newGameMoves.length; i++) {
    game.move(newGameMoves[i]);
    bestMove = Math.min(bestMove, minimax(depth - 1, game, alpha, beta, !isMaximizingPlayer));
    game.undo();
    beta = Math.min(beta, bestMove);
    if (beta <= alpha) {
      return bestMove;
    }
  }
  return bestMove;
};

const YellowSubsAction = (depth, game, isMaximizingPlayer, numRounds) => {
  const newGameMoves = game.moves();
  let bestMove = -9999;
  let bestMoveFound;

  for (let i = 0; i < newGameMoves.length; i++) {
    const newGameMove = newGameMoves[i];
    game.move(newGameMove);
    const value = minimax(depth - 1, game, -10000, 10000, !isMaximizingPlayer, numRounds);
    game.undo();
    if (value >= bestMove) {
      bestMove = value;
      bestMoveFound = newGameMove;
    }
  }
  return bestMoveFound;
};

// export { YellowSubsAction };
module.exports = YellowSubsAction;
<|endoftext|>


<commit_before>import { Quote } from './ActionTypes';
import { callAPI } from '../utils/http';
import { pushState } from 'redux-react-router';
import { startSubmit, stopSubmit } from 'redux-form';

export function fetchAllApproved() {
  return callAPI({
    types: [
      Quote.FETCH_ALL_APPROVED_BEGIN,
      Quote.FETCH_ALL_APPROVED_SUCCESS,
      Quote.FETCH_ALL_APPROVED_FAILURE
    ],
    endpoint: '/quotes/'
  });
}

export function fetchAllUnapproved() {
  return callAPI({
    types: [
      Quote.FETCH_ALL_UNAPPROVED_BEGIN,
      Quote.FETCH_ALL_UNAPPROVED_SUCCESS,
      Quote.FETCH_ALL_UNAPPROVED_FAILURE
    ],
    endpoint: '/quotes/?approved=false'
  });
}

export function fetchQuote(quoteId) {
  return callAPI({
    types: [
      Quote.FETCH_BEGIN,
      Quote.FETCH_SUCCESS,
      Quote.FETCH_FAILURE
    ],
    endpoint: `/quotes/${quoteId}/`,
    method: 'get',
    meta: {
      quoteId
    }
  });
}

export function like(quoteId) {
  return callAPI({
    types: [
      Quote.LIKE_BEGIN,
      Quote.LIKE_SUCCESS,
      Quote.LIKE_FAILURE
    ],
    endpoint: `/quotes/${quoteId}/like/`,
    method: 'post'
  });
}

export function unlike(quoteId) {
  return callAPI({
    types: [
      Quote.UNLIKE_BEGIN,
      Quote.UNLIKE_SUCCESS,
      Quote.UNLIKE_FAILURE
    ],
    endpoint: `/quotes/${quoteId}/unlike/`,
    method: 'post'
  });
}

export function approve(quoteId) {
  return callAPI({
    types: [
      Quote.APPROVE_BEGIN,
      Quote.APPROVE_SUCCESS,
      Quote.APPROVE_FAILURE
    ],
    endpoint: `/quotes/${quoteId}/approve/`,
    method: 'put'
  });
}

export function unapprove(quoteId) {
  return callAPI({
    types: [
      Quote.UNAPPROVE_BEGIN,
      Quote.UNAPPROVE_SUCCESS,
      Quote.UNAPPROVE_FAILURE
    ],
    endpoint: `/quotes/${quoteId}/unapprove/`,
    method: 'put'
  });
}

export function addQuotes({ text, source }) {
  return (dispatch, getState) => {
    dispatch(startSubmit('addQuote'));

    dispatch(callAPI({
      types: [Quote.ADD_BEGIN, Quote.ADD_SUCCESS, Quote.ADD_FAILURE],
      endpoint: '/quotes/',
      method: 'post',
      body: {
        title: 'Tittel',
        text,
        source,
        approved: false
      }
    })).then(
      () => {
        stopSubmit('addQuote');
        pushState(null, '/quotes');
      },
      (error) => {
        const errors = { ...error.response.body };
        if (errors.text) {
          errors.text = errors.text[0];
        }
        if (errors.source) {
          errors.source = errors.source[0];
        }
        dispatch(stopSubmit('addQuote', errors));
      }
    );
  };
}

export function deleter(quoteId) {
  return callAPI({
    types: [Quote.DELETE_BEGIN, Quote.DELETE_SUCCESS, Quote.DELETE_FAILURE],
    endpoint: `/quotes/${quoteId}/`,
    method: 'del',
    meta: {
      quoteId
    }
  });
}
<commit_msg>Add missing dispatch calls<commit_after>import { Quote } from './ActionTypes';
import { callAPI } from '../utils/http';
import { pushState } from 'redux-react-router';
import { startSubmit, stopSubmit } from 'redux-form';

export function fetchAllApproved() {
  return callAPI({
    types: [
      Quote.FETCH_ALL_APPROVED_BEGIN,
      Quote.FETCH_ALL_APPROVED_SUCCESS,
      Quote.FETCH_ALL_APPROVED_FAILURE
    ],
    endpoint: '/quotes/'
  });
}

export function fetchAllUnapproved() {
  return callAPI({
    types: [
      Quote.FETCH_ALL_UNAPPROVED_BEGIN,
      Quote.FETCH_ALL_UNAPPROVED_SUCCESS,
      Quote.FETCH_ALL_UNAPPROVED_FAILURE
    ],
    endpoint: '/quotes/?approved=false'
  });
}

export function fetchQuote(quoteId) {
  return callAPI({
    types: [
      Quote.FETCH_BEGIN,
      Quote.FETCH_SUCCESS,
      Quote.FETCH_FAILURE
    ],
    endpoint: `/quotes/${quoteId}/`,
    method: 'get',
    meta: {
      quoteId
    }
  });
}

export function like(quoteId) {
  return callAPI({
    types: [
      Quote.LIKE_BEGIN,
      Quote.LIKE_SUCCESS,
      Quote.LIKE_FAILURE
    ],
    endpoint: `/quotes/${quoteId}/like/`,
    method: 'post'
  });
}

export function unlike(quoteId) {
  return callAPI({
    types: [
      Quote.UNLIKE_BEGIN,
      Quote.UNLIKE_SUCCESS,
      Quote.UNLIKE_FAILURE
    ],
    endpoint: `/quotes/${quoteId}/unlike/`,
    method: 'post'
  });
}

export function approve(quoteId) {
  return callAPI({
    types: [
      Quote.APPROVE_BEGIN,
      Quote.APPROVE_SUCCESS,
      Quote.APPROVE_FAILURE
    ],
    endpoint: `/quotes/${quoteId}/approve/`,
    method: 'put'
  });
}

export function unapprove(quoteId) {
  return callAPI({
    types: [
      Quote.UNAPPROVE_BEGIN,
      Quote.UNAPPROVE_SUCCESS,
      Quote.UNAPPROVE_FAILURE
    ],
    endpoint: `/quotes/${quoteId}/unapprove/`,
    method: 'put'
  });
}

export function addQuotes({ text, source }) {
  return (dispatch, getState) => {
    dispatch(startSubmit('addQuote'));

    dispatch(callAPI({
      types: [Quote.ADD_BEGIN, Quote.ADD_SUCCESS, Quote.ADD_FAILURE],
      endpoint: '/quotes/',
      method: 'post',
      body: {
        title: 'Tittel',
        text,
        source,
        approved: false
      }
    })).then(
      () => {
        dispatch(stopSubmit('addQuote'));
        dispatch(pushState(null, '/quotes'));
      },
      (error) => {
        const errors = { ...error.response.body };
        if (errors.text) {
          errors.text = errors.text[0];
        }
        if (errors.source) {
          errors.source = errors.source[0];
        }
        dispatch(stopSubmit('addQuote', errors));
      }
    );
  };
}

export function deleter(quoteId) {
  return callAPI({
    types: [Quote.DELETE_BEGIN, Quote.DELETE_SUCCESS, Quote.DELETE_FAILURE],
    endpoint: `/quotes/${quoteId}/`,
    method: 'del',
    meta: {
      quoteId
    }
  });
}
<|endoftext|>


<commit_before>'use strict';

/* eslint-env node */

const WHITESPACE = /^\s+$/;

module.exports = class {
  transform(ast) {
    let preStack = [];

    this.syntax.traverse(ast, {
      TextNode(node) {
        if (preStack.length === 0 && WHITESPACE.test(node.chars)) {
          node.chars = ' ';
        }
      },

      BlockStatement: {
        enter(node) {
          if (node.path.original === 'no-minify') {
            preStack.push(true);
          }
        },

        exit(node) {
          if (node.path.original === 'no-minify') {
            preStack.pop();
          }
        },
      },

      Program: {
        enter(node) {
          if (preStack.length !== 0) {
            return;
          }

          let firstChild = node.body[0];
          if (isWhitespaceTextNode(firstChild)) {
            node.body.shift();
          }

          let lastChild = node.body[node.body.length - 1];
          if (isWhitespaceTextNode(lastChild)) {
            node.body.pop();
          }
        },

        exit(node) {
          node.body = stripNoMinifyBlocks(node.body);
        },
      },

      ElementNode: {
        enter(node) {
          if (node.tag === 'pre') {
            preStack.push(true);
          }

          if (preStack.length !== 0) {
            return;
          }

          let firstChild = node.children[0];
          if (isWhitespaceTextNode(firstChild)) {
            node.children.shift();
          }

          let lastChild = node.children[node.children.length - 1];
          if (isWhitespaceTextNode(lastChild)) {
            node.children.pop();
          }
        },

        exit(node) {
          node.children = stripNoMinifyBlocks(node.children);

          if (node.tag === 'pre') {
            preStack.pop();
          }
        }
      },
    });

    return ast;
  }
};

function isWhitespaceTextNode(node) {
  return node && node.type === 'TextNode' && WHITESPACE.test(node.chars);
}

function stripNoMinifyBlocks(nodes) {
  return nodes.map(node => {
    if (node.type === 'BlockStatement' && node.path.original === 'no-minify') {
      return node.program.body;
    }
    return node;
  }).reduce((a, b) => a.concat(b), []);
}
<commit_msg>Extract ASTPlugin factory<commit_after>'use strict';

/* eslint-env node */

const WHITESPACE = /^\s+$/;

module.exports = class HBSMinifierPlugin {
  static createASTPlugin() {
    let preStack = [];

    let visitor = {
      TextNode(node) {
        if (preStack.length === 0 && WHITESPACE.test(node.chars)) {
          node.chars = ' ';
        }
      },

      BlockStatement: {
        enter(node) {
          if (node.path.original === 'no-minify') {
            preStack.push(true);
          }
        },

        exit(node) {
          if (node.path.original === 'no-minify') {
            preStack.pop();
          }
        },
      },

      Program: {
        enter(node) {
          if (preStack.length !== 0) {
            return;
          }

          let firstChild = node.body[0];
          if (isWhitespaceTextNode(firstChild)) {
            node.body.shift();
          }

          let lastChild = node.body[node.body.length - 1];
          if (isWhitespaceTextNode(lastChild)) {
            node.body.pop();
          }
        },

        exit(node) {
          node.body = stripNoMinifyBlocks(node.body);
        },
      },

      ElementNode: {
        enter(node) {
          if (node.tag === 'pre') {
            preStack.push(true);
          }

          if (preStack.length !== 0) {
            return;
          }

          let firstChild = node.children[0];
          if (isWhitespaceTextNode(firstChild)) {
            node.children.shift();
          }

          let lastChild = node.children[node.children.length - 1];
          if (isWhitespaceTextNode(lastChild)) {
            node.children.pop();
          }
        },

        exit(node) {
          node.children = stripNoMinifyBlocks(node.children);

          if (node.tag === 'pre') {
            preStack.pop();
          }
        }
      },
    };

    return { name: 'hbs-minifier-plugin', visitor };
  }

  transform(ast) {
    let plugin = HBSMinifierPlugin.createASTPlugin();

    this.syntax.traverse(ast, plugin.visitor);

    return ast;
  }
};

function isWhitespaceTextNode(node) {
  return node && node.type === 'TextNode' && WHITESPACE.test(node.chars);
}

function stripNoMinifyBlocks(nodes) {
  return nodes.map(node => {
    if (node.type === 'BlockStatement' && node.path.original === 'no-minify') {
      return node.program.body;
    }
    return node;
  }).reduce((a, b) => a.concat(b), []);
}
<|endoftext|>


<commit_before>var demo_data = require("./demo_data.js");
var url = require("url");

module.exports = function (req, res, request, callback, isLoginCheck){

	var token = req.query.token;
	if (/^([0-9a-z\-]+)$/.test(token) == false) {
        console.log(token);
		res.statusCode = 406;
		res.send({
			error: global.Errors.InvalidToken
		});
		return false;
	}
    if (!token) {
		res.statusCode = 406;
		res.send({
			error: global.Errors.NoToken
		});
		return false;
	}

    if (token == "00000000-0000-0000-0000-000000000000")
    {
        var path = url.parse(req.url).pathname.substr(1);

        if (path == "logout") {
            res.send({
                result: 'Bye, Dummy account.'
            });
            return;
        }
        if (path == "login") {
            res.send({
                result: true
            });
            return;
        }

        var pathname = url.parse(req.url).pathname;

        setTimeout (function() {
            res.send({
                result: demo_data[path]['result']
            });
        }
        , 6000);
        return;
    }

	global.db.GetUser(token, function (store) {
		if (store) {
			if (store.cookies && store.LoginData && isLoginCheck == 1)
			{
				// Checking if user have logged in on /load
				callback(req, res, store);
			}
			else if (store.cookies && isLoginCheck == -1)
			{
				callback(req, res, store);
			}
			else if (store.cookies && store.LoggedIn && isLoginCheck == 0) {
				var url = global.setting.NeonURL + 'Registration/ViewStudentAttendance.aspx';
				var j = request.jar();
				var cookie = request.cookie(store.cookies);
				j.setCookie(cookie, global.setting.NeonURL);

				request({
						url: url,
						timeout: global.setting.DefaultTimeout,
						headers: global.setting.DefaultHeaders,
						followRedirect : false,
						jar : j
					}, function (error, response, body) {
                        if (error) {
                            console.log(error);
                            res.statusCode = 406;
							res.send({
								error: global.Errors.NetworkError
							});
                        }
						else if(typeof response.headers !== 'undefined' && response.headers['location']) {
                            res.statusCode = 406;
							res.send({
								error: global.Errors.NeONExpired
							});
						}
						else {
							callback(req, res, store);
						}
					}
				);

			}
            else {
				res.statusCode = 406;
				res.send({
					error: global.Errors.LoginFirst
				});
				return false;
			}
		}
        else if (store == null) {
            res.statusCode = 406;
            res.send({
                error: global.Errors.DatabaseError
            });
        }
		else {
            console.log(store);
			res.statusCode = 406;
			res.send({
				error: global.Errors.APIExpired
			});
			return false;
		}
	});

}<commit_msg>Temp data response time<commit_after>var demo_data = require("./demo_data.js");
var url = require("url");

module.exports = function (req, res, request, callback, isLoginCheck){

	var token = req.query.token;
	if (/^([0-9a-z\-]+)$/.test(token) == false) {
        console.log(token);
		res.statusCode = 406;
		res.send({
			error: global.Errors.InvalidToken
		});
		return false;
	}
    if (!token) {
		res.statusCode = 406;
		res.send({
			error: global.Errors.NoToken
		});
		return false;
	}

    if (token == "00000000-0000-0000-0000-000000000000")
    {
        var path = url.parse(req.url).pathname.substr(1);

        if (path == "logout") {
            res.send({
                result: 'Bye, Dummy account.'
            });
            return;
        }
        if (path == "login") {
            res.send({
                result: true
            });
            return;
        }

        var pathname = url.parse(req.url).pathname;

        setTimeout (function() {
            res.send({
                result: demo_data[path]['result']
            });
        }
        , 3000);
        return;
    }

	global.db.GetUser(token, function (store) {
		if (store) {
			if (store.cookies && store.LoginData && isLoginCheck == 1)
			{
				// Checking if user have logged in on /load
				callback(req, res, store);
			}
			else if (store.cookies && isLoginCheck == -1)
			{
				callback(req, res, store);
			}
			else if (store.cookies && store.LoggedIn && isLoginCheck == 0) {
				var url = global.setting.NeonURL + 'Registration/ViewStudentAttendance.aspx';
				var j = request.jar();
				var cookie = request.cookie(store.cookies);
				j.setCookie(cookie, global.setting.NeonURL);

				request({
						url: url,
						timeout: global.setting.DefaultTimeout,
						headers: global.setting.DefaultHeaders,
						followRedirect : false,
						jar : j
					}, function (error, response, body) {
                        if (error) {
                            console.log(error);
                            res.statusCode = 406;
							res.send({
								error: global.Errors.NetworkError
							});
                        }
						else if(typeof response.headers !== 'undefined' && response.headers['location']) {
                            res.statusCode = 406;
							res.send({
								error: global.Errors.NeONExpired
							});
						}
						else {
							callback(req, res, store);
						}
					}
				);

			}
            else {
				res.statusCode = 406;
				res.send({
					error: global.Errors.LoginFirst
				});
				return false;
			}
		}
        else if (store == null) {
            res.statusCode = 406;
            res.send({
                error: global.Errors.DatabaseError
            });
        }
		else {
            console.log(store);
			res.statusCode = 406;
			res.send({
				error: global.Errors.APIExpired
			});
			return false;
		}
	});

}<|endoftext|>


<commit_before>'use strict';

var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var runSequence = require('run-sequence');
var js = '*.js';
var tests = 'test/**/*.js';

gulp.task('default', ['test'], function(cb){
  gulp.watch([js, tests], ['test']);
});

gulp.task('test', function(cb){
  runSequence('jshint', 'mocha', cb);
});

gulp.task('jshint', function () {
  return gulp.src([js, tests])
    .pipe($.jshint())
    .pipe($.jshint.reporter('jshint-stylish'));
});

gulp.task('mocha', function () {
  return gulp.src(tests, {read: false})
        .pipe($.mocha({reporter: 'spec'}));
});
<commit_msg>fail tests when jshint doesn't pass<commit_after>'use strict';

var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var runSequence = require('run-sequence');
var js = '*.js';
var tests = 'test/**/*.js';

gulp.task('default', ['test'], function(cb){
  gulp.watch([js, tests], ['test']);
});

gulp.task('test', function(cb){
  runSequence('jshint', 'mocha', cb);
});

gulp.task('jshint', function () {
  return gulp.src([js, tests])
    .pipe($.jshint())
    .pipe($.jshint.reporter('jshint-stylish'))
    .pipe($.jshint.reporter('fail'));
});

gulp.task('mocha', function () {
  return gulp.src(tests, {read: false})
        .pipe($.mocha({reporter: 'spec'}));
});
<|endoftext|>