<commit_before>/*#ifndef(UMD)*/
"use strict";
/*global _gpfFunc*/ // Create a new function using the source
/*global _gpfIgnore*/ // Helper to remove unused parameter warning
/*global _gpfGenDefHandler*/ // Class handler for class types (interfaces...)
/*global _gpfResolveScope*/ // Translate the parameter into a valid scope
/*global _gpfBuildParamArray*/ // Build a parameter array
/*global _gpfDoApply*/ // Apply the parameter array through a function
/*global _gpfGetClassDefinition*/ // Get GPF class definition for a constructor
// /*#endif*/

var
    /**
     * gpf.attributes shortcut
     *
     * @type {Object}
     * @private
     */
    _gpfA = gpf.attributes = {},

    /**
     * Used for empty members
     *
     * @type {gpf.attributes.Array}
     * @private
     */
    _gpfEmptyMemberArray = 0,

    /**
     * Generates a factory capable of creating a new instance of a class
     *
     * @param {Function} objectClass Object constructor
     * @param {String} name Alias name (will be prefixed by $)
     * @private
     * @closure
     */
    _gpfAlias = function (objectClass, name) {
        name = "$" + name;
        gpf[name] = (function(){
            var Proxy = (_gpfFunc("return function " + name + "(args) {" +
                "this.constructor.apply(this, args);" +
            "};"))();
            Proxy.prototype = objectClass.prototype;
            return function() {
                return new Proxy(arguments);
            };
        }());
    },

    /**
     * gpf.define handler for attributes
     *
     * @type {Function}
     * @private
     */
    _gpfDefAttrBase = _gpfGenDefHandler("gpf.attributes", "Attribute"),

    /**
     * gpf.define for attributes
     *
     * @param {String} name Attribute name. If it contains a dot, it is
     * treated as absolute contextual. Otherwise, it is relative to
     * "gpf.attributes". If starting with $ (and no dot), the contextual name
     * will be the "gpf.attributes." + name(without $) + "Attribute" and an
     * alias is automatically created (otherwise, use $Alias attribute on class)
     * @param {Function|string} [base=undefined] base Base attribute
     * (or contextual name)
     * @param {Object} [definition=undefined] definition Attribute definition
     * @return {Function}
     * @private
     */
    _gpfDefAttr = function (name, base, definition) {
        var
            isAlias = name.charAt(0) === "$",
            fullName,
            result;
        if (isAlias) {
            name = name.substr(1);
            fullName = name + "Attribute";
        } else {
            fullName = name;
        }
        result = _gpfDefAttrBase(fullName, base, definition);
        if (isAlias) {
            _gpfAlias(result, name);
        }
        return result;
    };

/**
 * Base class for any attribute
 *
 * @class gpf.attributes.Attribute
 */
_gpfDefAttr("Attribute", {

    protected: {

        /**
         * Name of the member the attribute is associated to
         *
         * @type {String}
         * @protected
         * @friend {gpf.attributes.add}
         */
        _member: "",

        /**
         * This method is the implementation of the attribute: it receives
         * the prototype to alter.
         *
         * NOTE: this is called *after* all declared members are set
         *
         * @param {Object} objPrototype Class prototype
         * @protected
         * @friend {gpf.attributes.add}
         */
        _alterPrototype: function /*abstract*/ (objPrototype) {
            _gpfIgnore(objPrototype);
        }

    },

    public: {

        /**
         * Get the member name
         *
         * @return {String}
         */
        member: function () {
            return this._member;
        }

    }

});

/**
 * Generates an alias for the attribute. An alias is a factory function that
 * allocates an attribute instance (parameters are forwarded).
 * As a result, instead of using:
 * "[Class]" : [new gpf.attributes.AliasAttribute("Name")]
 * It is reduced to:
 * "[Class]" : [$Alias("Name")]
 *
 * @param {String} name Name of the alias to build below gpf
 *
 * @class gpf.attributes.AliasAttribute
 * @extends gpf.attributes.Attribute
 * @alias gpf.$Alias
 */
_gpfDefAttr("$Alias", {

    private: {

        /**
         * Name of the alias to create
         *
         * @type {String}
         * @private
         */
        _name: ""

    },

    protected: {

        /**
         * @inheritDoc gpf.attributes.Attribute:_alterPrototype
         */
        _alterPrototype: function (objPrototype) {
            _gpfAlias(objPrototype.constructor, this._name);
        }

    },

    public: {

        /**
         * Defines an alias
         *
         * @param {String} name Name of the alias to create
         * @constructor
         */
        constructor: function (name) {
            this._name = name;
        }

    }

});

/**
 * Attribute array, generally used to list attributes on a class member
 *
 * @class gpf.attributes.Array
 * TODO implements gpf.interfaces.IReadOnlyArray
 */
gpf.define("gpf.attributes.Array", {

    private: {

        /**
         * @type {gpf.attributes.Attribute[]}
         * @private
         */
        _array: []

    },

    public: {

        /**
         * @constructor
         */
        constructor: function () {
            this._array = []; // Create a new instance of the array
        },

        /**
         * Gives the number of attributes in the array
         *
         * @return {Number}
         */
        count: function () {
            return this._array.length;
        },

        /**
         * Return the first occurrence of the expected class
         *
         * @param {gpf.attributes.Attribute} expectedClass the class to
         * match
         * @return {gpf.attributes.Attribute}
         */
        has: function (expectedClass) {
            gpf.ASSERT("function" === typeof expectedClass,
                "Expected a class parameter");
            gpf.ASSERT(
                expectedClass.prototype instanceof _gpfA.Attribute,
                "Expected an Attribute-like class parameter");
            var
                idx,
                array = this._array,
                len = array.length,
                item;
            for (idx = 0; idx < len; ++idx) {
                item = array[idx];
                if (item instanceof expectedClass) {
                    return item;
                }
            }
            return null;
        },

        /**
         * Returns a new array with all attributes matching the expected
         * class
         *
         * @param {Function} expectedClass the class to match
         * @return {gpf.attributes.Array}
         */
        filter: function (expectedClass) {
            gpf.ASSERT("function" === typeof expectedClass,
                "Expected a class parameter");
            gpf.ASSERT(
                expectedClass.prototype instanceof _gpfA.Attribute,
                "Expected an Attribute-like class parameter");
            var
                idx,
                array = this._array,
                len = array.length,
                attribute,
                result = new _gpfA.Array(),
                resultArray = result._array;
            for (idx = 0; idx < len; ++idx) {
                attribute = array[idx];
                if (attribute instanceof expectedClass) {
                    resultArray.push(attribute);
                }
            }
            return result;
        },

        /**
         * Apply the callback for each attribute in the array.
         * If the callback returns anything, the loop stops and the result
         * is returned to the caller.
         *
         * @param {Function} callback, defined with parameters
         * * {gpf.attributes.Attribute} attribute
         * No result is expected
         * @param {Object} [scope=undefined] scope
         * @param {*} [params=undefined] params Additional parameters
         * appended at the end of the expected parameter list
         * @return {*}
         */
        each: function (callback, scope, params) {
            scope = _gpfResolveScope(scope);
            params = _gpfBuildParamArray(1, params);
            var
                idx,
                array = this._array,
                len = array.length,
                result;
            for (idx = 0; idx < len; ++idx) {
                result = _gpfDoApply(callback, scope, params, array[idx]);
                if (undefined !== result) {
                    return result;
                }
            }
        }
    }

});

/**
 * Attribute map, generally used to list attributes of a class
 *
 * @class gpf.attributes.Map
 */
