<commit_before>var _ = require('../util').lodash,
    PropertyBase = require('./property-base').PropertyBase,

    __PARENT = '__parent',
    DEFAULT_INDEX_ATTR = 'id',
    DEFAULT_INDEXCASE_ATTR = false,

    PropertyList;

_.inherit((
    /**
     * @constructor
     *
     * @todo
     * - document stuff
     */
    PropertyList = function PostmanPropertyList (type, parent, populate) {
        // @todo add this test sometime later
        // if (!type) {
        //     throw new Error('postman-collection: cannot initialise a list without a type parameter');
        // }

        PropertyList.super_.call(this); // call super with appropriate options

        _.assignLocked(this, __PARENT, parent); // save reference to parent
        _.extend(this, /** @lends PropertyList.prototype */ {
            /**
             * @private
             * @type {Array}
             */
            members: this.members || [],
            /**
             * @private
             * @type {Object}
             */
            reference: this.reference || {},
            /**
             * @private
             * @type {Function}
             */
            Type: type,
            /**
             * Holds the attribute to index this PropertyList by. Default: 'id'
             *
             * @private
             * @type {String}
             */
            _postman_propertyIndexKey: _.getOwn(type, '_postman_propertyIndexKey', DEFAULT_INDEX_ATTR),
            /**
             * Holds the attribute whether indexing of this list is case sensitive or not
             *
             * @private
             * @type {String}
             */
            _postman_propertyIndexCaseInsensitive: _.getOwn(type, '_postman_propertyIndexCaseInsensitive',
                DEFAULT_INDEXCASE_ATTR)
        });

        // prepopulate
        populate && this.populate(populate);
    }), PropertyBase);

_.extend(PropertyList.prototype, /** @lends PropertyList.prototype */ {

    /**
     * Indicates that this element contains a number of other elements.
     * @private
     */
    _postman_propertyIsList: true,

    /**
     * Insert an element at the end of this list. When a reference member specified via second parameter is found, the
     * member is inserted at an index before the reference member.
     *
     * @param {PropertyList.Type} item
     * @param {PropertyList.Type|String} [before]
     */
    insert: function (item, before) {
        if (!_.isObject(item)) { return; } // do not proceed on empty param

        var duplicate = this.indexOf(item),
            index;

        // remove from previous list
        PropertyList.isPropertyList(item[__PARENT]) && (item[__PARENT] !== this) && item[__PARENT].remove(item);
        // inject the parent reference
        _.assignHidden(item, __PARENT, this);

        // ensure that we do not double insert things into member array
        (duplicate > -1) && this.members.splice(duplicate, 1);
        // find the position of the reference element
        before && (before = this.indexOf(before));

        // inject to the members array ata position or at the end in case no item is there for reference
        (before > -1) ? this.members.splice(before, 0, item) : this.members.push(item);

        // store reference by id, so create the index string. we first ensure that the index value is truthy and then
        // recheck that the string conversion of the same is truthy as well.
        if ((index = item[this._postman_propertyIndexKey]) && (index = String(index))) {
            // desensitise case, if the property needs it to be
            this._postman_propertyIndexCaseInsensitive && (index = index.toLowerCase());
            this.reference[index] = item;
        }
    },

    /**
     * Insert an element at the end of this list. When a reference member specified via second parameter is found, the
     * member is inserted at an index after the reference member.
     *
     * @param {PropertyList.Type} item
     * @param {PropertyList.Type|String} [after]
     */
    insertAfter: function (item, after) {
        // convert item to positional reference
        return this.insert(item, this.idx(this.indexOf(after) + 1));
    },

    /**
     * Adds or moves an item to the end of this list
     * @param {PropertyList.Type} item
     */
    append: function (item) {
        return this.insert(item);
    },

    /**
     * Adds or moves an item to the beginning of this list
     * @param {PropertyList.Type} item
     */
    prepend: function (item) {
        return this.insert(item, this.idx(0));
    },

    /**
     * Add an item or item definition to this list
     * @param {Object|PropertyList.Type} item
     *
     * @todo
     * - remove item from original parent if already it has a parent
     * - validate that the original parent's constructor matches this parent's constructor
     */
    add: function (item) {
        // do not proceed on empty param, but empty strings are in fact valid.
        if (_.isNull(item) || _.isUndefined(item) || _.isNaN()) { return; }

        // create new instance of the item based on the type specified if it is not already
        this.insert((item.constructor === this.Type) ? item :
            // if the prperty has acreate static function, use it.
            (_.has(this.Type, 'create') ? this.Type.create.apply(this.Type, arguments) : new this.Type(item)));
    },

    /**
     * Removes all elements from the PropertyList for which the predicate returns truthy.
     * @param predicate {Function|String|Type}
     * @param context {Object} Optional context to bind the predicate to.
     */
    remove: function (predicate, context) {
        var match; // to be used if predicate is an ID

        !context && (context = this);
        // if predicate is id, then create a function to remove that from array
        if (_.isString(predicate)) {
            (match = this.one(predicate)) && (predicate = function (item) {
                return (item === match);
            });
        }
        // in case an object reference is sent, prepare it for removal
        else if (predicate instanceof this.Type) {
            match = predicate;
            predicate = function (item) {
                return (item === match);
            };
        }

        _.isFunction(predicate) && _.remove(this.members, function (item) {
            var index;
            if (predicate.apply(context, arguments)) {
                if ((index = item[this._postman_propertyIndexKey]) && (index = String(index))) {
                    this._postman_propertyIndexCaseInsensitive && (index = index.toLowerCase());
                    delete this.reference[index];
                }
                delete item[__PARENT]; // unlink from its parent
                return true;
            }
        }, this);
    },

    /**
     * Load one or more items
     *
     * @param {Object|Array} items
     */
    populate: function (items) {
        // if Type supports parsing of string headers then do it before adding it.
        _.isString(items) && _.isFunction(this.Type.parse) && (items = this.Type.parse(items));
        // add a single item or an array of items.
        _.each(_.isArray(items) ? items :
            // if population is not an array, we send this as single item in an array or send each property separately
            // if the core Type supports Type.create
            ((_.isPlainObject(items) && _.has(this.Type, 'create')) ? items : [items]), this.add, this);
    },

    /**
     * Removes all items in the list
     */
    clear: function () {
        this.each(this.remove.bind(this));
    },

    /**
     * Returns a map of all items
     * @returns {Object}
     */
    all: function () {
        return _.clone(this.members);
    },

    /**
     * Get Item in this list by `ID` reference
     *
     * @param {String} id
     * @returns {PropertyList.Type}
     */
    one: function (id) {
        return this.reference[this._postman_propertyIndexCaseInsensitive ? String(id).toLowerCase() : id];
    },

    /**
     * Iterate on each item of this list
     */
    each: function (iterator, context) {
        _.each(this.members, iterator, context || this.__parent);
    },

    /**
     * @param {Function} rule
     */
    filter: function (rule, context) {
        return _.filter(this.members, rule, context);
    },

    /**
     * Find an item within the item group
     *
     * @param {Function} rule
     * @param {Object} [context]
     * @returns {Item|ItemGroup}
     */
    find: function (rule, context) {
        return _.find(this.members, rule, context);
    },

    /**
     * Iterates over the property list.
     *
     * @param iterator {Function} Function to call on each item.
     * @param context Optional context, defaults to the PropertyList itself.
     */
    map: function (iterator, context) {
        !context && (context = this);
        return _.map(this.members, iterator, context);
    },

    /**
     * Returns the length of the PropertyList
     *
     * @returns {Number}
     */
    count: function () {
        return this.members.length;
    },

    /**
     * Get a member of this list by it's index
     *
     * @param {Number} index
     * @returns {PropertyList.Type}
     */
    idx: function (index) {
        return this.members[index];
    },

    /**
     * Find the index of an item in this list
     *
     * @param {String|Object} item
     * @returns {Number}
     */
    indexOf: function (item) {
        return this.members.indexOf(_.isString(item) ? (item = this.one(item)) : item);
    },

    /**
     * Check whether an item exists in this list
     *
     * @param {String|PropertyList.Type} item
     * @returns {Boolean}
     */
    has: function (item) {
        return !!( _.isString(item) ? this.one(item) : this.filter(function (member) {
            return member === item;
        }).length);
    },

    /**
     * Iterates over all parents of the property list
     *
     * @param {Function} iterator
     * @param {Object=} [context]
     */
    eachParent: function (iterator, context) {
        // validate parameters
        if (!_.isFunction(iterator)) { return; }
        !context && (context = this);

        var parent = this.__parent,
            prev;

        // iterate till there is no parent
        while (parent) {
            // call iterator with the parent and previous parent
            iterator.call(context, parent, prev);

            // update references
            prev = parent;
            parent = parent.__parent;
        }
    },

    toJSON: function () {
        if (!this.count()) {
            return;
        }

        return _.map(this.members, function (member) {
            return _.reduce(member, function (accumulator, value, key) {
                if (value === undefined) { // true/false/null need to be preserved.
                    return accumulator;
                }

                // Handle plurality of PropertyLists in the SDK vs the exported JSON.
                // Basically, removes the trailing "s" from key if the value is a property list.
                if (value && value._postman_propertyIsList && _.endsWith(key, 's')) {
                    key = key.slice(0, -1);
                }

                // Handle 'PropertyBase's
                if (value && _.isFunction(value.toJSON)) {
                    accumulator[key] = value.toJSON();
                    return accumulator;
                }

                // Handle Strings
                if (_.isString(value)) {
                    accumulator[key] = value;
                    return accumulator;
                }

                // Everything else
                accumulator[key] = _.cloneElement(value);
                return accumulator;
            }, {});
        });
    }
});

_.extend(PropertyList, /** @lends PropertyList */ {
    /**
     * Defines the name of this property for internal use.
     * @private
     * @readOnly
     * @type {String}
     */
    _postman_propertyName: 'PropertyList',
    /**
     * Checks whether an object is a PropertyList
     *
     * @param {*} obj
     * @returns {Boolean}
     */
    isPropertyList: function (obj) {
        return obj && ((obj instanceof PropertyList) ||
            _.inSuperChain(obj.constructor, '_postman_propertyName', PropertyList._postman_propertyName));
    }
});

module.exports = {
    PropertyList: PropertyList
};
<commit_msg>Fixed issue in PropertyList.add where isNaN missed the `item` variable as parameter<commit_after>var _ = require('../util').lodash,
    PropertyBase = require('./property-base').PropertyBase,

    __PARENT = '__parent',
    DEFAULT_INDEX_ATTR = 'id',
    DEFAULT_INDEXCASE_ATTR = false,

    PropertyList;

_.inherit((
    /**
     * @constructor
     *
     * @todo
     * - document stuff
     */
    PropertyList = function PostmanPropertyList (type, parent, populate) {
        // @todo add this test sometime later
        // if (!type) {
        //     throw new Error('postman-collection: cannot initialise a list without a type parameter');
        // }

        PropertyList.super_.call(this); // call super with appropriate options

        _.assignLocked(this, __PARENT, parent); // save reference to parent
        _.extend(this, /** @lends PropertyList.prototype */ {
            /**
             * @private
             * @type {Array}
             */
            members: this.members || [],
            /**
             * @private
             * @type {Object}
             */
            reference: this.reference || {},
            /**
             * @private
             * @type {Function}
             */
            Type: type,
            /**
             * Holds the attribute to index this PropertyList by. Default: 'id'
             *
             * @private
             * @type {String}
             */
            _postman_propertyIndexKey: _.getOwn(type, '_postman_propertyIndexKey', DEFAULT_INDEX_ATTR),
            /**
             * Holds the attribute whether indexing of this list is case sensitive or not
             *
             * @private
             * @type {String}
             */
            _postman_propertyIndexCaseInsensitive: _.getOwn(type, '_postman_propertyIndexCaseInsensitive',
                DEFAULT_INDEXCASE_ATTR)
        });

        // prepopulate
        populate && this.populate(populate);
    }), PropertyBase);