gpf.define("gpf.attributes.Map", {

    private: {

        /**
         * @type {Object} Map(String,gpf.attributes.Array)
         * @private
         */
        _members: {},

        /**
         * @type {Number}
         * @private
         */
        _count: 0,

        /**
         * Copy the content of this map to a new one
         *
         * @param {gpf.attributes.Map} attributesMap recipient of the copy
         * @param {Function} [callback=undefined] callback callback function
         * to test if the mapping should be added
         * @param {*} [param=undefined] param additional parameter for the
         * callback
         * @private
         */
        _copyTo: function (attributesMap, callback, param) {
            var
                members = this._members,
                member,
                array,
                idx,
                attribute;
            if (this._count) {
                for (member in members) {
                    if (members.hasOwnProperty(member)) {
                        array = members[member]._array;
                        for (idx = 0; idx < array.length; ++idx) {
                            attribute = array[ idx ];
                            if (!callback
                                || callback(member, attribute, param)) {
                                attributesMap.add(member, attribute);
                            }
                        }
                    }
                }
            }
        },

        /**
         * Callback for _copyTo, test if attribute is of a given class
         *
         * @param {String} member
         * @param {gpf.attributes.Attribute} attribute
         * @param {Function} expectedClass
         * @return {Boolean}
         * @private
         */
        _filterCallback: function (member, attribute, expectedClass) {
            _gpfIgnore(member);
            return attribute instanceof expectedClass;
        }

    },

    public: {

        /**
         * @param {Object} [object=undefined] object Object to read
         *        attributes from
         * @constructor
         */
        constructor: function (object) {
            this._members = {}; // Creates a new dictionary
            this._count = 0;
            if (undefined !== object) {
                this.fillFromObject(object);
            }
        },

        /**
         * Gives the total number of attributes enclosed in the map
         *
         * @return {Number}
         */
        count: function () {
            return this._count;
        },

        /**
         * Associate an attribute to a member
         *
         * @param {String} member member name
         * @param {gpf.attributes.Attribute} attribute attribute to map
         */
        add: function (member, attribute) {
            var array = this._members[member];
            if (undefined === array) {
                array = this._members[member] = new _gpfA.Array();
            }
            array._array.push(attribute);
            ++this._count;
        },

        /**
         * Fill the map using object's attributes
         *
         * @param {Object} object object to get attributes from
         * @return {Number} number of attributes in the resulting map
         */
        fillFromObject: function (object) {
            var classDef = _gpfGetClassDefinition(object.constructor);
            return this.fillFromClassDef(classDef);
        },

        /**
         * Fill the map using class definition object
         *
         * @param {gpf.classDef} classDef class definition
         * @return {Number} number of attributes in the resulting map
         */
        fillFromClassDef: function (classDef) {
            var
                attributes,
                Super;
            while (classDef) { // !undefined && !null
                attributes = classDef.attributes();
                if (attributes) {
                    attributes._copyTo(this);
                }
                Super = classDef.Super()
                if (Super !== Object) { // Can't go upper
                    classDef = _gpfGetClassDefinition(Super);
                } else {
                    break;
                }
            }
            return this._count;
        },

        /**
         * Creates a new map that contains only instances of the given
         * attribute class
         *
         * @param {Function} expectedClass
         * @return {gpf.attributes.Map}
         */
        filter: function (expectedClass) {
            gpf.ASSERT("function" === typeof expectedClass,
                "Expected a class parameter");
            gpf.ASSERT( expectedClass.prototype instanceof _gpfA.Attribute,
                "Expected an Attribute-like class parameter");
            var result = new _gpfA.Map();
            this._copyTo(result, this._filterCallback, expectedClass);
            return result;
        },

        /**
         * Returns the array of map associated to a member
         *
         * @param {String} name
         * @return {gpf.attributes.Array}
         */
        member: function (name) {
            /**
             * When member is a known Object member (i.e. constructor),
             * this generates weird results. Filter out by testing the
             * result type.
             */
            var result = this._members[name];
            if (undefined === result
                || !(result instanceof _gpfA.Array)) {
                if (0 === _gpfEmptyMemberArray) {
                    _gpfEmptyMemberArray = new _gpfA.Array();
                }
                result = _gpfEmptyMemberArray;
            }
            return result;
        },

        /**
         * Returns the list of members stored in this map
         *
         * @perf_warn Result is computed on each call
         * @return {String[]}
         */
        members: function () {
            var
                members = this._members,
                result = [],
                member;
            for (member in members) {
                if (members.hasOwnProperty(member)) {
                    result.push(member);
                }
            }
            return result;
        },

        /**
         * Apply the callback for each member in the map
         * If the callback returns anything, the loop stops and the result
         * is returned to the caller.
         *
         * @param {Function} callback, defined with parameters
         * * {String} member
         * * {gpf.attributes.Array} attributes
         * No result is expected
         * @param {Object} [scope=undefined] scope
         * @param {*} [params=undefined] params Additional parameters
         * appended at the end of the expected parameter list
         * @return {*}
         */
        each: function (callback, scope, params) {
            scope = _gpfResolveScope(scope);
            params = _gpfBuildParamArray(2, params);
            var
                members = this._members,
                member,
                result;
            for (member in members) {
                if (members.hasOwnProperty(member)) {
                    result = _gpfDoApply(callback, scope, params,
                        member, members[member]);
                    if (undefined !== result) {
                        return result;
                    }
                }
            }
        },

        /**
         * Add the attributes contained in the map to the given prototype
         *
         * @param {Function} objectClass
         */
        addTo: function (objectClass) {
            var
                members = this._members,
                member;
            for (member in members) {
                if (members.hasOwnProperty(member)) {
                    _gpfA.add(objectClass, member,
                        members[member]);
                }
            }
        }

    }

});

/**
 * Add the attribute list to the given prototype associated with the
 * provided member name
 *
 * @param {Function} objectClass class constructor
 * @param {String} name member name
 * @param {gpf.attributes.Attribute[]} attributes
 */
_gpfA.add = function (objectClass, name, attributes) {
    var
        attributeList,
        len,
        idx,
        attribute;
    attributeList = _gpfGetClassDefinition(objectClass).attributes();
    len = attributes.length;
    for (idx = 0; idx < len; ++idx) {
        attribute = attributes[idx];
        attribute._member = name; // Assign member name
        attributeList.add(name, attribute);
        attribute._alterPrototype(objectClass.prototype);
    }
};<commit_msg>JSHint fix<commit_after>/*#ifndef(UMD)*/
"use strict";
/*global _gpfFunc*/ // Create a new function using the source
/*global _gpfIgnore*/ // Helper to remove unused parameter warning
/*global _gpfGenDefHandler*/ // Class handler for class types (interfaces...)
/*global _gpfResolveScope*/ // Translate the parameter into a valid scope
/*global _gpfBuildParamArray*/ // Build a parameter array
/*global _gpfDoApply*/ // Apply the parameter array through a function
/*global _gpfGetClassDefinition*/ // Get GPF class definition for a constructor
// /*#endif*/

var
    /**
     * gpf.attributes shortcut
     *
     * @type {Object}
     * @private
     */
    _gpfA = gpf.attributes = {},

    /**
     * Used for empty members
     *
     * @type {gpf.attributes.Array}
     * @private
     */
    _gpfEmptyMemberArray = 0,

    /**
     * Generates a factory capable of creating a new instance of a class
     *
     * @param {Function} objectClass Object constructor
     * @param {String} name Alias name (will be prefixed by $)
     * @private
     * @closure
     */
    _gpfAlias = function (objectClass, name) {
        name = "$" + name;
        gpf[name] = (function(){
            var Proxy = (_gpfFunc("return function " + name + "(args) {" +
                "this.constructor.apply(this, args);" +
            "};"))();
            Proxy.prototype = objectClass.prototype;
            return function() {
                return new Proxy(arguments);
            };
        }());
    },

    /**
     * gpf.define handler for attributes
     *
     * @type {Function}
     * @private
     */
    _gpfDefAttrBase = _gpfGenDefHandler("gpf.attributes", "Attribute"),

    /**
     * gpf.define for attributes
     *
     * @param {String} name Attribute name. If it contains a dot, it is
     * treated as absolute contextual. Otherwise, it is relative to
     * "gpf.attributes". If starting with $ (and no dot), the contextual name
     * will be the "gpf.attributes." + name(without $) + "Attribute" and an
     * alias is automatically created (otherwise, use $Alias attribute on class)
     * @param {Function|string} [base=undefined] base Base attribute
     * (or contextual name)
     * @param {Object} [definition=undefined] definition Attribute definition
     * @return {Function}
     * @private
     */
    _gpfDefAttr = function (name, base, definition) {
        var
            isAlias = name.charAt(0) === "$",
            fullName,
            result;
        if (isAlias) {
            name = name.substr(1);
            fullName = name + "Attribute";
        } else {
            fullName = name;
        }
        result = _gpfDefAttrBase(fullName, base, definition);
        if (isAlias) {
            _gpfAlias(result, name);
        }
        return result;
    };

/**
 * Base class for any attribute
 *
 * @class gpf.attributes.Attribute
 */
_gpfDefAttr("Attribute", {

    protected: {

        /**
         * Name of the member the attribute is associated to
         *
         * @type {String}
         * @protected
         * @friend {gpf.attributes.add}
         */
        _member: "",

        /**
         * This method is the implementation of the attribute: it receives
         * the prototype to alter.
         *
         * NOTE: this is called *after* all declared members are set
         *
         * @param {Object} objPrototype Class prototype
         * @protected
         * @friend {gpf.attributes.add}
         */
        _alterPrototype: function /*abstract*/ (objPrototype) {
            _gpfIgnore(objPrototype);
        }

    },

    public: {

        /**
         * Get the member name
         *
         * @return {String}
         */
        member: function () {
            return this._member;
        }

    }

});

/**
 * Generates an alias for the attribute. An alias is a factory function that
 * allocates an attribute instance (parameters are forwarded).
 * As a result, instead of using:
 * "[Class]" : [new gpf.attributes.AliasAttribute("Name")]
 * It is reduced to:
 * "[Class]" : [$Alias("Name")]
 *
 * @param {String} name Name of the alias to build below gpf
 *
 * @class gpf.attributes.AliasAttribute
 * @extends gpf.attributes.Attribute
 * @alias gpf.$Alias
 */
_gpfDefAttr("$Alias", {

    private: {

        /**
         * Name of the alias to create
         *
         * @type {String}
         * @private
         */
        _name: ""

    },

    protected: {

        /**
         * @inheritDoc gpf.attributes.Attribute:_alterPrototype
         */
        _alterPrototype: function (objPrototype) {
            _gpfAlias(objPrototype.constructor, this._name);
        }

    },

    public: {

        /**
         * Defines an alias
         *
         * @param {String} name Name of the alias to create
         * @constructor
         */
        constructor: function (name) {
            this._name = name;
        }

    }

});

/**
 * Attribute array, generally used to list attributes on a class member
 *
 * @class gpf.attributes.Array
 * TODO implements gpf.interfaces.IReadOnlyArray
 */
gpf.define("gpf.attributes.Array", {

    private: {

        /**
         * @type {gpf.attributes.Attribute[]}
         * @private
         */
        _array: []

    },

    public: {

        /**
         * @constructor
         */
        constructor: function () {
            this._array = []; // Create a new instance of the array
        },

        /**
         * Gives the number of attributes in the array
         *
         * @return {Number}
         */
        count: function () {
            return this._array.length;
        },

        /**
         * Return the first occurrence of the expected class
         *
         * @param {gpf.attributes.Attribute} expectedClass the class to
         * match
         * @return {gpf.attributes.Attribute}
         */
        has: function (expectedClass) {
            gpf.ASSERT("function" === typeof expectedClass,
                "Expected a class parameter");
            gpf.ASSERT(
                expectedClass.prototype instanceof _gpfA.Attribute,
                "Expected an Attribute-like class parameter");
            var
                idx,
                array = this._array,
                len = array.length,
                item;
            for (idx = 0; idx < len; ++idx) {
                item = array[idx];
                if (item instanceof expectedClass) {
                    return item;
                }
            }
            return null;
        },

        /**
         * Returns a new array with all attributes matching the expected
         * class
         *
         * @param {Function} expectedClass the class to match
         * @return {gpf.attributes.Array}
         */
        filter: function (expectedClass) {
            gpf.ASSERT("function" === typeof expectedClass,
                "Expected a class parameter");
            gpf.ASSERT(
                expectedClass.prototype instanceof _gpfA.Attribute,
                "Expected an Attribute-like class parameter");
            var
                idx,
                array = this._array,
                len = array.length,
                attribute,
                result = new _gpfA.Array(),
                resultArray = result._array;
            for (idx = 0; idx < len; ++idx) {
                attribute = array[idx];
                if (attribute instanceof expectedClass) {
                    resultArray.push(attribute);
                }
            }
            return result;
        },

        /**
         * Apply the callback for each attribute in the array.
         * If the callback returns anything, the loop stops and the result
         * is returned to the caller.
         *
         * @param {Function} callback, defined with parameters
         * * {gpf.attributes.Attribute} attribute
         * No result is expected
         * @param {Object} [scope=undefined] scope
         * @param {*} [params=undefined] params Additional parameters
         * appended at the end of the expected parameter list
         * @return {*}
         */
        each: function (callback, scope, params) {
            scope = _gpfResolveScope(scope);
            params = _gpfBuildParamArray(1, params);
            var
                idx,
                array = this._array,
                len = array.length,
                result;
            for (idx = 0; idx < len; ++idx) {
                result = _gpfDoApply(callback, scope, params, array[idx]);
                if (undefined !== result) {
                    return result;
                }
            }
        }
    }

});

/**
 * Attribute map, generally used to list attributes of a class
 *
 * @class gpf.attributes.Map
 */
gpf.define("gpf.attributes.Map", {

    private: {

        /**
         * @type {Object} Map(String,gpf.attributes.Array)
         * @private
         */
        _members: {},

        /**
         * @type {Number}
         * @private
         */
        _count: 0,

        /**
         * Copy the content of this map to a new one
         *
         * @param {gpf.attributes.Map} attributesMap recipient of the copy
         * @param {Function} [callback=undefined] callback callback function
         * to test if the mapping should be added
         * @param {*} [param=undefined] param additional parameter for the
         * callback
         * @private
         */
        _copyTo: function (attributesMap, callback, param) {
            var
                members = this._members,
                member,
                array,
                idx,
                attribute;
            if (this._count) {
                for (member in members) {
                    if (members.hasOwnProperty(member)) {
                        array = members[member]._array;
                        for (idx = 0; idx < array.length; ++idx) {
                            attribute = array[ idx ];
                            if (!callback
                                || callback(member, attribute, param)) {
                                attributesMap.add(member, attribute);
                            }
                        }
                    }
                }
            }
        },

        /**
         * Callback for _copyTo, test if attribute is of a given class
         *
         * @param {String} member
         * @param {gpf.attributes.Attribute} attribute
         * @param {Function} expectedClass
         * @return {Boolean}
         * @private
         */
        _filterCallback: function (member, attribute, expectedClass) {
            _gpfIgnore(member);
            return attribute instanceof expectedClass;
        }

    },

    public: {

        /**
         * @param {Object} [object=undefined] object Object to read
         *        attributes from
         * @constructor
         */
        constructor: function (object) {
            this._members = {}; // Creates a new dictionary
            this._count = 0;
            if (undefined !== object) {
                this.fillFromObject(object);
            }
        },

        /**
         * Gives the total number of attributes enclosed in the map
         *
         * @return {Number}
         */
        count: function () {
            return this._count;
        },

        /**
         * Associate an attribute to a member
         *
         * @param {String} member member name
         * @param {gpf.attributes.Attribute} attribute attribute to map
         */
        add: function (member, attribute) {
            var array = this._members[member];
            if (undefined === array) {
                array = this._members[member] = new _gpfA.Array();
            }
            array._array.push(attribute);
            ++this._count;
        },

        /**
         * Fill the map using object's attributes
         *
         * @param {Object} object object to get attributes from
         * @return {Number} number of attributes in the resulting map
         */
        fillFromObject: function (object) {
            var classDef = _gpfGetClassDefinition(object.constructor);
            return this.fillFromClassDef(classDef);
        },

        /**
         * Fill the map using class definition object
         *
         * @param {gpf.classDef} classDef class definition
         * @return {Number} number of attributes in the resulting map
         */
        fillFromClassDef: function (classDef) {
            var
                attributes,
                Super;
            while (classDef) { // !undefined && !null
                attributes = classDef.attributes();
                if (attributes) {
                    attributes._copyTo(this);
                }
                Super = classDef.Super();
                if (Super !== Object) { // Can't go upper
                    classDef = _gpfGetClassDefinition(Super);
                } else {
                    break;
                }
            }
            return this._count;
        },

        /**
         * Creates a new map that contains only instances of the given
         * attribute class
         *
         * @param {Function} expectedClass
         * @return {gpf.attributes.Map}
         */
        filter: function (expectedClass) {
            gpf.ASSERT("function" === typeof expectedClass,
                "Expected a class parameter");
            gpf.ASSERT( expectedClass.prototype instanceof _gpfA.Attribute,
                "Expected an Attribute-like class parameter");
            var result = new _gpfA.Map();
            this._copyTo(result, this._filterCallback, expectedClass);
            return result;
        },

        /**
         * Returns the array of map associated to a member
         *
         * @param {String} name
         * @return {gpf.attributes.Array}
         */
        member: function (name) {
            /**
             * When member is a known Object member (i.e. constructor),
             * this generates weird results. Filter out by testing the
             * result type.
             */
            var result = this._members[name];
            if (undefined === result
                || !(result instanceof _gpfA.Array)) {
                if (0 === _gpfEmptyMemberArray) {
                    _gpfEmptyMemberArray = new _gpfA.Array();
                }
                result = _gpfEmptyMemberArray;
            }
            return result;
        },

        /**
         * Returns the list of members stored in this map
         *
         * @perf_warn Result is computed on each call
         * @return {String[]}
         */
        members: function () {
            var
                members = this._members,
                result = [],
                member;
            for (member in members) {
                if (members.hasOwnProperty(member)) {
                    result.push(member);
                }
            }
            return result;
        },

        /**
         * Apply the callback for each member in the map
         * If the callback returns anything, the loop stops and the result
         * is returned to the caller.
         *
         * @param {Function} callback, defined with parameters
         * * {String} member
         * * {gpf.attributes.Array} attributes
         * No result is expected
         * @param {Object} [scope=undefined] scope
         * @param {*} [params=undefined] params Additional parameters
         * appended at the end of the expected parameter list
         * @return {*}
         */
        each: function (callback, scope, params) {
            scope = _gpfResolveScope(scope);
            params = _gpfBuildParamArray(2, params);
            var
                members = this._members,
                member,
                result;
            for (member in members) {
                if (members.hasOwnProperty(member)) {
                    result = _gpfDoApply(callback, scope, params,
                        member, members[member]);
                    if (undefined !== result) {
                        return result;
                    }
                }
            }
        },

        /**
         * Add the attributes contained in the map to the given prototype
         *
         * @param {Function} objectClass
         */
        addTo: function (objectClass) {
            var
                members = this._members,
                member;
            for (member in members) {
                if (members.hasOwnProperty(member)) {
                    _gpfA.add(objectClass, member,
                        members[member]);
                }
            }
        }

    }

});

/**
 * Add the attribute list to the given prototype associated with the
 * provided member name
 *
 * @param {Function} objectClass class constructor
 * @param {String} name member name
 * @param {gpf.attributes.Attribute[]} attributes
 */
_gpfA.add = function (objectClass, name, attributes) {
    var
        attributeList,
        len,
        idx,
        attribute;
    attributeList = _gpfGetClassDefinition(objectClass).attributes();
    len = attributes.length;
    for (idx = 0; idx < len; ++idx) {
        attribute = attributes[idx];
        attribute._member = name; // Assign member name
        attributeList.add(name, attribute);
        attribute._alterPrototype(objectClass.prototype);
    }
};<|endoftext|>


<commit_before>chrome.omnibox.onInputEntered.addListener(
	function(searchText) {
		// Format: "5", "5.2", "4.7", etc.
		var qtVersion = localStorage['qtver']
		if (qtVersion == undefined) {
			qtVersion = '5'
		}

		var site;
		switch (qtVersion) {
			// Docs for older versions of Qt 5 are archived at doc.qt.digia.com
			case '5.2':
			case '5.1':
			case '5.0':
				site = 'site%3Adoc.qt.digia.com%2Fqt-' + qtVersion + '%2F'
				break

			// Docs for Qt 4.7, 4.8, and the latest Qt 5 are hosted at qt-project.org
			default:
				site = 'site%3Aqt-project.org%2Fdoc%2Fqt-' + qtVersion + '%2F'
		}

		chrome.tabs.create({'url': 'https://www.google.com/search?q=' + site + '+' + searchText})
	});

<commit_msg>CHANGE: Point to http://doc.qt.io for Qt 5.4<commit_after>chrome.omnibox.onInputEntered.addListener(
	function(searchText) {
		// Format: "5", "5.2", "4.7", etc.
		var qtVersion = localStorage['qtver']
		if (qtVersion == undefined) {
			qtVersion = '5'
		}

		var site;
		switch (qtVersion) {
			// Docs for Qt 5.4 onwards are hosted at doc.qt.io
			case '5':
				site = 'site%3Adoc.qt.io%2Fdoc%2Fqt-5%2F'
				break

			// Docs for Qt 5.3 aren't archived, apparently

			// Docs for Qt 5.0 - 5.2 are hosted at doc.qt.digia.com
			case '5.2':
			case '5.1':
			case '5.0':
				site = 'site%3Adoc.qt.digia.com%2Fqt-' + qtVersion + '%2F'
				break

			// Docs for Qt 4.7 and 4.8 are hosted at qt-project.org
			default:
				site = 'site%3Aqt-project.org%2Fdoc%2Fqt-' + qtVersion + '%2F'
		}

		chrome.tabs.create({'url': 'https://www.google.com/search?q=' + site + '+' + searchText})
	});

<|endoftext|>