_.extend(PropertyList.prototype, /** @lends PropertyList.prototype */ {

    /**
     * Indicates that this element contains a number of other elements.
     * @private
     */
    _postman_propertyIsList: true,

    /**
     * Insert an element at the end of this list. When a reference member specified via second parameter is found, the
     * member is inserted at an index before the reference member.
     *
     * @param {PropertyList.Type} item
     * @param {PropertyList.Type|String} [before]
     */
    insert: function (item, before) {
        if (!_.isObject(item)) { return; } // do not proceed on empty param

        var duplicate = this.indexOf(item),
            index;

        // remove from previous list
        PropertyList.isPropertyList(item[__PARENT]) && (item[__PARENT] !== this) && item[__PARENT].remove(item);
        // inject the parent reference
        _.assignHidden(item, __PARENT, this);

        // ensure that we do not double insert things into member array
        (duplicate > -1) && this.members.splice(duplicate, 1);
        // find the position of the reference element
        before && (before = this.indexOf(before));

        // inject to the members array ata position or at the end in case no item is there for reference
        (before > -1) ? this.members.splice(before, 0, item) : this.members.push(item);

        // store reference by id, so create the index string. we first ensure that the index value is truthy and then
        // recheck that the string conversion of the same is truthy as well.
        if ((index = item[this._postman_propertyIndexKey]) && (index = String(index))) {
            // desensitise case, if the property needs it to be
            this._postman_propertyIndexCaseInsensitive && (index = index.toLowerCase());
            this.reference[index] = item;
        }
    },

    /**
     * Insert an element at the end of this list. When a reference member specified via second parameter is found, the
     * member is inserted at an index after the reference member.
     *
     * @param {PropertyList.Type} item
     * @param {PropertyList.Type|String} [after]
     */
    insertAfter: function (item, after) {
        // convert item to positional reference
        return this.insert(item, this.idx(this.indexOf(after) + 1));
    },

    /**
     * Adds or moves an item to the end of this list
     * @param {PropertyList.Type} item
     */
    append: function (item) {
        return this.insert(item);
    },

    /**
     * Adds or moves an item to the beginning of this list
     * @param {PropertyList.Type} item
     */
    prepend: function (item) {
        return this.insert(item, this.idx(0));
    },

    /**
     * Add an item or item definition to this list
     * @param {Object|PropertyList.Type} item
     *
     * @todo
     * - remove item from original parent if already it has a parent
     * - validate that the original parent's constructor matches this parent's constructor
     */
    add: function (item) {
        // do not proceed on empty param, but empty strings are in fact valid.
        if (_.isNull(item) || _.isUndefined(item) || _.isNaN(item)) { return; }

        // create new instance of the item based on the type specified if it is not already
        this.insert((item.constructor === this.Type) ? item :
            // if the prperty has acreate static function, use it.
            (_.has(this.Type, 'create') ? this.Type.create.apply(this.Type, arguments) : new this.Type(item)));
    },

    /**
     * Removes all elements from the PropertyList for which the predicate returns truthy.
     * @param predicate {Function|String|Type}
     * @param context {Object} Optional context to bind the predicate to.
     */
    remove: function (predicate, context) {
        var match; // to be used if predicate is an ID

        !context && (context = this);
        // if predicate is id, then create a function to remove that from array
        if (_.isString(predicate)) {
            (match = this.one(predicate)) && (predicate = function (item) {
                return (item === match);
            });
        }
        // in case an object reference is sent, prepare it for removal
        else if (predicate instanceof this.Type) {
            match = predicate;
            predicate = function (item) {
                return (item === match);
            };
        }

        _.isFunction(predicate) && _.remove(this.members, function (item) {
            var index;
            if (predicate.apply(context, arguments)) {
                if ((index = item[this._postman_propertyIndexKey]) && (index = String(index))) {
                    this._postman_propertyIndexCaseInsensitive && (index = index.toLowerCase());
                    delete this.reference[index];
                }
                delete item[__PARENT]; // unlink from its parent
                return true;
            }
        }, this);
    },

    /**
     * Load one or more items
     *
     * @param {Object|Array} items
     */
    populate: function (items) {
        // if Type supports parsing of string headers then do it before adding it.
        _.isString(items) && _.isFunction(this.Type.parse) && (items = this.Type.parse(items));
        // add a single item or an array of items.
        _.each(_.isArray(items) ? items :
            // if population is not an array, we send this as single item in an array or send each property separately
            // if the core Type supports Type.create
            ((_.isPlainObject(items) && _.has(this.Type, 'create')) ? items : [items]), this.add, this);
    },

    /**
     * Removes all items in the list
     */
    clear: function () {
        this.each(this.remove.bind(this));
    },

    /**
     * Returns a map of all items
     * @returns {Object}
     */
    all: function () {
        return _.clone(this.members);
    },

    /**
     * Get Item in this list by `ID` reference
     *
     * @param {String} id
     * @returns {PropertyList.Type}
     */
    one: function (id) {
        return this.reference[this._postman_propertyIndexCaseInsensitive ? String(id).toLowerCase() : id];
    },

    /**
     * Iterate on each item of this list
     */
    each: function (iterator, context) {
        _.each(this.members, iterator, context || this.__parent);
    },

    /**
     * @param {Function} rule
     */
    filter: function (rule, context) {
        return _.filter(this.members, rule, context);
    },

    /**
     * Find an item within the item group
     *
     * @param {Function} rule
     * @param {Object} [context]
     * @returns {Item|ItemGroup}
     */
    find: function (rule, context) {
        return _.find(this.members, rule, context);
    },

    /**
     * Iterates over the property list.
     *
     * @param iterator {Function} Function to call on each item.
     * @param context Optional context, defaults to the PropertyList itself.
     */
    map: function (iterator, context) {
        !context && (context = this);
        return _.map(this.members, iterator, context);
    },

    /**
     * Returns the length of the PropertyList
     *
     * @returns {Number}
     */
    count: function () {
        return this.members.length;
    },

    /**
     * Get a member of this list by it's index
     *
     * @param {Number} index
     * @returns {PropertyList.Type}
     */
    idx: function (index) {
        return this.members[index];
    },

    /**
     * Find the index of an item in this list
     *
     * @param {String|Object} item
     * @returns {Number}
     */
    indexOf: function (item) {
        return this.members.indexOf(_.isString(item) ? (item = this.one(item)) : item);
    },

    /**
     * Check whether an item exists in this list
     *
     * @param {String|PropertyList.Type} item
     * @returns {Boolean}
     */
    has: function (item) {
        return !!( _.isString(item) ? this.one(item) : this.filter(function (member) {
            return member === item;
        }).length);
    },

    /**
     * Iterates over all parents of the property list
     *
     * @param {Function} iterator
     * @param {Object=} [context]
     */
    eachParent: function (iterator, context) {
        // validate parameters
        if (!_.isFunction(iterator)) { return; }
        !context && (context = this);

        var parent = this.__parent,
            prev;

        // iterate till there is no parent
        while (parent) {
            // call iterator with the parent and previous parent
            iterator.call(context, parent, prev);

            // update references
            prev = parent;
            parent = parent.__parent;
        }
    },

    toJSON: function () {
        if (!this.count()) {
            return;
        }

        return _.map(this.members, function (member) {
            return _.reduce(member, function (accumulator, value, key) {
                if (value === undefined) { // true/false/null need to be preserved.
                    return accumulator;
                }

                // Handle plurality of PropertyLists in the SDK vs the exported JSON.
                // Basically, removes the trailing "s" from key if the value is a property list.
                if (value && value._postman_propertyIsList && _.endsWith(key, 's')) {
                    key = key.slice(0, -1);
                }

                // Handle 'PropertyBase's
                if (value && _.isFunction(value.toJSON)) {
                    accumulator[key] = value.toJSON();
                    return accumulator;
                }

                // Handle Strings
                if (_.isString(value)) {
                    accumulator[key] = value;
                    return accumulator;
                }

                // Everything else
                accumulator[key] = _.cloneElement(value);
                return accumulator;
            }, {});
        });
    }
});

_.extend(PropertyList, /** @lends PropertyList */ {
    /**
     * Defines the name of this property for internal use.
     * @private
     * @readOnly
     * @type {String}
     */
    _postman_propertyName: 'PropertyList',
    /**
     * Checks whether an object is a PropertyList
     *
     * @param {*} obj
     * @returns {Boolean}
     */
    isPropertyList: function (obj) {
        return obj && ((obj instanceof PropertyList) ||
            _.inSuperChain(obj.constructor, '_postman_propertyName', PropertyList._postman_propertyName));
    }
});

module.exports = {
    PropertyList: PropertyList
};
<|endoftext|>