<commit_before>/*
 * Copyright 2017 SideeX committers
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

import browser from "webextension-polyfill";

var panelId = undefined;
var windowOpenSideex = new Object();

function onCreated(windowInfo) {
  console.log(`Create editor successfully: id = ${windowInfo.id}`);
  panelId = windowInfo.id;
}

function onError(error) {
  console.log(`Error: ${error}`);
}

function checkOpenOneSideex(contentWindowInfo) {
  console.log("contentWindowInfo1-2: ", contentWindowInfo);
  if (windowOpenSideex[contentWindowInfo.id] !== undefined && windowOpenSideex[contentWindowInfo.id] == true) {
    console.log("Sideex has been opened.");
    console.log("windowOpenSideex: ", windowOpenSideex);
    return Promise.reject("Sideex has been opened.");
  }
  windowOpenSideex[contentWindowInfo.id] = true;
  console.log("Open one sideex.");
  console.log("contentWindowInfo2: ", contentWindowInfo);
  return contentWindowInfo;
}

function openSideexWindow(contentWindowInfo) {
  let sideexWindowInfo = browser.windows.create({
    url: browser.extension.getURL("assets/panel.html"),
    type: "popup",
    height: 730,
    width: 750
  });
  console.log("contentWindowInfo3: ", contentWindowInfo);
  console.log("sideexWindowInfo: ", sideexWindowInfo);
  return sideexWindowInfo;
}

function openPage() {

  var getContentWindowInfo = browser.windows.getLastFocused();
  var getSideexWindowInfo = browser.windows.create({
    url: browser.extension.getURL("assets/panel.html"),
    type: "popup",
    height: 730,
    width: 750
  });

  Promise.all([getContentWindowInfo, getSideexWindowInfo])
    .then(function(windowInfo) {
      console.log("get the window info");
      let contentWindowInfo = windowInfo[0];
      let sideexWindowInfo = windowInfo[1];
      console.log("contentWindowInfo Id:" + contentWindowInfo.id);
      console.log("contentWindowInfo:", contentWindowInfo);
      console.log("sideexWindowInfo Id:" + sideexWindowInfo.id);
      console.log("sideexWindowInfo:", sideexWindowInfo);
      return new Promise(function(resolve, reject) {
        let count = 0;
        let interval = setInterval(function() {
          if (count > 100) {
            reject("SideeX editor has no response");
            clearInterval(interval);
          }

          browser.tabs.query({
            active: true,
            windowId: sideexWindowInfo.id
          }).then(function(tabs) {
            if (tabs.length != 1) {
              count++;
              return;
            }
            let sideexTabInfo = tabs[0];
            if (sideexTabInfo.status == "loading") {
              count++;
              return;
            } else {
              console.log("SideeX has been fully loaded");
              resolve(windowInfo);
              clearInterval(interval);
            }
          });
        }, 200);
      });
    }).then(passWindowId)
    .catch(function(e) {
      console.log(e);
    });

  browser.contextMenus.create({
    id: "verifyText",
    title: "verifyText",
    documentUrlPatterns: ["<all_urls>"],
    contexts: ["all"]
  });
  browser.contextMenus.create({
    id: "verifyTitle",
    title: "verifyTitle",
    documentUrlPatterns: ["<all_urls>"],
    contexts: ["all"]
  });
  browser.contextMenus.create({
    id: "assertText",
    title: "assertText",
    documentUrlPatterns: ["<all_urls>"],
    contexts: ["all"]
  });
  browser.contextMenus.create({
    id: "assertTitle",
    title: "assertTitle",
    documentUrlPatterns: ["<all_urls>"],
    contexts: ["all"]
  });
  browser.contextMenus.create({
    id: "storeText",
    title: "storeText",
    documentUrlPatterns: ["<all_urls>"],
    contexts: ["all"]
  });
  browser.contextMenus.create({
    id: "storeTitle",
    title: "storeTitle",
    documentUrlPatterns: ["<all_urls>"],
    contexts: ["all"]
  });

}

browser.browserAction.onClicked.addListener(openPage);

function disconnectAllTabs(tabs) {
  for (let tab of tabs) {
    browser.tabs.sendMessage(tab.id, { active: false });
  }
}

function queryError(error) {
  console.log(`Error: ${error}`);
}

browser.windows.onRemoved.addListener(function(windowId) {
  if (windowId === panelId) {
    console.log("Editor has closed");
    var querying = browser.tabs.query({ url: "<all_urls>" });
    querying.then(disconnectAllTabs, queryError);
    panelId = undefined;
  }

  browser.contextMenus.removeAll();
});

function passWindowId(windowInfo){
  let contentWindowInfo = windowInfo[0];
  let sideexWindowInfo = windowInfo[1];
  let contentWindowId = contentWindowInfo.id;
  let sideexTabId = sideexWindowInfo.tabs[0].id;
  let sideexWindowId = sideexWindowInfo.id;

  return browser.tabs.sendMessage(sideexTabId, {
    selfWindowId: sideexWindowId,
    commWindowId: contentWindowId
  });
}

var port;
browser.contextMenus.onClicked.addListener(function(info, tab) {
  port.postMessage({ cmd: info.menuItemId });
});

browser.runtime.onConnect.addListener(function(m) {
  port = m;
});
<commit_msg>migrate all the vars<commit_after>/*
 * Copyright 2017 SideeX committers
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

import browser from "webextension-polyfill";

let panelId = undefined;
const windowOpenSideex = {};

function onCreated(windowInfo) {
  console.log(`Create editor successfully: id = ${windowInfo.id}`);
  panelId = windowInfo.id;
}

function onError(error) {
  console.log(`Error: ${error}`);
}

function checkOpenOneSideex(contentWindowInfo) {
  console.log("contentWindowInfo1-2: ", contentWindowInfo);
  if (windowOpenSideex[contentWindowInfo.id] !== undefined && windowOpenSideex[contentWindowInfo.id] == true) {
    console.log("Sideex has been opened.");
    console.log("windowOpenSideex: ", windowOpenSideex);
    return Promise.reject("Sideex has been opened.");
  }
  windowOpenSideex[contentWindowInfo.id] = true;
  console.log("Open one sideex.");
  console.log("contentWindowInfo2: ", contentWindowInfo);
  return contentWindowInfo;
}

function openSideexWindow(contentWindowInfo) {
  let sideexWindowInfo = browser.windows.create({
    url: browser.extension.getURL("assets/panel.html"),
    type: "popup",
    height: 730,
    width: 750
  });
  console.log("contentWindowInfo3: ", contentWindowInfo);
  console.log("sideexWindowInfo: ", sideexWindowInfo);
  return sideexWindowInfo;
}

function openPage() {

  const getContentWindowInfo = browser.windows.getLastFocused();
  const getSideexWindowInfo = browser.windows.create({
    url: browser.extension.getURL("assets/panel.html"),
    type: "popup",
    height: 730,
    width: 750
  });

  Promise.all([getContentWindowInfo, getSideexWindowInfo])
    .then(function(windowInfo) {
      console.log("get the window info");
      let contentWindowInfo = windowInfo[0];
      let sideexWindowInfo = windowInfo[1];
      console.log("contentWindowInfo Id:" + contentWindowInfo.id);
      console.log("contentWindowInfo:", contentWindowInfo);
      console.log("sideexWindowInfo Id:" + sideexWindowInfo.id);
      console.log("sideexWindowInfo:", sideexWindowInfo);
      return new Promise(function(resolve, reject) {
        let count = 0;
        let interval = setInterval(function() {
          if (count > 100) {
            reject("SideeX editor has no response");
            clearInterval(interval);
          }

          browser.tabs.query({
            active: true,
            windowId: sideexWindowInfo.id
          }).then(function(tabs) {
            if (tabs.length != 1) {
              count++;
              return;
            }
            let sideexTabInfo = tabs[0];
            if (sideexTabInfo.status == "loading") {
              count++;
              return;
            } else {
              console.log("SideeX has been fully loaded");
              resolve(windowInfo);
              clearInterval(interval);
            }
          });
        }, 200);
      });
    }).then(passWindowId)
    .catch(function(e) {
      console.log(e);
    });

  browser.contextMenus.create({
    id: "verifyText",
    title: "verifyText",
    documentUrlPatterns: ["<all_urls>"],
    contexts: ["all"]
  });
  browser.contextMenus.create({
    id: "verifyTitle",
    title: "verifyTitle",
    documentUrlPatterns: ["<all_urls>"],
    contexts: ["all"]
  });
  browser.contextMenus.create({
    id: "assertText",
    title: "assertText",
    documentUrlPatterns: ["<all_urls>"],
    contexts: ["all"]
  });
  browser.contextMenus.create({
    id: "assertTitle",
    title: "assertTitle",
    documentUrlPatterns: ["<all_urls>"],
    contexts: ["all"]
  });
  browser.contextMenus.create({
    id: "storeText",
    title: "storeText",
    documentUrlPatterns: ["<all_urls>"],
    contexts: ["all"]
  });
  browser.contextMenus.create({
    id: "storeTitle",
    title: "storeTitle",
    documentUrlPatterns: ["<all_urls>"],
    contexts: ["all"]
  });

}

browser.browserAction.onClicked.addListener(openPage);

function disconnectAllTabs(tabs) {
  for (let tab of tabs) {
    browser.tabs.sendMessage(tab.id, { active: false });
  }
}

function queryError(error) {
  console.log(`Error: ${error}`);
}

browser.windows.onRemoved.addListener(function(windowId) {
  if (windowId === panelId) {
    console.log("Editor has closed");
    const querying = browser.tabs.query({ url: "<all_urls>" });
    querying.then(disconnectAllTabs, queryError);
    panelId = undefined;
  }

  browser.contextMenus.removeAll();
});

function passWindowId(windowInfo){
  let contentWindowInfo = windowInfo[0];
  let sideexWindowInfo = windowInfo[1];
  let contentWindowId = contentWindowInfo.id;
  let sideexTabId = sideexWindowInfo.tabs[0].id;
  let sideexWindowId = sideexWindowInfo.id;

  return browser.tabs.sendMessage(sideexTabId, {
    selfWindowId: sideexWindowId,
    commWindowId: contentWindowId
  });
}

let port;
browser.contextMenus.onClicked.addListener(function(info) {
  port.postMessage({ cmd: info.menuItemId });
});

browser.runtime.onConnect.addListener(function(m) {
  port = m;
});
<|endoftext|>


<commit_before>
var filterUrls = [
  "*://*.baidu.com/*.js*",
  "*://*.baidustatic.com/*.js*"
];

chrome.webRequest.onBeforeRequest.addListener(function(info) {

        console.log("Blocked: " , info.url);

        return { cancel : true};
    },{
        urls: filterUrls,
        types: ["script","image"]
    }

 );<commit_msg>Added the missing parameter to onBeforeRequest listener<commit_after>
var filterUrls = [
  "*://*.baidu.com/*.js*",
  "*://*.baidustatic.com/*.js*"
];

chrome.webRequest.onBeforeRequest.addListener(function(info) {

        console.log("Blocked: " , info.url);

        return { cancel : true};
    },{
        urls: filterUrls,
        types: ["script","image"]
    },["blocking"]

 );<|endoftext|>


<commit_before>function checkUrl(tabId) {
    chrome.tabs.sendMessage(tabId, {}, function(location) {
        if (location && location.pathname.indexOf("/f5-w-") >= 0) {
            chrome.pageAction.show(tabId);
        } else {
            chrome.pageAction.hide(tabId);
        }
    });
}

chrome.tabs.onCreated.addListener(function(tab)             { checkUrl(tab.Id); });
chrome.tabs.onUpdated.addListener(function(tabId)           { checkUrl(tabId); });
chrome.tabs.onSelectionChanged.addListener(function(tabId)  { checkUrl(tabId); });
chrome.tabs.onActivated.addListener(function(info)          { checkUrl(info.tabId); });

// Ensure the current selected tab is set up.
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
    checkUrl(tabs[0].id);
});<commit_msg>Update background.js<commit_after>function checkUrl(tabId) {
    chrome.tabs.sendMessage(tabId, {}, function(location) {
        if (location && location.pathname.indexOf("/f5-w-") >= 0) {
            chrome.pageAction.show(tabId);
        } else {
            chrome.pageAction.hide(tabId);
        }
    });
}

chrome.tabs.onUpdated.addListener(function(tabId)           { checkUrl(tabId); });
chrome.tabs.onSelectionChanged.addListener(function(tabId)  { checkUrl(tabId); });
chrome.tabs.onActivated.addListener(function(info)          { checkUrl(info.tabId); });

// Ensure the current selected tab is set up.
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
    checkUrl(tabs[0].id);
});
<|endoftext|>


<commit_before>// Script blocking
chrome.webRequest.onBeforeRequest.addListener(
  function(details) {
    return {cancel: true};
  },
  {
    urls: [
      // O Estado de S. Paulo
      "*://*.estadao.com.br/paywall/*",

      // Folha de S.Paulo
      "*://paywall.folha.uol.com.br/*",
      "*://static.folha.uol.com.br/paywall/*",

      // O Globo
      "*://ogjs.infoglobo.com.br/*/js/controla-acesso-aux.js",
      "*://cdn.tinypass.com/api/tinypass.min.js",

      // Gazeta do Povo
      "*://*.gazetadopovo.com.br/loader/v1/logan_full_toolbar.js*",

      // Correio Popular
      "*://correio.rac.com.br/includes/js/novo_cp/fivewall.js*",

      // O Estado do Maranhão
      "*://dashboard.tinypass.com/xbuilder/experience/load*",
      "http://assets.imirante.com/2.0/oestadoma/js/jquery.login.min.js",

      // Jornal de Novo Hamburgo
      "*://www.jornalnh.com.br/includes/js/paywall.js*",
      "*://blockv2.fivewall.com.br/*",

      // Diário de Santa Maria
      "*://www.rbsonline.com.br/cdn/scripts/SLoader.js",

      // New York Times
      "*://*.nyt.com/js/mtr.js",

      // Washington Post
      "*://*.washingtonpost.com/*pwapi/*.js*",
      "*://*.washingtonpost.com/*drawbridge/drawbridge.js?_*"
    ],
    types: ["script"]
  },
  ["blocking"]
);

// XHR blocking
WHITELIST = [
  'http://paywall.folha.uol.com.br/status.php'
];
chrome.webRequest.onBeforeRequest.addListener(
  function(details) {
    if (WHITELIST.indexOf(details.url) !== -1)
      return {cancel: false};
    else
      return {cancel: true};
  },
  {
    urls: [
      // Folha de S.Paulo
      "*://paywall.folha.uol.com.br/*",
      "*://static.folha.uol.com.br/paywall/*",

      // Diário Catarinense
      "http://dc.clicrbs.com.br/jornal-2015/jsp/paywall.jspx*",

      // Jornal de Santa Catarina
      "http://jornaldesantacatarina.clicrbs.com.br/jornal/jsp/paywall*",

      // O Globo
      "*://cdn.tinypass.com/api/tinypass.min.js"
    ],
    types: ["xmlhttprequest"]
  },
  ["blocking"]
);

// Cookie blocking
chrome.webRequest.onBeforeRequest.addListener(
  function(details) {
    chrome.cookies.remove({
      'url': 'http://jota.info/*',
      'name': 'articles'
    });
  },
  {
    urls: [
      // JOTA
      "http://jota.info/*"
    ],
    types: ["main_frame"]
  }
);

chrome.webRequest.onBeforeRequest.addListener(
  function(details) {
    console.log(details);
    removeCookies('https://gauchazh.clicrbs.com.br');
    removeCookies('https://www.ft.com');
  },
  {
    urls: [
      // Financial Times
      "*://*.ft.com/*",

      // Zero Hora
      "*://gauchazh.clicrbs.com.br/*"
    ],
    types: ["main_frame"]
  }
);

function removeCookies(url) {
  chrome.cookies.getAll({}, function(cookies) {
    cookies.forEach(function(cookie, index, array) {
      chrome.cookies.remove({
        'url': url,
        'name': cookie.name
      });
    });
  });
}

chrome.webRequest.onHeadersReceived.addListener(
  // Block cookies from being set
  function (details) {
    details.responseHeaders.forEach(function(responseHeader) {
      if (responseHeader.name.toLowerCase() == "set-cookie") {
        responseHeader.value = '';
      }
    });
    return {
      responseHeaders: details.responseHeaders
    };
  },
  {
    urls: [
      // Financial Times
      "*://*.ft.com/*",

      // Zero Hora
      "*://*.clicrbs.com.br/*"
    ],
    types: ['xmlhttprequest']
  },
  ['blocking', 'responseHeaders']
);

chrome.webRequest.onBeforeSendHeaders.addListener(
  function(details) {
    injectHeader('Cookie', '', details.requestHeaders);
    return {requestHeaders: details.requestHeaders};
  },
  {
    urls: [
      // Jornal Nexo
      '*://api.nexojornal.com.br/*',

      // Zero Hora
      "*://api.clicrbs.com.br/*"
    ],
    types: ['xmlhttprequest']
  },
  ['blocking', 'requestHeaders']
);

// Referer injection
chrome.webRequest.onBeforeSendHeaders.addListener(
  function(details) {
    injectHeader(
      'Referer',
      'https://www.google.com.br/',
      details.requestHeaders
    );

    return {requestHeaders: details.requestHeaders};
  },
  {
    urls: [
      // Financial Times
      "*://www.ft.com/*"
    ],
    types: ["xmlhttprequest", "main_frame"]
  },
  ["blocking", "requestHeaders"]
);

function injectHeader(name, value, requestHeaders) {
  /**
   * @param {string} name - Name of the header to be inserted
   * @param {string} value - Value of the header to be inserted
   * @param {Object[]} requestHeaders - Provided by webRequest
   *   listeners in callback arg `details.requestHeader`
   * @param {string} requestHeaders[].name
   * @param {string} requestHeaders[].value
   */
  var headerIndex = requestHeaders.findIndex(
    x => x.name.toLowerCase() == name.toLowerCase());

  var newHeader = {name: name, value: value};
  if (headerIndex == -1)
    requestHeaders.push(newHeader);
  else
    requestHeaders[headerIndex] = newHeader;
}
<commit_msg>Exame e melhora NH<commit_after>// Script blocking
chrome.webRequest.onBeforeRequest.addListener(
  function(details) {
    return {cancel: true};
  },
  {
    urls: [
      // O Estado de S. Paulo
      "*://*.estadao.com.br/paywall/*",

      // Folha de S.Paulo
      "*://paywall.folha.uol.com.br/*",
      "*://static.folha.uol.com.br/paywall/*",

      // O Globo
      "*://ogjs.infoglobo.com.br/*/js/controla-acesso-aux.js",

      // Gazeta do Povo
      "*://*.gazetadopovo.com.br/loader/v1/logan_full_toolbar.js*",

      // Correio Popular
      "*://correio.rac.com.br/includes/js/novo_cp/fivewall.js*",

      // O Estado do Maranhão
      "*://dashboard.tinypass.com/xbuilder/experience/load*",
      "http://assets.imirante.com/2.0/oestadoma/js/jquery.login.min.js",

      // Jornal de Novo Hamburgo
      "*://jornalnh.com.br/includes/js/paywall.js*",
      "*://blockv2.fivewall.com.br/*",

      // Diário de Santa Maria
      "*://www.rbsonline.com.br/cdn/scripts/SLoader.js",

      // New York Times
      "*://*.nyt.com/js/mtr.js",

      // Washington Post
      "*://*.washingtonpost.com/*pwapi/*.js*",
      "*://*.washingtonpost.com/*drawbridge/drawbridge.js?_*",

      // Tinypass (O Globo, Exame e outros)
      "*://cdn.tinypass.com/api/tinypass.min.js"

    ],
    types: ["script"]
  },
  ["blocking"]
);

// XHR blocking
WHITELIST = [
  'http://paywall.folha.uol.com.br/status.php'
];
chrome.webRequest.onBeforeRequest.addListener(
  function(details) {
    if (WHITELIST.indexOf(details.url) !== -1)
      return {cancel: false};
    else
      return {cancel: true};
  },
  {
    urls: [
      // Folha de S.Paulo
      "*://paywall.folha.uol.com.br/*",
      "*://static.folha.uol.com.br/paywall/*",

      // Diário Catarinense
      "http://dc.clicrbs.com.br/jornal-2015/jsp/paywall.jspx*",

      // Jornal de Santa Catarina
      "http://jornaldesantacatarina.clicrbs.com.br/jornal/jsp/paywall*",

      // Tinypass (O Globo, Exame e outros)
      "*://cdn.tinypass.com/api/tinypass.min.js"
    ],
    types: ["xmlhttprequest"]
  },
  ["blocking"]
);

// Cookie blocking
chrome.webRequest.onBeforeRequest.addListener(
  function(details) {
    chrome.cookies.remove({
      'url': 'http://jota.info/*',
      'name': 'articles'
    });
  },
  {
    urls: [
      // JOTA
      "http://jota.info/*"
    ],
    types: ["main_frame"]
  }
);