<commit_before>function gpxParser() {
	this.parseGPX = function() {

		/* Example */
		var jsonExampleData = {
			metadata: {
				name: 'The name of the GPX file',
				desc: 'A description of the contents of the GPX file',
				author: {
					name: 'Author name'
				},
				time: '2007-10-02T07:51:30Z',
			},
			trkdata: {
				name: 'GPS name of track',
				cmt: 'GPS comment for track',
				desc: 'User description of track',
				number: '1',
			},
			trkpts: [{
				attributes: {
					lat: '46.57608333',
					lon: '8.89241667'
				},
				ele: '2373',
				time: '2007-10-02T07:51:30Z'
			}, {
				attributes: {
					lat: '46.57619444',
					lon: '8.89252778'
				},
				ele: '2375',
				time: '2007-10-02T07:56:30Z'
			}, {
				attributes: {
					lat: '46.57641667',
					lon: '8.89266667'
				},
				ele: '2372',
				time: '2007-10-02T07:59:30Z'
			}]
		};

		return _toGPX(jsonExampleData);
	}

	this.parseJSON = function() {
		/* Will be implemented as soon as possible */
	}

	var _toJSON = function(gpxData) {
		var parser = new DOMParser();
	};

	var _toGPX = function(jsonData) {

		var metadata = jsonData.metadata;
		var trkdata = jsonData.trkdata;
		var trkpts = jsonData.trkpts;

		/* Create gpx document*/
		var gpxDoc = document.implementation.createDocument('', '', null);

		/* Initialize gpx element */
		var gpxElem = _createRoot(gpxDoc);

		/* Initialize metadata */
		var metadataElem = gpxDoc.createElement('metadata');
		metadataElem = _createMetadata(gpxDoc, metadata, metadataElem);

		/* Initialize track info */
		var trkElem = gpxDoc.createElement('trk');
		trkElem = _createTrackData(gpxDoc, trkdata, trkElem);

		/* Initialize tack segments info */
		var trksegElem = gpxDoc.createElement('trkseg');
		trksegElem = _createTrkPts(gpxDoc, trkpts, trksegElem);

		/* Mounting of the GPX tree */
		gpxElem.appendChild(metadataElem);
		trkElem.appendChild(trksegElem);
		gpxElem.appendChild(trkElem);

		return gpxElem;
	};

	var _createRoot = function(gpxDoc) {

		/* Attributes for GXP 1.1 version */
		var VERSION = '1.1';
		var CREATOR = 'Software that created your GPX document'; //Creator name. Example: Application name.
		var XMLNS_XSI = 'http://www.w3.org/2001/XMLSchema-instance';
		var XMLNS = 'http://www.topografix.com/GPX/1/1';
		var XSI_SCHEMALOCATION = 'http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd';

		var gxpElem = gpxDoc.createElement('gpx');
		gxpElem.setAttribute('version', VERSION);
		gxpElem.setAttribute('creator', CREATOR);
		gxpElem.setAttribute('xmlns:xsi', XMLNS_XSI);
		gxpElem.setAttribute('xmlns', XMLNS);
		gxpElem.setAttribute('xsi:schemaLocation', XSI_SCHEMALOCATION);

		return gxpElem;
	};

	var _createMetadata = function(gpxDoc, metadata, metadataElem) {
		var name = metadata.name;
		var descFile = metadata.desc;
		var author = metadata.author;
		var fileTime = metadata.time;

		/* The name of the GPX file */
		if(name) {
			var nameElem = gpxDoc.createElement('name');
			var nameVal = gpxDoc.createTextNode(name);

			nameElem.appendChild(nameVal);
			metadataElem.appendChild(nameElem);
		}

		/* A description of the contents of the GPX file */
		if(descFile) {
			var descElem = gpxDoc.createElement('desc');
			var descVal = gpxDoc.createTextNode(descFile);

			descElem.appendChild(descVal);
			metadataElem.appendChild(descElem);
		}

		/* Author name or URL */
		if(author.name) {
			var authorElem = gpxDoc.createElement('author');
			var authorNameElem = gpxDoc.createElement('name');

			authorVal = gpxDoc.createTextNode(author.name);
			authorNameElem.appendChild(authorVal);
			authorElem.appendChild(authorNameElem);
			metadataElem.appendChild(authorElem);
		}

		/* The creation date of the file */
		if(fileTime) {
			var fileTimeElem = gpxDoc.createElement('time');
			var fileTimeVal = gpxDoc.createTextNode(fileTime);

			fileTimeElem.appendChild(fileTimeVal);
			metadataElem.appendChild(fileTimeElem);
		}

		return metadataElem;
	};

	var _createTrackData = function(gpxDoc, trkdata, trkElem) {
		var name = trkdata.name;
		var cmt = trkdata.cmt;
		var descTrack = trkdata.desc;
		var number = trkdata.number;

		/* GPS name of track */
		if(name) {
			var nameElem = gpxDoc.createElement('name');
			var nameVal = gpxDoc.createTextNode(name);

			nameElem.appendChild(nameVal);
			trkElem.appendChild(nameElem);
		}

		/* GPS comment for track */
		if(cmt) {
			var cmtElem = gpxDoc.createElement('cmt');
			var cmtVal = gpxDoc.createTextNode(cmt);

			cmtElem.appendChild(cmtVal);
			trkElem.appendChild(cmtElem);
		}

		/* A description of the contents of the GPX file */
		if(descTrack) {
			var descElem = gpxDoc.createElement('desc');
			var descVal = gpxDoc.createTextNode(descTrack);

			descElem.appendChild(descVal);
			trkElem.appendChild(descElem);
		}

		/* GPS track number */
		if(number) {
			var numberElem = gpxDoc.createElement('number');
			var numberVal = gpxDoc.createTextNode(number);

			numberElem.appendChild(numberVal);
			trkElem.appendChild(numberElem);
		}

		return trkElem;
	};

	var _createTrkPts = function(gpxDoc, trkpts, trksegElem) {
		var trkpt,
			latVal,
			lonVal,
			eleElem,
			eleVal,
			ptTimeElem,
			ptTimeVal;

		for (var pt = 0; trkpts.length > pt; pt++) {
			trkpt = gpxDoc.createElement('trkpt');

			/* Get LatLng attributes */
			latVal = trkpts[pt].attributes.lat;
			lonVal = trkpts[pt].attributes.lon;

			/* Get elevation/altitude value */
			eleElem = gpxDoc.createElement('ele');
			eleVal = gpxDoc.createTextNode(trkpts[pt].ele);
			eleElem.appendChild(eleVal);

			/* Get point time */
			ptTimeElem = gpxDoc.createElement('time');
			ptTimeVal = gpxDoc.createTextNode(trkpts[pt].time);
			ptTimeElem.appendChild(ptTimeVal);

			/* Mounting of the point tree */
			trkpt.setAttribute('lat', latVal);
			trkpt.setAttribute('lon', lonVal);
			trkpt.appendChild(eleElem);
			trkpt.appendChild(ptTimeElem);

			trksegElem.appendChild(trkpt);
		}

		return trksegElem;
	};
};

var gpxParserInst = new gpxParser();
console.log(gpxParserInst.parseGPX());<commit_msg>Fix: method names<commit_after>function gpxParser() {
	this.parseJSON = function() {

		/* Example */
		var jsonExampleData = {
			metadata: {
				name: 'The name of the GPX file',
				desc: 'A description of the contents of the GPX file',
				author: {
					name: 'Author name'
				},
				time: '2007-10-02T07:51:30Z',
			},
			trkdata: {
				name: 'GPS name of track',
				cmt: 'GPS comment for track',
				desc: 'User description of track',
				number: '1',
			},
			trkpts: [{
				attributes: {
					lat: '46.57608333',
					lon: '8.89241667'
				},
				ele: '2373',
				time: '2007-10-02T07:51:30Z'
			}, {
				attributes: {
					lat: '46.57619444',
					lon: '8.89252778'
				},
				ele: '2375',
				time: '2007-10-02T07:56:30Z'
			}, {
				attributes: {
					lat: '46.57641667',
					lon: '8.89266667'
				},
				ele: '2372',
				time: '2007-10-02T07:59:30Z'
			}]
		};

		return _toGPX(jsonExampleData);
	}

	this.parseGPX = function() {
		/* Will be implemented as soon as possible */
	}

	var _toJSON = function(gpxData) {
		var parser = new DOMParser();
	};

	var _toGPX = function(jsonData) {

		var metadata = jsonData.metadata;
		var trkdata = jsonData.trkdata;
		var trkpts = jsonData.trkpts;

		/* Create gpx document*/
		var gpxDoc = document.implementation.createDocument('', '', null);

		/* Initialize gpx element */
		var gpxElem = _createRoot(gpxDoc);

		/* Initialize metadata */
		var metadataElem = gpxDoc.createElement('metadata');
		metadataElem = _createMetadata(gpxDoc, metadata, metadataElem);

		/* Initialize track info */
		var trkElem = gpxDoc.createElement('trk');
		trkElem = _createTrackData(gpxDoc, trkdata, trkElem);

		/* Initialize tack segments info */
		var trksegElem = gpxDoc.createElement('trkseg');
		trksegElem = _createTrkPts(gpxDoc, trkpts, trksegElem);

		/* Mounting of the GPX tree */
		gpxElem.appendChild(metadataElem);
		trkElem.appendChild(trksegElem);
		gpxElem.appendChild(trkElem);

		return gpxElem;
	};

	var _createRoot = function(gpxDoc) {

		/* Attributes for GXP 1.1 version */
		var VERSION = '1.1';
		var CREATOR = 'Software that created your GPX document'; //Creator name. Example: Application name.
		var XMLNS_XSI = 'http://www.w3.org/2001/XMLSchema-instance';
		var XMLNS = 'http://www.topografix.com/GPX/1/1';
		var XSI_SCHEMALOCATION = 'http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd';

		var gxpElem = gpxDoc.createElement('gpx');
		gxpElem.setAttribute('version', VERSION);
		gxpElem.setAttribute('creator', CREATOR);
		gxpElem.setAttribute('xmlns:xsi', XMLNS_XSI);
		gxpElem.setAttribute('xmlns', XMLNS);
		gxpElem.setAttribute('xsi:schemaLocation', XSI_SCHEMALOCATION);

		return gxpElem;
	};

	var _createMetadata = function(gpxDoc, metadata, metadataElem) {
		var name = metadata.name;
		var descFile = metadata.desc;
		var author = metadata.author;
		var fileTime = metadata.time;

		/* The name of the GPX file */
		if(name) {
			var nameElem = gpxDoc.createElement('name');
			var nameVal = gpxDoc.createTextNode(name);

			nameElem.appendChild(nameVal);
			metadataElem.appendChild(nameElem);
		}

		/* A description of the contents of the GPX file */
		if(descFile) {
			var descElem = gpxDoc.createElement('desc');
			var descVal = gpxDoc.createTextNode(descFile);

			descElem.appendChild(descVal);
			metadataElem.appendChild(descElem);
		}

		/* Author name or URL */
		if(author.name) {
			var authorElem = gpxDoc.createElement('author');
			var authorNameElem = gpxDoc.createElement('name');

			authorVal = gpxDoc.createTextNode(author.name);
			authorNameElem.appendChild(authorVal);
			authorElem.appendChild(authorNameElem);
			metadataElem.appendChild(authorElem);
		}

		/* The creation date of the file */
		if(fileTime) {
			var fileTimeElem = gpxDoc.createElement('time');
			var fileTimeVal = gpxDoc.createTextNode(fileTime);

			fileTimeElem.appendChild(fileTimeVal);
			metadataElem.appendChild(fileTimeElem);
		}

		return metadataElem;
	};

	var _createTrackData = function(gpxDoc, trkdata, trkElem) {
		var name = trkdata.name;
		var cmt = trkdata.cmt;
		var descTrack = trkdata.desc;
		var number = trkdata.number;

		/* GPS name of track */
		if(name) {
			var nameElem = gpxDoc.createElement('name');
			var nameVal = gpxDoc.createTextNode(name);

			nameElem.appendChild(nameVal);
			trkElem.appendChild(nameElem);
		}

		/* GPS comment for track */
		if(cmt) {
			var cmtElem = gpxDoc.createElement('cmt');
			var cmtVal = gpxDoc.createTextNode(cmt);

			cmtElem.appendChild(cmtVal);
			trkElem.appendChild(cmtElem);
		}

		/* A description of the contents of the GPX file */
		if(descTrack) {
			var descElem = gpxDoc.createElement('desc');
			var descVal = gpxDoc.createTextNode(descTrack);

			descElem.appendChild(descVal);
			trkElem.appendChild(descElem);
		}

		/* GPS track number */
		if(number) {
			var numberElem = gpxDoc.createElement('number');
			var numberVal = gpxDoc.createTextNode(number);

			numberElem.appendChild(numberVal);
			trkElem.appendChild(numberElem);
		}

		return trkElem;
	};

	var _createTrkPts = function(gpxDoc, trkpts, trksegElem) {
		var trkpt,
			latVal,
			lonVal,
			eleElem,
			eleVal,
			ptTimeElem,
			ptTimeVal;

		for (var pt = 0; trkpts.length > pt; pt++) {
			trkpt = gpxDoc.createElement('trkpt');

			/* Get LatLng attributes */
			latVal = trkpts[pt].attributes.lat;
			lonVal = trkpts[pt].attributes.lon;

			/* Get elevation/altitude value */
			eleElem = gpxDoc.createElement('ele');
			eleVal = gpxDoc.createTextNode(trkpts[pt].ele);
			eleElem.appendChild(eleVal);

			/* Get point time */
			ptTimeElem = gpxDoc.createElement('time');
			ptTimeVal = gpxDoc.createTextNode(trkpts[pt].time);
			ptTimeElem.appendChild(ptTimeVal);

			/* Mounting of the point tree */
			trkpt.setAttribute('lat', latVal);
			trkpt.setAttribute('lon', lonVal);
			trkpt.appendChild(eleElem);
			trkpt.appendChild(ptTimeElem);

			trksegElem.appendChild(trkpt);
		}

		return trksegElem;
	};
};
<|endoftext|>