chrome.webRequest.onBeforeRequest.addListener(
  function(details) {
    console.log(details);
    removeCookies('https://gauchazh.clicrbs.com.br');
    removeCookies('https://www.ft.com');
  },
  {
    urls: [
      // Financial Times
      "*://*.ft.com/*",

      // Zero Hora
      "*://gauchazh.clicrbs.com.br/*"
    ],
    types: ["main_frame"]
  }
);

function removeCookies(url) {
  chrome.cookies.getAll({}, function(cookies) {
    cookies.forEach(function(cookie, index, array) {
      chrome.cookies.remove({
        'url': url,
        'name': cookie.name
      });
    });
  });
}

chrome.webRequest.onHeadersReceived.addListener(
  // Block cookies from being set
  function (details) {
    details.responseHeaders.forEach(function(responseHeader) {
      if (responseHeader.name.toLowerCase() == "set-cookie") {
        responseHeader.value = '';
      }
    });
    return {
      responseHeaders: details.responseHeaders
    };
  },
  {
    urls: [
      // Financial Times
      "*://*.ft.com/*",

      // Zero Hora
      "*://*.clicrbs.com.br/*"
    ],
    types: ['xmlhttprequest']
  },
  ['blocking', 'responseHeaders']
);

chrome.webRequest.onBeforeSendHeaders.addListener(
  function(details) {
    injectHeader('Cookie', '', details.requestHeaders);
    return {requestHeaders: details.requestHeaders};
  },
  {
    urls: [
      // Jornal Nexo
      '*://api.nexojornal.com.br/*',

      // Zero Hora
      "*://api.clicrbs.com.br/*"
    ],
    types: ['xmlhttprequest']
  },
  ['blocking', 'requestHeaders']
);

// Referer injection
chrome.webRequest.onBeforeSendHeaders.addListener(
  function(details) {
    injectHeader(
      'Referer',
      'https://www.google.com.br/',
      details.requestHeaders
    );

    return {requestHeaders: details.requestHeaders};
  },
  {
    urls: [
      // Financial Times
      "*://www.ft.com/*"
    ],
    types: ["xmlhttprequest", "main_frame"]
  },
  ["blocking", "requestHeaders"]
);

function injectHeader(name, value, requestHeaders) {
  /**
   * @param {string} name - Name of the header to be inserted
   * @param {string} value - Value of the header to be inserted
   * @param {Object[]} requestHeaders - Provided by webRequest
   *   listeners in callback arg `details.requestHeader`
   * @param {string} requestHeaders[].name
   * @param {string} requestHeaders[].value
   */
  var headerIndex = requestHeaders.findIndex(
    x => x.name.toLowerCase() == name.toLowerCase());

  var newHeader = {name: name, value: value};
  if (headerIndex == -1)
    requestHeaders.push(newHeader);
  else
    requestHeaders[headerIndex] = newHeader;
}
<|endoftext|>


<commit_before>// Copyright 2014 Globo.com Player authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

var assign = require('lodash.assign')
var Browser = require('../components/browser')

var extend = function(protoProps, staticProps) {
  var parent = this
  var child

  if (protoProps && protoProps.constructor !== undefined) {
    child = protoProps.constructor
  } else {
    child = function(){ return parent.apply(this, arguments); }
  }

  assign(child, parent, staticProps)

  var Surrogate = function(){ this.constructor = child; }
  Surrogate.prototype = parent.prototype
  child.prototype = new Surrogate()

  if (protoProps) assign(child.prototype, protoProps)

  child.__super__ = parent.prototype

  child.super = function(name) {
    return parent.prototype[name]
  }

  child.prototype.getClass = function() {
    return child
  }

  return child
}

var formatTime = function(time) {
    time = time * 1000
    time = parseInt(time/1000)
    var seconds = time % 60
    time = parseInt(time/60)
    var minutes = time % 60
    time = parseInt(time/60)
    var hours = time % 24
    var out = ""
    if (hours && hours > 0) out += ("0" + hours).slice(-2) + ":"
    out += ("0" + minutes).slice(-2) + ":"
    out += ("0" + seconds).slice(-2)
    return out.trim()
}

var Fullscreen = {
  isFullscreen: function() {
    return (
      document.webkitFullscreenElement ||
      document.webkitIsFullScreen ||
      document.mozFullScreen ||
      !!document.msFullscreenElement
    )
  },
  requestFullscreen: function(el) {
    if(el.requestFullscreen) {
      el.requestFullscreen()
    } else if(el.webkitRequestFullscreen) {
      el.webkitRequestFullscreen()
    } else if(el.mozRequestFullScreen) {
      el.mozRequestFullScreen()
    } else if(el.msRequestFullscreen) {
      el.msRequestFullscreen()
    } else if (el.querySelector && el.querySelector("video").webkitEnterFullScreen) {
      el.querySelector("video").webkitEnterFullScreen()
    }
  },
  cancelFullscreen: function() {
    if(document.exitFullscreen) {
      document.exitFullscreen()
    } else if(document.webkitCancelFullScreen) {
      document.webkitCancelFullScreen()
    } else if(document.webkitExitFullscreen) {
      document.webkitExitFullscreen()
    } else if(document.mozCancelFullScreen) {
      document.mozCancelFullScreen()
    } else if(document.msExitFullscreen) {
      document.msExitFullscreen()
    }
  }
}

class Config {

  static _defaultConfig() {
    return {
      volume: {
        value: 100,
        parse: parseInt
      }
    }
  }

  static _defaultValueFor(key) {
    try {
      return this._defaultConfig()[key]['parse'](this._defaultConfig()[key]['value'])
    } catch(e) {
      return undefined
    }
  }

  static _create_keyspace(key){
    return 'clappr.' + document.domain + '.' + key
  }

  static restore(key) {
    if (Browser.hasLocalstorage && localStorage[this._create_keyspace(key)]){
      return this._defaultConfig()[key]['parse'](localStorage[this._create_keyspace(key)])
    }
    return this._defaultValueFor(key)
  }

  static persist(key, value) {
    if (Browser.hasLocalstorage) {
      try {
        localStorage[this._create_keyspace(key)] = value
        return true
      } catch(e) {
        return false
      }
    }
  }
}

var seekStringToSeconds = function(url) {
  var elements = (url.match(/t=([0-9]*h)?([0-9]*m)?([0-9]*s)?/) || []).splice(1)
  return (!!elements.length)? elements.map(function (el) {
    if (el) {
      var value = parseInt(el.slice(0,2)) || 0
      switch (el[el.length-1]) {
        case 'h': value = value * 3600; break
        case 'm': value = value * 60; break
      }
      return value
    }
    return 0
  }).reduce(function (a,b) { return a+b; }): 0
}

var idsCounter = {}

var uniqueId = function(prefix) {
  idsCounter[prefix] || (idsCounter[prefix] = 0)
  var id = ++idsCounter[prefix]
  return prefix + id
}

var isNumber = function(value) {
  return value - parseFloat(value) + 1 >= 0
}

var requestAnimationFrame = window.requestAnimationFrame ||
                            window.mozRequestAnimationFrame ||
                            window.webkitRequestAnimationFrame ||
                            (fn) => window.setTimeout(fn, 1000/60)

var cancelAnimationFrame = window.cancelAnimationFrame ||
                           window.mozCancelAnimationFrame ||
                           window.webkitCancelAnimationFrame ||
                           window.clearTimeout

module.exports = {
  extend: extend,
  formatTime: formatTime,
  Fullscreen: Fullscreen,
  Config: Config,
  seekStringToSeconds: seekStringToSeconds,
  uniqueId: uniqueId,
  isNumber: isNumber,
  requestAnimationFrame: requestAnimationFrame,
  cancelAnimationFrame: cancelAnimationFrame
}
<commit_msg>utils: fix format time for non finite values<commit_after>// Copyright 2014 Globo.com Player authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

var assign = require('lodash.assign')
var Browser = require('../components/browser')

var extend = function(protoProps, staticProps) {
  var parent = this
  var child

  if (protoProps && protoProps.constructor !== undefined) {
    child = protoProps.constructor
  } else {
    child = function(){ return parent.apply(this, arguments); }
  }

  assign(child, parent, staticProps)

  var Surrogate = function(){ this.constructor = child; }
  Surrogate.prototype = parent.prototype
  child.prototype = new Surrogate()

  if (protoProps) assign(child.prototype, protoProps)

  child.__super__ = parent.prototype

  child.super = function(name) {
    return parent.prototype[name]
  }

  child.prototype.getClass = function() {
    return child
  }

  return child
}

var formatTime = function(time) {
    if (!isFinite(time)) {
      return "--:--"
    }
    time = time * 1000
    time = parseInt(time/1000)
    var seconds = time % 60
    time = parseInt(time/60)
    var minutes = time % 60
    time = parseInt(time/60)
    var hours = time % 24
    var out = ""
    if (hours && hours > 0) out += ("0" + hours).slice(-2) + ":"
    out += ("0" + minutes).slice(-2) + ":"
    out += ("0" + seconds).slice(-2)
    return out.trim()
}

var Fullscreen = {
  isFullscreen: function() {
    return (
      document.webkitFullscreenElement ||
      document.webkitIsFullScreen ||
      document.mozFullScreen ||
      !!document.msFullscreenElement
    )
  },
  requestFullscreen: function(el) {
    if(el.requestFullscreen) {
      el.requestFullscreen()
    } else if(el.webkitRequestFullscreen) {
      el.webkitRequestFullscreen()
    } else if(el.mozRequestFullScreen) {
      el.mozRequestFullScreen()
    } else if(el.msRequestFullscreen) {
      el.msRequestFullscreen()
    } else if (el.querySelector && el.querySelector("video").webkitEnterFullScreen) {
      el.querySelector("video").webkitEnterFullScreen()
    }
  },
  cancelFullscreen: function() {
    if(document.exitFullscreen) {
      document.exitFullscreen()
    } else if(document.webkitCancelFullScreen) {
      document.webkitCancelFullScreen()
    } else if(document.webkitExitFullscreen) {
      document.webkitExitFullscreen()
    } else if(document.mozCancelFullScreen) {
      document.mozCancelFullScreen()
    } else if(document.msExitFullscreen) {
      document.msExitFullscreen()
    }
  }
}

class Config {

  static _defaultConfig() {
    return {
      volume: {
        value: 100,
        parse: parseInt
      }
    }
  }

  static _defaultValueFor(key) {
    try {
      return this._defaultConfig()[key]['parse'](this._defaultConfig()[key]['value'])
    } catch(e) {
      return undefined
    }
  }

  static _create_keyspace(key){
    return 'clappr.' + document.domain + '.' + key
  }

  static restore(key) {
    if (Browser.hasLocalstorage && localStorage[this._create_keyspace(key)]){
      return this._defaultConfig()[key]['parse'](localStorage[this._create_keyspace(key)])
    }
    return this._defaultValueFor(key)
  }

  static persist(key, value) {
    if (Browser.hasLocalstorage) {
      try {
        localStorage[this._create_keyspace(key)] = value
        return true
      } catch(e) {
        return false
      }
    }
  }
}

var seekStringToSeconds = function(url) {
  var elements = (url.match(/t=([0-9]*h)?([0-9]*m)?([0-9]*s)?/) || []).splice(1)
  return (!!elements.length)? elements.map(function (el) {
    if (el) {
      var value = parseInt(el.slice(0,2)) || 0
      switch (el[el.length-1]) {
        case 'h': value = value * 3600; break
        case 'm': value = value * 60; break
      }
      return value
    }
    return 0
  }).reduce(function (a,b) { return a+b; }): 0
}

var idsCounter = {}

var uniqueId = function(prefix) {
  idsCounter[prefix] || (idsCounter[prefix] = 0)
  var id = ++idsCounter[prefix]
  return prefix + id
}

var isNumber = function(value) {
  return value - parseFloat(value) + 1 >= 0
}

var requestAnimationFrame = window.requestAnimationFrame ||
                            window.mozRequestAnimationFrame ||
                            window.webkitRequestAnimationFrame ||
                            (fn) => window.setTimeout(fn, 1000/60)

var cancelAnimationFrame = window.cancelAnimationFrame ||
                           window.mozCancelAnimationFrame ||
                           window.webkitCancelAnimationFrame ||
                           window.clearTimeout

module.exports = {
  extend: extend,
  formatTime: formatTime,
  Fullscreen: Fullscreen,
  Config: Config,
  seekStringToSeconds: seekStringToSeconds,
  uniqueId: uniqueId,
  isNumber: isNumber,
  requestAnimationFrame: requestAnimationFrame,
  cancelAnimationFrame: cancelAnimationFrame
}
<|endoftext|>


<commit_before>/*
 * Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
 * http://paperjs.org/
 *
 * Copyright (c) 2011 - 2013, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */

/**
 * @name Line
 *
 * @class The Line object represents..
 */
var Line = Base.extend(/** @lends Line# */{
	// DOCS: document Line class and constructor
	/**
	 * Creates a Line object.
	 *
	 * @param {Point} point1
	 * @param {Point} point2
	 * @param {Boolean} [asVector=false]
	 */
	initialize: function Line(arg0, arg1, arg2, arg3, arg4) {
		var asVector = false;
		if (arguments.length >= 4) {
			this._px = arg0;
			this._py = arg1;
			this._vx = arg2;
			this._vy = arg3;
			asVector = arg4;
		} else {
			this._px = arg0.x;
			this._py = arg0.y;
			this._vx = arg1.x;
			this._vy = arg1.y;
			asVector = arg2;
		}
		if (!asVector) {
			this._vx -= this._px;
			this._vy -= this._py;
		}
	},

	/**
	 * The starting point of the line
	 *
	 * @name Line#point
	 * @type Point
	 */
	getPoint: function() {
		return new Point(this._px, this._py);
	},

	/**
	 * The vector of the line
	 *
	 * @name Line#vector
	 * @type Point
	 */
	getVector: function() {
		return new Point(this._vx, this._vy);
	},

	/**
	 * The length of the line
	 *
	 * @name Line#vector
	 * @type Number
	 */
	getLength: function() {
		return this.getVector().getLength();
	},

	/**
	 * @param {Line} line
	 * @param {Boolean} [isInfinite=false]
	 * @return {Point} the intersection point of the lines, {@code undefined}
	 * if the two lines are colinear, or {@code null} if they don't intersect.
	 */
	intersect: function(line, isInfinite) {
		return Line.intersect(
				this._px, this._py, this._vx, this._vy,
				line._px, line._py, line._vx, line._vy,
				true, isInfinite);
	},

	// DOCS: document Line#getSide(point)
	/**
	 * @param {Point} point
	 * @return {Number}
	 */
	getSide: function(point) {
		return Line.getSide(
				this._px, this._py, this._vx, this._vy,
				point.x, point.y, true);
	},

	// DOCS: document Line#getDistance(point)
	/**
	 * @param {Point} point
	 * @return {Number}
	 */
	getDistance: function(point) {
		return Math.abs(Line.getSignedDistance(
				this._px, this._py, this._vx, this._vy,
				point.x, point.y, true));
	},

	statics: /** @lends Line */{
		intersect: function(apx, apy, avx, avy, bpx, bpy, bvx, bvy, asVector,
				isInfinite) {
			// Convert 2nd points to vectors if they are not specified as such.
			if (!asVector) {
				avx -= apx;
				avy -= apy;
				bvx -= bpx;
				bvy -= bpy;
			}
			var cross = bvy * avx - bvx * avy;
			// Avoid divisions by 0, and errors when getting too close to 0
			if (!Numerical.isZero(cross)) {
				var dx = apx - bpx,
					dy = apy - bpy,
					ta = (bvx * dy - bvy * dx) / cross,
					tb = (avx * dy - avy * dx) / cross;
				// Check the ranges of t parameters if the line is not allowed
				// to extend beyond the definition points.
				if ((isInfinite || 0 <= ta && ta <= 1)
						&& (isInfinite || 0 <= tb && tb <= 1))
					return new Point(
								apx + ta * avx,
								apy + ta * avy);
			}
		},

		getSide: function(px, py, vx, vy, x, y, asVector) {
			if (!asVector) {
				vx -= px;
				vy -= py;
			}
			var v2x = x - px,
				v2y = y - py,
				ccw = v2x * vy - v2y * vx; // ccw = v2.cross(v1);
			if (ccw === 0) {
				ccw = v2x * vx + v2y * vy; // ccw = v2.dot(v1);
				if (ccw > 0) {
					// ccw = v2.subtract(v1).dot(v1);
					v2x -= vx;
					v2y -= vy;
					ccw = v2x * vx + v2y * vy;
					if (ccw < 0)
						ccw = 0;
				}
			}
			return ccw < 0 ? -1 : ccw > 0 ? 1 : 0;
		},

		getSignedDistance: function(px, py, vx, vy, x, y, asVector) {
			if (!asVector) {
				vx -= px;
				vy -= py;
			}
			// Cache these values since they're used heavily in fatline code
			var m = vy / vx, // slope
				b = py - m * px; // y offset
			// Distance to the linear equation
			return (y - (m * x) - b) / Math.sqrt(m * m + 1);
		}
	}
});
<commit_msg>Correctly fix Line#length documentation.<commit_after>/*
 * Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
 * http://paperjs.org/
 *
 * Copyright (c) 2011 - 2013, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */

/**
 * @name Line
 *
 * @class The Line object represents..
 */
var Line = Base.extend(/** @lends Line# */{
	// DOCS: document Line class and constructor
	/**
	 * Creates a Line object.
	 *
	 * @param {Point} point1
	 * @param {Point} point2
	 * @param {Boolean} [asVector=false]
	 */
	initialize: function Line(arg0, arg1, arg2, arg3, arg4) {
		var asVector = false;
		if (arguments.length >= 4) {
			this._px = arg0;
			this._py = arg1;
			this._vx = arg2;
			this._vy = arg3;
			asVector = arg4;
		} else {
			this._px = arg0.x;
			this._py = arg0.y;
			this._vx = arg1.x;
			this._vy = arg1.y;
			asVector = arg2;
		}
		if (!asVector) {
			this._vx -= this._px;
			this._vy -= this._py;
		}
	},

	/**
	 * The starting point of the line
	 *
	 * @name Line#point
	 * @type Point
	 */
	getPoint: function() {
		return new Point(this._px, this._py);
	},

	/**
	 * The vector of the line
	 *
	 * @name Line#vector
	 * @type Point
	 */
	getVector: function() {
		return new Point(this._vx, this._vy);
	},

	/**
	 * The length of the line
	 *
	 * @name Line#length
	 * @type Number
	 */
	getLength: function() {
		return this.getVector().getLength();
	},

	/**
	 * @param {Line} line
	 * @param {Boolean} [isInfinite=false]
	 * @return {Point} the intersection point of the lines, {@code undefined}
	 * if the two lines are colinear, or {@code null} if they don't intersect.
	 */
	intersect: function(line, isInfinite) {
		return Line.intersect(
				this._px, this._py, this._vx, this._vy,
				line._px, line._py, line._vx, line._vy,
				true, isInfinite);
	},

	// DOCS: document Line#getSide(point)
	/**
	 * @param {Point} point
	 * @return {Number}
	 */
	getSide: function(point) {
		return Line.getSide(
				this._px, this._py, this._vx, this._vy,
				point.x, point.y, true);
	},

	// DOCS: document Line#getDistance(point)
	/**
	 * @param {Point} point
	 * @return {Number}
	 */
	getDistance: function(point) {
		return Math.abs(Line.getSignedDistance(
				this._px, this._py, this._vx, this._vy,
				point.x, point.y, true));
	},

	statics: /** @lends Line */{
		intersect: function(apx, apy, avx, avy, bpx, bpy, bvx, bvy, asVector,
				isInfinite) {
			// Convert 2nd points to vectors if they are not specified as such.
			if (!asVector) {
				avx -= apx;
				avy -= apy;
				bvx -= bpx;
				bvy -= bpy;
			}
			var cross = bvy * avx - bvx * avy;
			// Avoid divisions by 0, and errors when getting too close to 0
			if (!Numerical.isZero(cross)) {
				var dx = apx - bpx,
					dy = apy - bpy,
					ta = (bvx * dy - bvy * dx) / cross,
					tb = (avx * dy - avy * dx) / cross;
				// Check the ranges of t parameters if the line is not allowed
				// to extend beyond the definition points.
				if ((isInfinite || 0 <= ta && ta <= 1)
						&& (isInfinite || 0 <= tb && tb <= 1))
					return new Point(
								apx + ta * avx,
								apy + ta * avy);
			}
		},

		getSide: function(px, py, vx, vy, x, y, asVector) {
			if (!asVector) {
				vx -= px;
				vy -= py;
			}
			var v2x = x - px,
				v2y = y - py,
				ccw = v2x * vy - v2y * vx; // ccw = v2.cross(v1);
			if (ccw === 0) {
				ccw = v2x * vx + v2y * vy; // ccw = v2.dot(v1);
				if (ccw > 0) {
					// ccw = v2.subtract(v1).dot(v1);
					v2x -= vx;
					v2y -= vy;
					ccw = v2x * vx + v2y * vy;
					if (ccw < 0)
						ccw = 0;
				}
			}
			return ccw < 0 ? -1 : ccw > 0 ? 1 : 0;
		},

		getSignedDistance: function(px, py, vx, vy, x, y, asVector) {
			if (!asVector) {
				vx -= px;
				vy -= py;
			}
			// Cache these values since they're used heavily in fatline code
			var m = vy / vx, // slope
				b = py - m * px; // y offset
			// Distance to the linear equation
			return (y - (m * x) - b) / Math.sqrt(m * m + 1);
		}
	}
});
<|endoftext|>