<commit_before>const express = require('express');
const router = express.Router(); // eslint-disable-line new-cap
const UserModel = require('../models/user');
const jwt = require('jsonwebtoken');
const config = require('../app/config');

// Authenticate a user
router.post('/authenticate', (req, res) => {
  UserModel.findOne({ username: req.body.username }, (err, user) => {
    if (err) {
      throw err;
    }

    if (!user) {
      res.json({
        status: 'fail',
        meta: {
          message: 'Authentication not possible - username not found',
          validation: {
            username: 'That username could not be found',
          },
        },
        data: null,
      });
    } else {
      const payload = {
        id: user.id,
        username: user.username,
        name: user.name.full,
        role: user.role,
      };

      const token = jwt.sign(payload, config.jwt.secret, {
        expiresIn: req.body.remember ? '14 days' : '1 day',
      });

      res.json({
        status: 'success',
        meta: null,
        data: null,
        token,
      });
    }
  });
});

module.exports = router;
<commit_msg>authenticate: use new config pattern<commit_after>const express = require('express');
const router = express.Router(); // eslint-disable-line new-cap
const jwt = require('jsonwebtoken');
const config = require('nconf');

const UserModel = require('../models/user');

// Authenticate a user
router.post('/authenticate', (req, res) => {
  UserModel.findOne({ username: req.body.username }, (err, user) => {
    if (err) {
      throw err;
    }

    if (!user) {
      res.json({
        status: 'fail',
        meta: {
          message: 'Authentication not possible - username not found',
          validation: {
            username: 'That username could not be found',
          },
        },
        data: null,
      });
    } else {
      const payload = {
        id: user.id,
        username: user.username,
        name: user.name.full,
        role: user.role,
      };

      const token = jwt.sign(payload, config.get('JWT:SECRET'), {
        expiresIn: req.body.remember ? '14 days' : '1 day',
      });

      res.json({
        status: 'success',
        meta: null,
        data: null,
        token,
      });
    }
  });
});

module.exports = router;
<|endoftext|>


<commit_before>/**
 */
function Entity()
{
}
Entity.prototype=
{
};

/**
 * Define setters and getters for a given property.
 */

/** getter */
  // returns value from property dict

/** setter */
  // calls validator and throws exception for bad input
  // set the value in the propery dict

function defineProperty(entity, propname, validator)
{
  entity.__defineGetter__(propname, function()
      {
        return entity.__propertyDict[propname]
      });

  entity.__defineSetter__(propname, function(value)
      {
        entity.__propertyDict[propname] = validator(value);
      });
}
<commit_msg>Removed the entity class file<commit_after><|endoftext|>


<commit_before>var exec = require('child_process').exec;
var fs = require("fs");

var file = __dirname+"/../config/version.js";
require('crypto').randomBytes(6, function(ex, buf) {
  var newId = buf.toString('hex');
  var oldId = require(file).productionVersionId;
  var str = "exports.productionVersionId = \""+newId+"\";";
  fs.unlink(file,function(e){
    fs.writeFile(file, str, function(e){
      console.log("Updating ID from "+oldId+" to "+newId+": "+((e) ? "Error" : "Success"));
      if (!e) {
        exec( "git add "+file+"; "
              +"git commit -m \"Incrementing Production Version.\"; "
              +"git checkout aws_push; "
              +"git merge master -m \"Merging with master branch.\"; "
 //             +"git aws.push; "
 //             +"git checkout master; "
              ,function(err,stdout,stderr){
          console.log(stdout);
          exec("git status | grep clean;",function(err,stdout,stderr){
            if (stdout==="nothing to commit, working directory clean") {
              console.log("OK to push to prod...");
            } else {
              console.log("Not OK to push to prod: "+stdout);
            }
          });
        });
      }
    });
  });
});<commit_msg>publish script<commit_after>var exec = require('child_process').exec;
var fs = require("fs");

var file = __dirname+"/../config/version.js";
require('crypto').randomBytes(6, function(ex, buf) {
  var newId = buf.toString('hex');
  var oldId = require(file).productionVersionId;
  var str = "exports.productionVersionId = \""+newId+"\";";
  fs.unlink(file,function(e){
    fs.writeFile(file, str, function(e){
      console.log("Updating ID from "+oldId+" to "+newId+": "+((e) ? "Error" : "Success"));
      if (!e) {
        exec( "git add "+file+"; "
              +"git commit -m \"Incrementing Production Version.\"; "
              +"git checkout aws_push; "
              +"git merge master -m \"Merging with master branch.\"; "
 //             +"git aws.push; "
 //             +"git checkout master; "
              ,function(err,stdout,stderr){
          console.log(stdout);
          exec("git status | grep \"nothing to commit\";",function(err,stdout,stderr){
            if (stdout.indexOf("nothing to commit, working directory clean") != -1) {
              console.log("OK to push to prod...");
            } else {
              console.log("Not OK to push to prod: "+stdout);
            }
          });
        });
      }
    });
  });
});<|endoftext|>


<commit_before>var fs = require('fs'),
    DDP = require('ddp'),
    ddpLogin = require('ddp-login'),
    config = require('./config.js'),
    os = require('os');

var ddp = new DDP({
  host: config.ddpHost,
  port: config.ddpPort,
  use_ejson: true
})

ddp.connect(function(err){

  if(err) throw err;
  ddpLogin(ddp, {
    env: "METEOR_TOKEN",
    method: "username",
    account: config.key,
    pass: config.secret,
    retry: 5,
    plaintext: false
  }, function(err, userInfo){
    if(err) throw err;

    getAndReportSensors();

  })
})

var getAndReportSensors = function(){
  //Since our IP address may shift, check with each push and let the server know. Slightly simpler than setting this up to email changes.
  //This doesn't appear to be working the best.
  var ifaces = os.networkInterfaces();
  var currentIP = "";
  for (var dev in ifaces) {

    // ... and find the one that matches the criteria
    var iface = ifaces[dev].filter(function(details) {
      return details.family === 'IPv4' && details.internal === false;
    });

    if(iface.length > 0) currentIP = iface[0].address;
  }

  //Next, look at sensors. These particular temperature sensors put their readings into the following location
  var allSensors = fs.readdirSync('/sys/bus/w1/devices');
  var sensorValues = [];

  //Go through each sensor, read it, and push the data into our sensorValues array
  for(var i = 0; i < allSensors.length; i++){
    if(allSensors[i] != 'w1_bus_master1'){
      var logPath = '/sys/bus/w1/devices/' + allSensors[i] + '/w1_slave';
      var tempFile = fs.readFileSync(logPath,'utf8');
      var splitTemp = tempFile.split('t=');
      if(splitTemp.length > 1){
        var currentTemp = splitTemp[1];
        sensorValues.push({
          sensorID: allSensors[i],
          value: currentTemp,
          currentIP: currentIP,
          sensorType:"temp"
        });
      }
      console.log('Temp is', splitTemp[1]);
    }
  }
  //Now call Meteor, and use the 'addValues' call to report the new readings.
  ddp.call(
    'addValues',             // name of Meteor Method being called
    [sensorValues],            // parameters to send to Meteor Method
    function (err, result) {   // callback which returns the method call results
      if(err){
        console.log("Error:", err);
      } else {
        console.log("Values Recorded");
      }
    }
  )
//  setTimeout(getAndReportSensors(), 60 * 1000);
}
<commit_msg>another try...<commit_after>var fs = require('fs'),
    DDP = require('ddp'),
    ddpLogin = require('ddp-login'),
    config = require('./config.js'),
    os = require('os');

var ddp = new DDP({
  host: config.ddpHost,
  port: config.ddpPort,
  use_ejson: true
})

ddp.connect(function(err){

  if(err) throw err;
  ddpLogin(ddp, {
    env: "METEOR_TOKEN",
    method: "username",
    account: config.key,
    pass: config.secret,
    retry: 5,
    plaintext: false
  }, function(err, userInfo){
    if(err) throw err;

    getAndReportSensors();

  })
})

var getAndReportSensors = function(){
  //Since our IP address may shift, check with each push and let the server know. Slightly simpler than setting this up to email changes.
  //This doesn't appear to be working the best.
  var ifaces = os.networkInterfaces();
  var currentIP = "";
  for (var dev in ifaces) {

    // ... and find the one that matches the criteria
    var iface = ifaces[dev].filter(function(details) {
      return details.family === 'IPv4' && details.internal === false;
    });

    if(iface.length > 0) currentIP = iface[0].address;
  }

  //Next, look at sensors. These particular temperature sensors put their readings into the following location
  var allSensors = fs.readdirSync('/sys/bus/w1/devices');
  var sensorValues = [];

  //Go through each sensor, read it, and push the data into our sensorValues array
  for(var i = 0; i < allSensors.length; i++){
    if(allSensors[i] != 'w1_bus_master1'){
      var logPath = '/sys/bus/w1/devices/' + allSensors[i] + '/w1_slave';
      var tempFile = fs.readFileSync(logPath,'utf8');
      var splitTemp = tempFile.split('t=');
      if(splitTemp.length > 1){
        var currentTemp = splitTemp[1];
        sensorValues.push({
          sensorID: allSensors[i],
          value: currentTemp,
          currentIP: currentIP,
          sensorType:"temp"
        });
      }
      console.log('Temp is', splitTemp[1]);
    }
  }
  //Now call Meteor, and use the 'addValues' call to report the new readings.
  ddp.call(
    'addValues',             // name of Meteor Method being called
    [sensorValues],            // parameters to send to Meteor Method
    function (err, result) {   // callback which returns the method call results
      if(err){
        console.log("Error:", err);
      } else {
        console.log("Values Recorded");
      }
    }
  )
  setTimeout(getAndReportSensors(), 6 * 1000);
}
<|endoftext|>


<commit_before>import { filter, pluck, remove } from 'lodash';
import ORMAdapter from '../orm-adapter';

let guid = 0;

export default class MemoryAdapter extends ORMAdapter {

  _cache = {};

  async find(type, query) {
    return filter(this._cache[type] || {}, query);
  }

  async findOne(type, query) {
    if (typeof query === 'number' || typeof query === 'string') {
      return (this._cache[type] && this._cache[type][String(query)]) || null;
    }
    return filter(this._cache[type] || {}, query)[0];
  }

  buildRecord(type, data) {
    this._cache[type] = this._cache[type] || {};
    return data;
  }

  idFor(model) {
    return model.record.id;
  }

  setId() {
    throw new Error('Manually supplying id of a model is not supported by the memory adapter');
  }

  getAttribute(model, property) {
    return model.record[property];
  }

  setAttribute(model, property, value) {
    model.record[property] = value;
    return true;
  }

  deleteAttribute(model, property) {
    model.record[property] = null;
  }

  async getRelated(model, relationship, descriptor) {
    let relatedCollection = this._cache[descriptor.type];
    if (descriptor.mode === 'hasMany') {
      return filter(relatedCollection, (relatedRecord) => {
        return model.record[`${ relationship }_ids`].contains(relatedRecord.id);
      });
    }
    return this.find(relatedCollection, { id: model.record[`${ relationship }_id`] });
  }

  async setRelated(model, relationship, descriptor, relatedRecords) {
    if (descriptor.mode === 'hasMany') {
      model.record[`${ relationship }_ids`] = pluck(relatedRecords, 'id');
    } else {
      model.record[`${ relationship }_id`] = relatedRecords.id;
    }
  }

  async addRelated(model, relationship, descriptor, relatedRecord) {
    model.record[`${ relationship }_ids`].push(relatedRecord.id);
  }

  async removeRelated(model, relationship, descriptor, relatedRecord) {
    remove(model.record[`${ relationship }_ids`], { id: relatedRecord.id });
  }

  async saveRecord(type, model) {
    let collection = this._cache[type];
    if (model.record.id == null) {
      guid += 1;
      model.record.id = guid;
    }
    collection[model.record.id] = model.record;
    return model.record;
  }

  async deleteRecord(type, model) {
    let collection = this._cache[type];
    delete collection[model.record.id];
  }

}
<commit_msg>fix(data): return true to stop proxy from erroring<commit_after>import { filter, pluck, remove } from 'lodash';
import ORMAdapter from '../orm-adapter';

let guid = 0;

export default class MemoryAdapter extends ORMAdapter {

  _cache = {};

  async find(type, query) {
    return filter(this._cache[type] || {}, query);
  }

  async findOne(type, query) {
    if (typeof query === 'number' || typeof query === 'string') {
      return (this._cache[type] && this._cache[type][String(query)]) || null;
    }
    return filter(this._cache[type] || {}, query)[0];
  }

  buildRecord(type, data) {
    this._cache[type] = this._cache[type] || {};
    return data;
  }

  idFor(model) {
    return model.record.id;
  }

  setId() {
    throw new Error('Manually supplying id of a model is not supported by the memory adapter');
  }

  getAttribute(model, property) {
    return model.record[property];
  }

  setAttribute(model, property, value) {
    model.record[property] = value;
    return true;
  }

  deleteAttribute(model, property) {
    model.record[property] = null;
    return true;
  }

  async getRelated(model, relationship, descriptor) {
    let relatedCollection = this._cache[descriptor.type];
    if (descriptor.mode === 'hasMany') {
      return filter(relatedCollection, (relatedRecord) => {
        return model.record[`${ relationship }_ids`].contains(relatedRecord.id);
      });
    }
    return this.find(relatedCollection, { id: model.record[`${ relationship }_id`] });
  }

  async setRelated(model, relationship, descriptor, relatedRecords) {
    if (descriptor.mode === 'hasMany') {
      model.record[`${ relationship }_ids`] = pluck(relatedRecords, 'id');
    } else {
      model.record[`${ relationship }_id`] = relatedRecords.id;
    }
  }

  async addRelated(model, relationship, descriptor, relatedRecord) {
    model.record[`${ relationship }_ids`].push(relatedRecord.id);
  }

  async removeRelated(model, relationship, descriptor, relatedRecord) {
    remove(model.record[`${ relationship }_ids`], { id: relatedRecord.id });
  }

  async saveRecord(type, model) {
    let collection = this._cache[type];
    if (model.record.id == null) {
      guid += 1;
      model.record.id = guid;
    }
    collection[model.record.id] = model.record;
    return model.record;
  }

  async deleteRecord(type, model) {
    let collection = this._cache[type];
    delete collection[model.record.id];
  }

}
<|endoftext|>


<commit_before>import environment from 'bootenv';
import winston from 'winston';

const LOG_PROPERTY = 'LOG';
const LOG_LEVEL_PROPERTY = 'LOG_LEVEL';
const  CONFIG = {
  colors: {
    trace: 'magenta',
    input: 'grey',
    verbose: 'cyan',
    prompt: 'grey',
    debug: 'blue',
    info: 'green',
    data: 'grey',
    help: 'cyan',
    warn: 'yellow',
    error: 'red'
  },
  transports: [],
  exitOnError: false
};

if (!environment.supportsOr(LOG_PROPERTY, true)) {
  CONFIG.transports.push(
    new winston.transports.Console({
      level: environment.getPropertyOr(LOG_LEVEL_PROPERTY, 'warn')
    })
  );
} else {
  CONFIG.transports.push(
    new winston.transports.Console({
      level: environment.getPropertyOr(LOG_LEVEL_PROPERTY, 'debug'),
      handleExceptions: true,
      timestamp: true,
      stringify: false,
      json: false,
      prettyPrint: true,
      colorize: true,
      silent: false,
      humanReadableUnhandledException: true
    })
  );
}

var log = new winston.Logger(CONFIG);

winston.emitErrs = true;

log.debug('Running on [%s] environment.', environment.getName());

export default log;

<commit_msg>Fix logger issue on production env<commit_after>import environment from 'bootenv';
import winston from 'winston';

const LOG_LEVEL = 'LOG_LEVEL';
const CONFIG = {
  colors: {
    trace: 'magenta',
    input: 'grey',
    verbose: 'cyan',
    prompt: 'grey',
    debug: 'blue',
    info: 'green',
    data: 'grey',
    help: 'cyan',
    warn: 'yellow',
    error: 'red'
  },
  transports: [],
  exitOnError: false
};

var environmentName = environment.getName();
if (environmentName !== 'development') {
  CONFIG.transports.push(
    new winston.transports.Console({
      level: environment.getPropertyOr(LOG_LEVEL, 'warn')
    })
  );
} else {
  CONFIG.transports.push(
    new winston.transports.Console({
      level: environment.getPropertyOr(LOG_LEVEL, 'debug'),
      handleExceptions: true,
      timestamp: true,
      stringify: false,
      json: false,
      prettyPrint: true,
      colorize: true,
      silent: false,
      humanReadableUnhandledException: true
    })
  );
}

var log = new winston.Logger(CONFIG);

winston.emitErrs = true;

log.debug('Running on [%s] environment.', environmentName);

export default log;

<|endoftext|>


<commit_before>"use strict";

var clc = require("cli-color");
var _ = require("lodash");

var FirebaseError = require("../../error");
var gcp = require("../../gcp");
var logger = require("../../logger");
var track = require("../../track");
var utils = require("../../utils");
var helper = require("../../functionsDeployHelper");
var prompt = require("../../prompt");

var CLI_DEPLOYMENT_TOOL = "cli-firebase";
var CLI_DEPLOYMENT_LABELS = {
  "deployment-tool": CLI_DEPLOYMENT_TOOL,
};
var timings = {};
var deployments = [];
var failedDeployments = 0;

function _startTimer(name, type) {
  timings[name] = { type: type, t0: process.hrtime() };
}

function _endTimer(name) {
  if (!timings[name]) {
    logger.debug("[functions] no timer initialized for", name);
    return;
  }

  // hrtime returns a duration as an array of [seconds, nanos]
  var duration = process.hrtime(timings[name].t0);
  track(
    "Functions Deploy (Duration)",
    timings[name].type,
    duration[0] * 1000 + Math.round(duration[1] * 1e-6)
  );
}

function _fetchTriggerUrls(projectId, ops, sourceUrl) {
  if (!_.find(ops, ["trigger.httpsTrigger", {}])) {
    // No HTTPS functions being deployed
    return Promise.resolve();
  }
  return gcp.cloudfunctions.listAll(projectId).then(function(functions) {
    var httpFunctions = _.chain(functions)
      .filter({ sourceUploadUrl: sourceUrl })
      .filter("httpsTrigger")
      .value();
    _.forEach(httpFunctions, function(httpFunc) {
      _.chain(ops)
        .find({ func: httpFunc.name })
        .assign({ triggerUrl: httpFunc.httpsTrigger.url })
        .value();
    });
    return Promise.resolve();
  });
}

var printSuccess = function(op) {
  _endTimer(op.func);
  utils.logSuccess(
    clc.bold.green("functions[" + helper.getFunctionLabel(op.func) + "]: ") +
      "Successful " +
      op.type +
      " operation. "
  );
  if (op.triggerUrl && op.type !== "delete") {
    logger.info(
      clc.bold("Function URL"),
      "(" + helper.getFunctionName(op.func) + "):",
      op.triggerUrl
    );
  }
};
var printFail = function(op) {
  _endTimer(op.func);
  failedDeployments += 1;
  utils.logWarning(
    clc.bold.yellow("functions[" + helper.getFunctionLabel(op.func) + "]: ") + "Deployment error."
  );
  if (op.error.code === 8) {
    logger.debug(op.error.message);
    logger.info(
      "You have exceeded your deployment quota, please deploy your functions in batches by using the --only flag, " +
        "and wait a few minutes before deploying again. Go to " +
        clc.underline("https://firebase.google.com/docs/cli/#deploy_specific_functions") +
        " to learn more."
    );
  } else {
    logger.info(op.error.message);
  }
};

var printTooManyOps = function(projectId) {
  utils.logWarning(
    clc.bold.yellow("functions:") + " too many functions are being deployed, cannot poll status."
  );
  logger.info(
    "In a few minutes, you can check status at " + utils.consoleUrl(projectId, "/functions/logs")
  );
  logger.info(
    "You can use the --only flag to deploy only a portion of your functions in the future."
  );
  deployments = []; // prevents analytics tracking of deployments
};