<commit_before>const fs = require('fs');
const cp = require('child_process');
const im = require('imagemagick');
const readline = require('readline');
const commandLineArgs = require('command-line-args');
const speakIndexName = 'whospeak.csv';
const charIndexName = 'chars.txt';

const fullWidth = 1920;
const fullHeight = 1080;
const outDir = 'clips';

const optionDefinitions = [
  { name: 'background', alias: 'b', type: String },
  { name: 'color', alias: 'c', type: String },
  { name: 'font', alias: 'f', type: String },
  { name: 'image', alias: 'i', type: String },
  { name: 'line', alias: 'l', type: Number },
  { name: 'novoice', alias: 'n', type: Boolean },
  { name: 'play', alias: 'p', type: String },
];
const options = commandLineArgs(optionDefinitions);

if (
      !options.hasOwnProperty('font')
   || !options.hasOwnProperty('image')
   || !options.hasOwnProperty('line')
   || !options.hasOwnProperty('play')
   ) {
  // Can't do anything useful without input
  return;
}

var background = options.hasOwnProperty('background') ? options.background : 'lightgray';
var foreground = options.hasOwnProperty('color') ? options.color : 'black';
var fontFile = options.font;
var imageFile = options.image;
var lineNumber = options.line;
var playFile = options.play;
var novoice = options.hasOwnProperty('novoice') ? options.novoice : false;
var imageBaseName = imageFile.split('/').pop();
var screenplay = fs.readFileSync(playFile).toString().split('\n');
var lines = screenplay.length;
var digits = lines.toString().length;
screenplay.unshift('');

var lineRead = screenplay[lineNumber];
var audioName = 'output/speech' + lineNumber + '.wav';
var proc = cp.spawnSync('/usr/bin/soxi', [ '-D', audioName ]);
var time = parseFloat(proc.stdout.toString().trim(), 10);
var width = 0;
var height = 0;
var rSwitch = Math.round(Math.random());

var speakIndex = fs.readFileSync(speakIndexName).toString().replace('|', ',').split('\n');
var charIndex = fs.readFileSync(charIndexName).toString().split('\n');

im.identify(imageFile, function (err, features) {
  if (err) throw err;
  var linelen = 100;
  var dir = 'Center';
  var geo = '+100+100';
  width = features.width;
  height = features.height;
  if (width > height) {
    var xScale = fullWidth / width;
    linelen = Math.round((fullWidth - 200) / 24 - 1);
    if (rSwitch == 1) {
      dir = 'South';
      geo = '+100+100';
    } else {
      dir = 'North';
      geo = '+100+' + (height * xScale + 50);
    }
  } else {
    var yScale = fullHeight / height;
    linelen = Math.round((fullWidth - width * yScale - 200) / 24 - 1);
    if (rSwitch == 1) {
      dir = 'East';
      geo = '+100+100';
    } else {
      dir = 'West';
      geo = '+' + (100 + Math.round(width * yScale)) + '+100';
    }
  }
  var words = lineRead.replace(/_/g, '').split(' ');
  var chars = 0;
  lineRead = '';
  for (var i = 0; i < words.length; i++) {
    var wd = words[i];
    chars += wd.length + 1;
    if (chars > linelen) {
      chars = 0;
      lineRead += '\n';
    }
    lineRead += wd + ' ';
  }
  im.convert([
      imageFile,
      '-resize', fullWidth + 'x' + fullHeight,
      '-gravity', dir,
      '-background', background,
      '-opaque', foreground,
      '-extent', fullWidth + 'x' + fullHeight,
      'resized_' + imageBaseName
    ], function (err, output) {
    if (err) {
      console.log(err);
    }
    im.convert([
      'resized_' + imageBaseName,
      '-fill', foreground,
      '-font', fontFile,
      '-pointsize', 48,
      '-annotate', geo,
      lineRead,
      'text_' + imageBaseName
      ], function (err, output) {
      var videoName = outDir + '/video' + ('00000' + lineNumber).slice(-5) + '.mp4';
      fs.unlink('resized_' + imageBaseName);
      cp.spawnSync('/usr/bin/ffmpeg', [
        '-framerate', '1/' + time,
        '-i', 'text_' + imageBaseName,
        '-strict', '-2',
        '-c:v', 'libx264',
        '-r', '30',
        '-pix_fmt', 'yuv420p',
        videoName
      ]);
      fs.unlink('text_' + imageBaseName);
    });
  });
});
<commit_msg>Refactor line length<commit_after>const fs = require('fs');
const cp = require('child_process');
const im = require('imagemagick');
const readline = require('readline');
const commandLineArgs = require('command-line-args');
const speakIndexName = 'whospeak.csv';
const charIndexName = 'chars.txt';

const fullWidth = 1920;
const fullHeight = 1080;
const outDir = 'clips';
const charPerLine = 30;

const optionDefinitions = [
  { name: 'background', alias: 'b', type: String },
  { name: 'color', alias: 'c', type: String },
  { name: 'font', alias: 'f', type: String },
  { name: 'image', alias: 'i', type: String },
  { name: 'line', alias: 'l', type: Number },
  { name: 'novoice', alias: 'n', type: Boolean },
  { name: 'play', alias: 'p', type: String },
];
const options = commandLineArgs(optionDefinitions);

if (
      !options.hasOwnProperty('font')
   || !options.hasOwnProperty('image')
   || !options.hasOwnProperty('line')
   || !options.hasOwnProperty('play')
   ) {
  // Can't do anything useful without input
  return;
}

var background = options.hasOwnProperty('background') ? options.background : 'lightgray';
var foreground = options.hasOwnProperty('color') ? options.color : 'black';
var fontFile = options.font;
var imageFile = options.image;
var lineNumber = options.line;
var playFile = options.play;
var novoice = options.hasOwnProperty('novoice') ? options.novoice : false;
var imageBaseName = imageFile.split('/').pop();
var screenplay = fs.readFileSync(playFile).toString().split('\n');
var lines = screenplay.length;
var digits = lines.toString().length;
screenplay.unshift('');

var lineRead = screenplay[lineNumber];
var audioName = 'output/speech' + lineNumber + '.wav';
var proc = cp.spawnSync('/usr/bin/soxi', [ '-D', audioName ]);
var time = parseFloat(proc.stdout.toString().trim(), 10);
var width = 0;
var height = 0;
var rSwitch = Math.round(Math.random());

var speakIndex = fs.readFileSync(speakIndexName).toString().replace('|', ',').split('\n');
var charIndex = fs.readFileSync(charIndexName).toString().split('\n');

im.identify(imageFile, function (err, features) {
  if (err) throw err;
  var linelen = 100;
  var dir = 'Center';
  var geo = '+100+100';
  width = features.width;
  height = features.height;
  if (width > height) {
    var xScale = fullWidth / width;
    linelen = Math.round((fullWidth - 200) / charPerLine);
    if (rSwitch == 1) {
      dir = 'South';
      geo = '+100+100';
    } else {
      dir = 'North';
      geo = '+100+' + (height * xScale + 50);
    }
  } else {
    var yScale = fullHeight / height;
    linelen = Math.round((fullWidth - width * yScale - 200) / charPerLine);
    if (rSwitch == 1) {
      dir = 'East';
      geo = '+100+100';
    } else {
      dir = 'West';
      geo = '+' + (100 + Math.round(width * yScale)) + '+100';
    }
  }
  var words = lineRead.replace(/_/g, '').split(' ');
  var chars = 0;
  lineRead = '';
  for (var i = 0; i < words.length; i++) {
    var wd = words[i];
    chars += wd.length + 1;
    if (chars > linelen) {
      chars = 0;
      lineRead += '\n';
    }
    lineRead += wd + ' ';
  }
  im.convert([
      imageFile,
      '-resize', fullWidth + 'x' + fullHeight,
      '-gravity', dir,
      '-background', background,
      '-opaque', foreground,
      '-extent', fullWidth + 'x' + fullHeight,
      'resized_' + imageBaseName
    ], function (err, output) {
    if (err) {
      console.log(err);
    }
    im.convert([
      'resized_' + imageBaseName,
      '-fill', foreground,
      '-font', fontFile,
      '-pointsize', 48,
      '-annotate', geo,
      lineRead,
      'text_' + imageBaseName
      ], function (err, output) {
      var videoName = outDir + '/video' + ('00000' + lineNumber).slice(-5) + '.mp4';
      fs.unlink('resized_' + imageBaseName);
      cp.spawnSync('/usr/bin/ffmpeg', [
        '-framerate', '1/' + time,
        '-i', 'text_' + imageBaseName,
        '-strict', '-2',
        '-c:v', 'libx264',
        '-r', '30',
        '-pix_fmt', 'yuv420p',
        videoName
      ]);
      fs.unlink('text_' + imageBaseName);
    });
  });
});
<|endoftext|>