module.exports = function(context, options, payload) {
  if (!options.config.has("functions")) {
    return Promise.resolve();
  }

  var projectId = context.projectId;
  var sourceUrl = context.uploadUrl;
  // Used in CLI releases v3.4.0 to v3.17.6
  var legacySourceUrlTwo =
    "gs://" + "staging." + context.firebaseConfig.storageBucket + "/firebase-functions-source";
  // Used in CLI releases v3.3.0 and prior
  var legacySourceUrlOne = "gs://" + projectId + "-gcf/" + projectId;
  var functionsInfo = helper.getFunctionsInfo(payload.functions.triggers, projectId);
  var uploadedNames = _.map(functionsInfo, "name");

  delete payload.functions;
  return gcp.cloudfunctions
    .listAll(projectId)
    .then(function(existingFunctions) {
      var pluckName = function(functionObject) {
        return _.get(functionObject, "name"); // e.g.'projects/proj1/locations/us-central1/functions/func'
      };

      var existingNames = _.map(existingFunctions, pluckName);
      var functionFilterGroups = helper.getFilterGroups(options);
      var releaseNames = helper.getReleaseNames(uploadedNames, existingNames, functionFilterGroups);
      // If not using function filters, then `deleteReleaseNames` should be equivalent to existingNames so that intersection is a noop
      var deleteReleaseNames = functionFilterGroups.length > 0 ? releaseNames : existingNames;

      helper.logFilters(existingNames, releaseNames, functionFilterGroups);

      // Create functions
      _.chain(uploadedNames)
        .difference(existingNames)
        .intersection(releaseNames)
        .forEach(function(name) {
          var functionInfo = _.find(functionsInfo, { name: name });
          var functionTrigger = helper.getFunctionTrigger(functionInfo);
          var functionName = helper.getFunctionName(name);
          var region = helper.getRegion(name);
          var runtime = context.runtimeChoice || helper.getDefaultRuntime(options);
          utils.logBullet(
            clc.bold.cyan("functions: ") +
              "creating " +
              helper.getRuntimeName(runtime) +
              " function " +
              clc.bold(helper.getFunctionLabel(name)) +
              "..."
          );
          logger.debug("Trigger is: ", JSON.stringify(functionTrigger));
          var eventType = functionTrigger.eventTrigger
            ? functionTrigger.eventTrigger.eventType
            : "https";
          _startTimer(name, "create");

          deployments.push({
            name: name,
            retryFunction: function() {
              return gcp.cloudfunctions.create({
                projectId: projectId,
                region: region,
                eventType: eventType,
                functionName: functionName,
                entryPoint: functionInfo.entryPoint,
                trigger: functionTrigger,
                labels: _.assign({}, CLI_DEPLOYMENT_LABELS, functionsInfo.labels),
                sourceUploadUrl: sourceUrl,
                runtime: runtime,
                availableMemoryMb: functionInfo.availableMemoryMb,
                timeout: functionInfo.timeout,
              });
            },
            trigger: functionTrigger,
          });
        })
        .value();

      // Update functions
      _.chain(uploadedNames)
        .intersection(existingNames)
        .intersection(releaseNames)
        .forEach(function(name) {
          var functionInfo = _.find(functionsInfo, { name: name });
          var functionTrigger = helper.getFunctionTrigger(functionInfo);
          var functionName = helper.getFunctionName(name);
          var region = helper.getRegion(name);

          var eventType = functionTrigger.eventTrigger
            ? functionTrigger.eventTrigger.eventType
            : "https";
          var existingFunction = _.find(existingFunctions, {
            name: name,
          });
          var existingEventType = _.get(existingFunction, "eventTrigger.eventType");
          var migratingTrigger = false;
          if (
            eventType.match(/google.storage.object./) &&
            existingEventType === "providers/cloud.storage/eventTypes/object.change"
          ) {
            migratingTrigger = true;
          } else if (
            eventType === "google.pubsub.topic.publish" &&
            existingEventType === "providers/cloud.pubsub/eventTypes/topic.publish"
          ) {
            migratingTrigger = true;
          }
          if (migratingTrigger) {
            throw new FirebaseError(
              "Function " +
                clc.bold(functionName) +
                " was deployed using a legacy trigger type and cannot be updated without deleting " +
                "the previous function. Follow the instructions on " +
                clc.underline(
                  "https://firebase.google.com/docs/functions/manage-functions#modify-trigger"
                ) +
                " for how to change the trigger without losing events.\n"
            );
          } else {
            var options = {
              projectId: projectId,
              region: region,
              functionName: functionName,
              trigger: functionTrigger,
              sourceUploadUrl: sourceUrl,
              labels: _.assign({}, CLI_DEPLOYMENT_LABELS, functionsInfo.labels),
              availableMemoryMb: functionInfo.availableMemoryMb,
              timeout: functionInfo.timeout,
            };
            if (context.runtimeChoice) {
              options.runtime = context.runtimeChoice;
            }
            var runtime = options.runtime || _.get(existingFunction, "runtime", "nodejs6"); // legacy functions are Node 6
            utils.logBullet(
              clc.bold.cyan("functions: ") +
                "updating " +
                helper.getRuntimeName(runtime) +
                " function " +
                clc.bold(helper.getFunctionLabel(name)) +
                "..."
            );
            logger.debug("Trigger is: ", JSON.stringify(functionTrigger));
            _startTimer(name, "update");

            deployments.push({
              name: name,
              retryFunction: function() {
                return gcp.cloudfunctions.update(options);
              },
              trigger: functionTrigger,
            });
          }
        })
        .value();

      // Delete functions
      var functionsToDelete = _.chain(existingFunctions)
        .filter(function(functionInfo) {
          if (typeof functionInfo.labels === "undefined") {
            return (
              functionInfo.sourceArchiveUrl === legacySourceUrlOne ||
              functionInfo.sourceArchiveUrl === legacySourceUrlTwo
            );
          }
          return functionInfo.labels["deployment-tool"] === CLI_DEPLOYMENT_TOOL;
        }) // only delete functions uploaded via firebase-tools
        .map(pluckName)
        .difference(uploadedNames)
        .intersection(deleteReleaseNames)
        .value();

      if (functionsToDelete.length === 0) {
        return Promise.resolve();
      }
      var deleteList = _.map(functionsToDelete, function(func) {
        return "\t" + helper.getFunctionLabel(func);
      }).join("\n");

      if (options.nonInteractive) {
        var deleteCommands = _.map(functionsToDelete, function(func) {
          return (
            "\tfirebase functions:delete " +
            helper.getFunctionName(func) +
            " --region " +
            helper.getRegion(func)
          );
        }).join("\n");

        throw new FirebaseError(
          "The following functions are found in your project but do not exist in your local source code:\n" +
            deleteList +
            "\n\nAborting because deletion cannot proceed in non-interactive mode. To fix, manually delete the functions by running:\n" +
            clc.bold(deleteCommands)
        );
      }

      logger.info(
        "\nThe following functions are found in your project but do not exist in your local source code:\n" +
          deleteList +
          "\n\nIf you are renaming a function or changing its region, it is recommended that you create the new " +
          "function first before deleting the old one to prevent event loss. For more info, visit " +
          clc.underline("https://firebase.google.com/docs/functions/manage-functions#modify" + "\n")
      );

      return prompt
        .once({
          type: "confirm",
          name: "confirm",
          default: false,
          message:
            "Would you like to proceed with deletion? Selecting no will continue the rest of the deployments.",
        })
        .then(function(proceed) {
          if (!proceed) {
            if (deployments.length !== 0) {
              utils.logBullet(clc.bold.cyan("functions: ") + "continuing with other deployments.");
            }
            return;
          }
          functionsToDelete.forEach(function(name) {
            var functionName = helper.getFunctionName(name);
            var region = helper.getRegion(name);

            utils.logBullet(
              clc.bold.cyan("functions: ") +
                "deleting function " +
                clc.bold(helper.getFunctionLabel(name)) +
                "..."
            );
            _startTimer(name, "delete");
            deployments.push({
              name: name,
              retryFunction: function() {
                return gcp.cloudfunctions.delete({
                  projectId: projectId,
                  region: region,
                  functionName: functionName,
                });
              },
            });
          });
        });
    })
    .then(function() {
      return utils.promiseAllSettled(
        _.map(deployments, function(op) {
          return op.retryFunction().then(function(res) {
            return _.merge(op, res);
          });
        })
      );
    })
    .then(function(allOps) {
      var failedCalls = _.chain(allOps)
        .filter({ state: "rejected" })
        .map("reason")
        .value();
      var successfulCalls = _.chain(allOps)
        .filter({ state: "fulfilled" })
        .map("value")
        .value();
      failedDeployments += failedCalls.length;

      return _fetchTriggerUrls(projectId, successfulCalls, sourceUrl)
        .then(function() {
          return helper.pollDeploys(
            successfulCalls,
            printSuccess,
            printFail,
            printTooManyOps,
            projectId
          );
        })
        .then(function() {
          if (deployments.length > 0) {
            track("Functions Deploy (Result)", "failure", failedDeployments);
            track("Functions Deploy (Result)", "success", deployments.length - failedDeployments);
          }

          if (failedDeployments > 0) {
            logger.info(
              "\n\nFunctions deploy had errors. To continue deploying other features (such as database), run:"
            );
            logger.info("    " + clc.bold("firebase deploy --except functions"));
            return Promise.reject(new FirebaseError("Functions did not deploy properly."));
          }
        });
    });
};
<commit_msg>fix typo for querying labels (#916)<commit_after>"use strict";

var clc = require("cli-color");
var _ = require("lodash");

var FirebaseError = require("../../error");
var gcp = require("../../gcp");
var logger = require("../../logger");
var track = require("../../track");
var utils = require("../../utils");
var helper = require("../../functionsDeployHelper");
var prompt = require("../../prompt");

var CLI_DEPLOYMENT_TOOL = "cli-firebase";
var CLI_DEPLOYMENT_LABELS = {
  "deployment-tool": CLI_DEPLOYMENT_TOOL,
};
var timings = {};
var deployments = [];
var failedDeployments = 0;

function _startTimer(name, type) {
  timings[name] = { type: type, t0: process.hrtime() };
}

function _endTimer(name) {
  if (!timings[name]) {
    logger.debug("[functions] no timer initialized for", name);
    return;
  }

  // hrtime returns a duration as an array of [seconds, nanos]
  var duration = process.hrtime(timings[name].t0);
  track(
    "Functions Deploy (Duration)",
    timings[name].type,
    duration[0] * 1000 + Math.round(duration[1] * 1e-6)
  );
}

function _fetchTriggerUrls(projectId, ops, sourceUrl) {
  if (!_.find(ops, ["trigger.httpsTrigger", {}])) {
    // No HTTPS functions being deployed
    return Promise.resolve();
  }
  return gcp.cloudfunctions.listAll(projectId).then(function(functions) {
    var httpFunctions = _.chain(functions)
      .filter({ sourceUploadUrl: sourceUrl })
      .filter("httpsTrigger")
      .value();
    _.forEach(httpFunctions, function(httpFunc) {
      _.chain(ops)
        .find({ func: httpFunc.name })
        .assign({ triggerUrl: httpFunc.httpsTrigger.url })
        .value();
    });
    return Promise.resolve();
  });
}

var printSuccess = function(op) {
  _endTimer(op.func);
  utils.logSuccess(
    clc.bold.green("functions[" + helper.getFunctionLabel(op.func) + "]: ") +
      "Successful " +
      op.type +
      " operation. "
  );
  if (op.triggerUrl && op.type !== "delete") {
    logger.info(
      clc.bold("Function URL"),
      "(" + helper.getFunctionName(op.func) + "):",
      op.triggerUrl
    );
  }
};
var printFail = function(op) {
  _endTimer(op.func);
  failedDeployments += 1;
  utils.logWarning(
    clc.bold.yellow("functions[" + helper.getFunctionLabel(op.func) + "]: ") + "Deployment error."
  );
  if (op.error.code === 8) {
    logger.debug(op.error.message);
    logger.info(
      "You have exceeded your deployment quota, please deploy your functions in batches by using the --only flag, " +
        "and wait a few minutes before deploying again. Go to " +
        clc.underline("https://firebase.google.com/docs/cli/#deploy_specific_functions") +
        " to learn more."
    );
  } else {
    logger.info(op.error.message);
  }
};

var printTooManyOps = function(projectId) {
  utils.logWarning(
    clc.bold.yellow("functions:") + " too many functions are being deployed, cannot poll status."
  );
  logger.info(
    "In a few minutes, you can check status at " + utils.consoleUrl(projectId, "/functions/logs")
  );
  logger.info(
    "You can use the --only flag to deploy only a portion of your functions in the future."
  );
  deployments = []; // prevents analytics tracking of deployments
};

module.exports = function(context, options, payload) {
  if (!options.config.has("functions")) {
    return Promise.resolve();
  }

  var projectId = context.projectId;
  var sourceUrl = context.uploadUrl;
  // Used in CLI releases v3.4.0 to v3.17.6
  var legacySourceUrlTwo =
    "gs://" + "staging." + context.firebaseConfig.storageBucket + "/firebase-functions-source";
  // Used in CLI releases v3.3.0 and prior
  var legacySourceUrlOne = "gs://" + projectId + "-gcf/" + projectId;
  var functionsInfo = helper.getFunctionsInfo(payload.functions.triggers, projectId);
  var uploadedNames = _.map(functionsInfo, "name");

  delete payload.functions;
  return gcp.cloudfunctions
    .listAll(projectId)
    .then(function(existingFunctions) {
      var pluckName = function(functionObject) {
        return _.get(functionObject, "name"); // e.g.'projects/proj1/locations/us-central1/functions/func'
      };

      var existingNames = _.map(existingFunctions, pluckName);
      var functionFilterGroups = helper.getFilterGroups(options);
      var releaseNames = helper.getReleaseNames(uploadedNames, existingNames, functionFilterGroups);
      // If not using function filters, then `deleteReleaseNames` should be equivalent to existingNames so that intersection is a noop
      var deleteReleaseNames = functionFilterGroups.length > 0 ? releaseNames : existingNames;

      helper.logFilters(existingNames, releaseNames, functionFilterGroups);

      // Create functions
      _.chain(uploadedNames)
        .difference(existingNames)
        .intersection(releaseNames)
        .forEach(function(name) {
          var functionInfo = _.find(functionsInfo, { name: name });
          var functionTrigger = helper.getFunctionTrigger(functionInfo);
          var functionName = helper.getFunctionName(name);
          var region = helper.getRegion(name);
          var runtime = context.runtimeChoice || helper.getDefaultRuntime(options);
          utils.logBullet(
            clc.bold.cyan("functions: ") +
              "creating " +
              helper.getRuntimeName(runtime) +
              " function " +
              clc.bold(helper.getFunctionLabel(name)) +
              "..."
          );
          logger.debug("Trigger is: ", JSON.stringify(functionTrigger));
          var eventType = functionTrigger.eventTrigger
            ? functionTrigger.eventTrigger.eventType
            : "https";
          _startTimer(name, "create");

          deployments.push({
            name: name,
            retryFunction: function() {
              return gcp.cloudfunctions.create({
                projectId: projectId,
                region: region,
                eventType: eventType,
                functionName: functionName,
                entryPoint: functionInfo.entryPoint,
                trigger: functionTrigger,
                labels: _.assign({}, CLI_DEPLOYMENT_LABELS, functionInfo.labels),
                sourceUploadUrl: sourceUrl,
                runtime: runtime,
                availableMemoryMb: functionInfo.availableMemoryMb,
                timeout: functionInfo.timeout,
              });
            },
            trigger: functionTrigger,
          });
        })
        .value();

      // Update functions
      _.chain(uploadedNames)
        .intersection(existingNames)
        .intersection(releaseNames)
        .forEach(function(name) {
          var functionInfo = _.find(functionsInfo, { name: name });
          var functionTrigger = helper.getFunctionTrigger(functionInfo);
          var functionName = helper.getFunctionName(name);
          var region = helper.getRegion(name);

          var eventType = functionTrigger.eventTrigger
            ? functionTrigger.eventTrigger.eventType
            : "https";
          var existingFunction = _.find(existingFunctions, {
            name: name,
          });
          var existingEventType = _.get(existingFunction, "eventTrigger.eventType");
          var migratingTrigger = false;
          if (
            eventType.match(/google.storage.object./) &&
            existingEventType === "providers/cloud.storage/eventTypes/object.change"
          ) {
            migratingTrigger = true;
          } else if (
            eventType === "google.pubsub.topic.publish" &&
            existingEventType === "providers/cloud.pubsub/eventTypes/topic.publish"
          ) {
            migratingTrigger = true;
          }
          if (migratingTrigger) {
            throw new FirebaseError(
              "Function " +
                clc.bold(functionName) +
                " was deployed using a legacy trigger type and cannot be updated without deleting " +
                "the previous function. Follow the instructions on " +
                clc.underline(
                  "https://firebase.google.com/docs/functions/manage-functions#modify-trigger"
                ) +
                " for how to change the trigger without losing events.\n"
            );
          } else {
            var options = {
              projectId: projectId,
              region: region,
              functionName: functionName,
              trigger: functionTrigger,
              sourceUploadUrl: sourceUrl,
              labels: _.assign({}, CLI_DEPLOYMENT_LABELS, functionInfo.labels),
              availableMemoryMb: functionInfo.availableMemoryMb,
              timeout: functionInfo.timeout,
            };
            if (context.runtimeChoice) {
              options.runtime = context.runtimeChoice;
            }
            var runtime = options.runtime || _.get(existingFunction, "runtime", "nodejs6"); // legacy functions are Node 6
            utils.logBullet(
              clc.bold.cyan("functions: ") +
                "updating " +
                helper.getRuntimeName(runtime) +
                " function " +
                clc.bold(helper.getFunctionLabel(name)) +
                "..."
            );
            logger.debug("Trigger is: ", JSON.stringify(functionTrigger));
            _startTimer(name, "update");

            deployments.push({
              name: name,
              retryFunction: function() {
                return gcp.cloudfunctions.update(options);
              },
              trigger: functionTrigger,
            });
          }
        })
        .value();

      // Delete functions
      var functionsToDelete = _.chain(existingFunctions)
        .filter(function(functionInfo) {
          if (typeof functionInfo.labels === "undefined") {
            return (
              functionInfo.sourceArchiveUrl === legacySourceUrlOne ||
              functionInfo.sourceArchiveUrl === legacySourceUrlTwo
            );
          }
          return functionInfo.labels["deployment-tool"] === CLI_DEPLOYMENT_TOOL;
        }) // only delete functions uploaded via firebase-tools
        .map(pluckName)
        .difference(uploadedNames)
        .intersection(deleteReleaseNames)
        .value();

      if (functionsToDelete.length === 0) {
        return Promise.resolve();
      }
      var deleteList = _.map(functionsToDelete, function(func) {
        return "\t" + helper.getFunctionLabel(func);
      }).join("\n");

      if (options.nonInteractive) {
        var deleteCommands = _.map(functionsToDelete, function(func) {
          return (
            "\tfirebase functions:delete " +
            helper.getFunctionName(func) +
            " --region " +
            helper.getRegion(func)
          );
        }).join("\n");

        throw new FirebaseError(
          "The following functions are found in your project but do not exist in your local source code:\n" +
            deleteList +
            "\n\nAborting because deletion cannot proceed in non-interactive mode. To fix, manually delete the functions by running:\n" +
            clc.bold(deleteCommands)
        );
      }

      logger.info(
        "\nThe following functions are found in your project but do not exist in your local source code:\n" +
          deleteList +
          "\n\nIf you are renaming a function or changing its region, it is recommended that you create the new " +
          "function first before deleting the old one to prevent event loss. For more info, visit " +
          clc.underline("https://firebase.google.com/docs/functions/manage-functions#modify" + "\n")
      );

      return prompt
        .once({
          type: "confirm",
          name: "confirm",
          default: false,
          message:
            "Would you like to proceed with deletion? Selecting no will continue the rest of the deployments.",
        })
        .then(function(proceed) {
          if (!proceed) {
            if (deployments.length !== 0) {
              utils.logBullet(clc.bold.cyan("functions: ") + "continuing with other deployments.");
            }
            return;
          }
          functionsToDelete.forEach(function(name) {
            var functionName = helper.getFunctionName(name);
            var region = helper.getRegion(name);

            utils.logBullet(
              clc.bold.cyan("functions: ") +
                "deleting function " +
                clc.bold(helper.getFunctionLabel(name)) +
                "..."
            );
            _startTimer(name, "delete");
            deployments.push({
              name: name,
              retryFunction: function() {
                return gcp.cloudfunctions.delete({
                  projectId: projectId,
                  region: region,
                  functionName: functionName,
                });
              },
            });
          });
        });
    })
    .then(function() {
      return utils.promiseAllSettled(
        _.map(deployments, function(op) {
          return op.retryFunction().then(function(res) {
            return _.merge(op, res);
          });
        })
      );
    })
    .then(function(allOps) {
      var failedCalls = _.chain(allOps)
        .filter({ state: "rejected" })
        .map("reason")
        .value();
      var successfulCalls = _.chain(allOps)
        .filter({ state: "fulfilled" })
        .map("value")
        .value();
      failedDeployments += failedCalls.length;

      return _fetchTriggerUrls(projectId, successfulCalls, sourceUrl)
        .then(function() {
          return helper.pollDeploys(
            successfulCalls,
            printSuccess,
            printFail,
            printTooManyOps,
            projectId
          );
        })
        .then(function() {
          if (deployments.length > 0) {
            track("Functions Deploy (Result)", "failure", failedDeployments);
            track("Functions Deploy (Result)", "success", deployments.length - failedDeployments);
          }

          if (failedDeployments > 0) {
            logger.info(
              "\n\nFunctions deploy had errors. To continue deploying other features (such as database), run:"
            );
            logger.info("    " + clc.bold("firebase deploy --except functions"));
            return Promise.reject(new FirebaseError("Functions did not deploy properly."));
          }
        });
    });
};
<|endoftext|>


<commit_before>import _ from 'lodash';
import { Observable } from 'rx';
import { Actions } from 'thundercats';
import debugFactory from 'debug';

const debug = debugFactory('freecc:hikes:actions');
const noOp = { transform: () => {} };

function getCurrentHike(hikes = [{}], dashedName, currentHike) {
  if (!dashedName) {
    debug('no dashedName');
    return hikes[0];
  }

  const filterRegex = new RegExp(dashedName, 'i');
  if (currentHike && filterRegex.test(currentHike.dashedName)) {
    return currentHike;
  }

  debug('setting new hike');
  return hikes
    .filter(({ dashedName }) => {
      return filterRegex.test(dashedName);
    })
    .reduce((throwAway, hike) => {
      return hike;
    }, currentHike || {});
}

function findNextHike(hikes, id) {
  if (!id) {
    debug('find next hike no id provided');
    return hikes[0];
  }
  const currentIndex = _.findIndex(hikes, ({ id: _id }) => _id === id);
  return hikes[currentIndex + 1] || hikes[0];
}

function getMouse(e, [dx, dy]) {
  let { pageX, pageY, touches } = e;

  if (touches) {
    e.preventDefault();
    // these re-assigns the values of pageX, pageY from touches
    ({ pageX, pageY } = touches[0]);
  }

  return [pageX - dx, pageY - dy];
}

export default Actions({
  refs: { displayName: 'HikesActions' },
  shouldBindMethods: true,
  fetchHikes({ isPrimed, dashedName }) {
    if (isPrimed) {
      return {
        transform: (state) => {

          const { hikesApp: oldState } = state;
          const currentHike = getCurrentHike(
            oldState.hikes,
            dashedName,
            oldState.currentHike
          );

          const hikesApp = { ...oldState, currentHike };
          return Object.assign({}, state, { hikesApp });
        }
      };
    }

    return this.readService$('hikes', null, null)
      .map(hikes => {
        const currentHike = getCurrentHike(hikes, dashedName);
        return {
          transform(state) {
            const hikesApp = { ...state.hikesApp, currentHike, hikes };
            return { ...state, hikesApp };
          }
        };
      })
      .catch(err => Observable.just({
        transform(state) { return { ...state, err }; }
      }));
  },

  toggleQuestions() {
    return {
      transform(state) {
        const hikesApp = {
          ...state.hikesApp,
          showQuestions: !state.hikesApp.showQuestions,
          currentQuestion: 1
        };
        return { ...state, hikesApp };
      }
    };
  },

  hideInfo() {
    return {
      transform(state) {
        const hikesApp = { ...state.hikesApp, showInfo: false };
        return { ...state, hikesApp };
      }
    };
  },

  grabQuestion(e) {
    const { pageX, pageY } = e;
    const delta = [pageX, pageY];
    const mouse = getMouse(e, delta);

    return {
      transform(state) {
        return {
          ...state,
          hikesApp: {
            ...state.hikesApp,
            isPressed: true,
            delta,
            mouse
          }
        };
      }
    };
  },

  releaseQuestion() {
    return {
      transform(state) {
        return {
          ...state,
          hikesApp: {
            ...state.hikesApp,
            isPressed: false,
            mouse: [0, 0]
          }
        };
      }
    };
  },

  moveQuestion({ e, delta }) {
    const mouse = getMouse(e, delta);

    return {
      transform(state) {
        return {
          ...state,
          hikesApp: {
            ...state.hikesApp,
            mouse
          }
        };
      }
    };
  },

  answer({
    e,
    answer,
    userAnswer,
    hike: { id, name, tests, challengeType },
    currentQuestion,
    isSignedIn,
    delta,
    threshold
  }) {
    if (typeof userAnswer === 'undefined') {
      const [positionX] = getMouse(e, delta);

      // question released under threshold
      if (Math.abs(positionX) < threshold) {
        return noOp;
      }

      if (positionX >= threshold) {
        userAnswer = true;
      }

      if (positionX <= -threshold) {
        userAnswer = false;
      }
    }

    // incorrect question
    if (answer !== userAnswer) {
      const startShake = {
        transform(state) {
          return {
            ...state,
            hikesApp: {
              ...state.hikesApp,
              showInfo: true,
              shake: true
            }
          };
        }
      };

      const removeShake = {
        transform(state) {
          return {
            ...state,
            hikesApp: {
              ...state.hikesApp,
              shake: false
            }
          };
        }
      };

      return Observable
        .just(removeShake)
        .delay(500)
        .startWith(startShake);
    }

    // move to next question
    // index 0
    if (tests[currentQuestion]) {

      return Observable.just({
        transform(state) {
          const hikesApp = {
            ...state.hikesApp,
            mouse: [0, 0],
            showInfo: false
          };
          return { ...state, hikesApp };
        }
      })
        .delay(300)
        .startWith({
          transform(state) {

            const hikesApp = {
              ...state.hikesApp,
              currentQuestion: currentQuestion + 1,
              mouse: [ userAnswer ? 1000 : -1000, 0],
              isPressed: false
            };

            return { ...state, hikesApp };
          }
        });
    }

    // challenge completed
    const optimisticSave = isSignedIn ?
      this.post$('/completed-challenge', { id, name, challengeType }) :
      Observable.just(true);

    const correctAnswer = {
      transform(state) {
        return {
          ...state,
          hikesApp: {
            ...state.hikesApp,
            isCorrect: true,
            isPressed: false,
            delta: [0, 0],
            mouse: [ userAnswer ? 1000 : -1000, 0]
          }
        };
      }
    };

    return Observable.just({
        transform(state) {
          const { hikes, currentHike: { id } } = state.hikesApp;
          const currentHike = findNextHike(hikes, id);

          return {
            ...state,
            points: isSignedIn ? state.points + 1 : state.points,
            hikesApp: {
              ...state.hikesApp,
              currentHike,
              showQuestions: false,
              currentQuestion: 1,
              mouse: [0, 0]
            },
            toast: {
              title: 'Congratulations!',
              message: 'Hike completed',
              id: state.toast && typeof state.toast.id === 'number' ?
                state.toast.id + 1 :
                0,
              type: 'success'
            },
            location: {
              action: 'PUSH',
              pathname: currentHike && currentHike.dashedName ?
                `/hikes/${ currentHike.dashedName }` :
                '/hikes'
            }
          };
        },
        optimistic: optimisticSave
      })
      .delay(300)
      .startWith(correctAnswer)
      .catch(err => Observable.just({
        transform(state) { return { ...state, err }; }
      }));
  },
  resetHike() {
    return {
      transform(state) {
        return { ...state,
          hikesApp: {
            ...state.hikesApp,
            currentQuestion: 1,
            showQuestions: false,
            showInfo: false,
            mouse: [0, 0],
            delta: [0, 0]
          }
        };
      }
    };
  }
});
<commit_msg>Fix grabQuestion on mobile<commit_after>import _ from 'lodash';
import { Observable } from 'rx';
import { Actions } from 'thundercats';
import debugFactory from 'debug';

const debug = debugFactory('freecc:hikes:actions');
const noOp = { transform: () => {} };

function getCurrentHike(hikes = [{}], dashedName, currentHike) {
  if (!dashedName) {
    debug('no dashedName');
    return hikes[0];
  }

  const filterRegex = new RegExp(dashedName, 'i');
  if (currentHike && filterRegex.test(currentHike.dashedName)) {
    return currentHike;
  }

  debug('setting new hike');
  return hikes
    .filter(({ dashedName }) => {
      return filterRegex.test(dashedName);
    })
    .reduce((throwAway, hike) => {
      return hike;
    }, currentHike || {});
}

function findNextHike(hikes, id) {
  if (!id) {
    debug('find next hike no id provided');
    return hikes[0];
  }
  const currentIndex = _.findIndex(hikes, ({ id: _id }) => _id === id);
  return hikes[currentIndex + 1] || hikes[0];
}

function getMouse(e, [dx, dy]) {
  let { pageX, pageY, touches } = e;

  if (touches) {
    e.preventDefault();
    // these re-assigns the values of pageX, pageY from touches
    ({ pageX, pageY } = touches[0]);
  }

  return [pageX - dx, pageY - dy];
}

export default Actions({
  refs: { displayName: 'HikesActions' },
  shouldBindMethods: true,
  fetchHikes({ isPrimed, dashedName }) {
    if (isPrimed) {
      return {
        transform: (state) => {

          const { hikesApp: oldState } = state;
          const currentHike = getCurrentHike(
            oldState.hikes,
            dashedName,
            oldState.currentHike
          );

          const hikesApp = { ...oldState, currentHike };
          return Object.assign({}, state, { hikesApp });
        }
      };
    }

    return this.readService$('hikes', null, null)
      .map(hikes => {
        const currentHike = getCurrentHike(hikes, dashedName);
        return {
          transform(state) {
            const hikesApp = { ...state.hikesApp, currentHike, hikes };
            return { ...state, hikesApp };
          }
        };
      })
      .catch(err => Observable.just({
        transform(state) { return { ...state, err }; }
      }));
  },

  toggleQuestions() {
    return {
      transform(state) {
        const hikesApp = {
          ...state.hikesApp,
          showQuestions: !state.hikesApp.showQuestions,
          currentQuestion: 1
        };
        return { ...state, hikesApp };
      }
    };
  },

  hideInfo() {
    return {
      transform(state) {
        const hikesApp = { ...state.hikesApp, showInfo: false };
        return { ...state, hikesApp };
      }
    };
  },

  grabQuestion(e) {
    let { pageX, pageY, touches } = e;
    if (touches) {
      e.preventDefault();
      // these re-assigns the values of pageX, pageY from touches
      ({ pageX, pageY } = touches[0]);
    }
    const delta = [pageX, pageY];
    const mouse = [0, 0];

    return {
      transform(state) {
        return {
          ...state,
          hikesApp: {
            ...state.hikesApp,
            isPressed: true,
            delta,
            mouse
          }
        };
      }
    };
  },

  releaseQuestion() {
    return {
      transform(state) {
        return {
          ...state,
          hikesApp: {
            ...state.hikesApp,
            isPressed: false,
            mouse: [0, 0]
          }
        };
      }
    };
  },

  moveQuestion({ e, delta }) {
    const mouse = getMouse(e, delta);

    return {
      transform(state) {
        return {
          ...state,
          hikesApp: {
            ...state.hikesApp,
            mouse
          }
        };
      }
    };
  },

  answer({
    e,
    answer,
    userAnswer,
    hike: { id, name, tests, challengeType },
    currentQuestion,
    isSignedIn,
    delta,
    threshold
  }) {
    if (typeof userAnswer === 'undefined') {
      const [positionX] = getMouse(e, delta);

      // question released under threshold
      if (Math.abs(positionX) < threshold) {
        return noOp;
      }

      if (positionX >= threshold) {
        userAnswer = true;
      }

      if (positionX <= -threshold) {
        userAnswer = false;
      }
    }

    // incorrect question
    if (answer !== userAnswer) {
      const startShake = {
        transform(state) {
          return {
            ...state,
            hikesApp: {
              ...state.hikesApp,
              showInfo: true,
              shake: true
            }
          };
        }
      };

      const removeShake = {
        transform(state) {
          return {
            ...state,
            hikesApp: {
              ...state.hikesApp,
              shake: false
            }
          };
        }
      };

      return Observable
        .just(removeShake)
        .delay(500)
        .startWith(startShake);
    }

    // move to next question
    // index 0
    if (tests[currentQuestion]) {

      return Observable.just({
        transform(state) {
          const hikesApp = {
            ...state.hikesApp,
            mouse: [0, 0],
            showInfo: false
          };
          return { ...state, hikesApp };
        }
      })
        .delay(300)
        .startWith({
          transform(state) {

            const hikesApp = {
              ...state.hikesApp,
              currentQuestion: currentQuestion + 1,
              mouse: [ userAnswer ? 1000 : -1000, 0],
              isPressed: false
            };

            return { ...state, hikesApp };
          }
        });
    }

    // challenge completed
    const optimisticSave = isSignedIn ?
      this.post$('/completed-challenge', { id, name, challengeType }) :
      Observable.just(true);

    const correctAnswer = {
      transform(state) {
        return {
          ...state,
          hikesApp: {
            ...state.hikesApp,
            isCorrect: true,
            isPressed: false,
            delta: [0, 0],
            mouse: [ userAnswer ? 1000 : -1000, 0]
          }
        };
      }
    };

    return Observable.just({
        transform(state) {
          const { hikes, currentHike: { id } } = state.hikesApp;
          const currentHike = findNextHike(hikes, id);

          return {
            ...state,
            points: isSignedIn ? state.points + 1 : state.points,
            hikesApp: {
              ...state.hikesApp,
              currentHike,
              showQuestions: false,
              currentQuestion: 1,
              mouse: [0, 0]
            },
            toast: {
              title: 'Congratulations!',
              message: 'Hike completed',
              id: state.toast && typeof state.toast.id === 'number' ?
                state.toast.id + 1 :
                0,
              type: 'success'
            },
            location: {
              action: 'PUSH',
              pathname: currentHike && currentHike.dashedName ?
                `/hikes/${ currentHike.dashedName }` :
                '/hikes'
            }
          };
        },
        optimistic: optimisticSave
      })
      .delay(300)
      .startWith(correctAnswer)
      .catch(err => Observable.just({
        transform(state) { return { ...state, err }; }
      }));
  },
  resetHike() {
    return {
      transform(state) {
        return { ...state,
          hikesApp: {
            ...state.hikesApp,
            currentQuestion: 1,
            showQuestions: false,
            showInfo: false,
            mouse: [0, 0],
            delta: [0, 0]
          }
        };
      }
    };
  }
});
<|endoftext|>