<commit_before>var _ = require('underscore');
var Q = require('q');

module.exports = function (crudStrategies, storageDriver, entityDescriptionService, injection, appUtil, securityService) {
    var service = {};

    service.strategyForCrudId = function (crudId) {
        if (_.isString(crudId)) {
            crudId = entityDescriptionService.entityTypeIdCrudId(crudId);
        }
        return _.map(crudStrategies, function (strategy) {
            return securityWrapper(crudId, strategy.crudHandlerFor(crudId));
        })[0];
    };

    service.systemStrategyForCrudId = function (crudId) {
        return systemCrudWrapper(service.strategyForCrudId(crudId));
    };

    service.setupModels = function () {
        _.forEach(entityDescriptionService.entityDescriptions, function (description) {
            storageDriver.setupModel(description.tableDescription);
        })
    };

    service.compile = function () {
        this.setupModels();
    };

    service.referenceValueByEntityId = function (crudId, entityId) { //TODO doubling
        var referenceFieldName = entityDescriptionService.entityDescription(crudId).referenceNameExpression;
        return service.strategyForCrudId(crudId).readEntity(entityId).then(function (e) {
            return {id: e.id, name: e[referenceFieldName]};
        });
    };

    service.resolveReferenceValues = function (crudId, entity) {
        return Q.all(entityDescriptionService.entityDescription(crudId).fields.map(function (field) {
            if (field.fieldType.id === 'reference' && entity.hasOwnProperty(field.field) && entity[field.field].id) {
                return service.referenceValueByEntityId(
                    entityDescriptionService.entityTypeIdCrudId(field.fieldType.referenceEntityTypeId),
                    entity[field.field].id
                ).then(function (referenceValue) {
                        entity[field.field] = referenceValue;
                    });
            } else if (field.fieldType.id === 'multiReference' && entity.hasOwnProperty(field.field)) {
                return Q.all(entity[field.field].map(function (entry) {
                    return service.referenceValueByEntityId(
                        entityDescriptionService.entityTypeIdCrudId(field.fieldType.referenceEntityTypeId),
                        entry.id
                    )
                })).then(function (referenceValue) {
                    entity[field.field] = referenceValue;
                });
            }
            return undefined;
        }));
    };

    function securityWrapper(crudId, crudStrategy) {
        var result = {};
        wrap(function () {
            var next = this;
            checkPermission('Read', 'userHasReadAccess');
            return next();
        }, ['findAll', 'findCount', 'getTotalRow', 'findRange', 'readEntity'], result, crudStrategy);
        wrap(function () {
            var next = this;
            checkPermission('Create', 'userHasCreateAccess');
            return next();
        }, ['createEntity'], result, crudStrategy);
        wrap(function () {
            var next = this;
            checkPermission('Update', 'userHasUpdateAccess');
            return next();
        }, ['updateEntity'], result, crudStrategy);
        wrap(function () {
            var next = this;
            checkPermission('Delete', 'userHasDeleteAccess');
            return next();
        }, ['deleteEntity'], result, crudStrategy);

        wrap(function () {
            var next = this;
            var filteredFields = entityDescriptionService.readPermissionFilteredFields(crudId, injection.inject('User', true));
            return next().then(function (items) {
                return filterItems(items, filteredFields);
            });
        }, ['findAll', 'findRange'], result);

        wrap(function () {
            var next = this;
            var filteredFields = entityDescriptionService.readPermissionFilteredFields(crudId, injection.inject('User', true));
            return next().then(function (item) {
                return item && filterFields(item, filteredFields);
            });
        }, ['getTotalRow', 'readEntity'], result);

        wrap(function (item) {
            var next = this;
            var filteredFields = entityDescriptionService.writePermissionFilteredFields(crudId, injection.inject('User', true));
            filterFields(item, filteredFields);
            return next();
        }, ['createEntity', 'updateEntity'], result);

        return result;

        function filterItems(items, filteredFields) {
            _.forEach(items, function (item) {
                filterFields(item, filteredFields);
            });
            return items;
        }

        function filterFields(item, filteredFields) {
            _.forEach(item, function (value, fieldName) {
                if (!filteredFields[fieldName] && fieldName !== 'id') { //TODO is id really special here?
                    delete item[fieldName];
                }
            });
            return item;
        }

        function checkPermission(permissionName, permissionCheckMethod) {
            var user = injection.inject('User', true);
            if (!entityDescriptionService[permissionCheckMethod](crudId, user)) {
                throw new appUtil.ForbiddenError(permissionName + ' permission to ' + JSON.stringify(crudId) + ' denied for ' + (user ? '"' + user.username + '"' : 'unauthorized user'));
            }
        }
    }

    function systemCrudWrapper(crudStrategy) {
        var result = {};
        wrap(function () {
            var next = this;
            return securityService.asSystemUser(next);
        }, ['findAll', 'findCount', 'getTotalRow', 'findRange', 'readEntity', 'createEntity', 'updateEntity', 'deleteEntity'], result, crudStrategy);
        return result;
    }

    function wrap(proxyFn, methodsToWrap, obj, target) {
        target = target || obj;
        _.forEach(methodsToWrap, function (methodName) {
            var targetFn = target[methodName];
            obj[methodName] = function () {
                var args = arguments;
                return proxyFn.apply(function () {
                    return targetFn.apply(target, args);
                }, args);
            }
        });
    }

    return service;
};<commit_msg>Don't resolve already persisted references<commit_after>var _ = require('underscore');
var Q = require('q');

module.exports = function (crudStrategies, storageDriver, entityDescriptionService, injection, appUtil, securityService) {
    var service = {};

    service.strategyForCrudId = function (crudId) {
        if (_.isString(crudId)) {
            crudId = entityDescriptionService.entityTypeIdCrudId(crudId);
        }
        return _.map(crudStrategies, function (strategy) {
            return securityWrapper(crudId, strategy.crudHandlerFor(crudId));
        })[0];
    };

    service.systemStrategyForCrudId = function (crudId) {
        return systemCrudWrapper(service.strategyForCrudId(crudId));
    };

    service.setupModels = function () {
        _.forEach(entityDescriptionService.entityDescriptions, function (description) {
            storageDriver.setupModel(description.tableDescription);
        })
    };

    service.compile = function () {
        this.setupModels();
    };

    service.referenceValueByEntityId = function (crudId, entityId) { //TODO doubling
        var referenceFieldName = entityDescriptionService.entityDescription(crudId).referenceNameExpression;
        return service.strategyForCrudId(crudId).readEntity(entityId).then(function (e) {
            return {id: e.id, name: e[referenceFieldName]};
        });
    };

    service.resolveReferenceValues = function (crudId, entity) {
        return Q.all(entityDescriptionService.entityDescription(crudId).fields.map(function (field) {
            if (field.fieldType.id === 'reference' && entity.hasOwnProperty(field.field) && entity[field.field] && entity[field.field].id) {
                return service.referenceValueByEntityId(
                    entityDescriptionService.entityTypeIdCrudId(field.fieldType.referenceEntityTypeId),
                    entity[field.field].id
                ).then(function (referenceValue) {
                        entity[field.field] = referenceValue;
                    });
            } else if (field.fieldType.id === 'multiReference' && entity.hasOwnProperty(field.field) && entity[field.field]) {
                return Q.all(entity[field.field].map(function (entry) {
                    return service.referenceValueByEntityId(
                        entityDescriptionService.entityTypeIdCrudId(field.fieldType.referenceEntityTypeId),
                        entry.id
                    )
                })).then(function (referenceValue) {
                    entity[field.field] = referenceValue;
                });
            }
            return undefined;
        }));
    };

    function securityWrapper(crudId, crudStrategy) {
        var result = {};
        wrap(function () {
            var next = this;
            checkPermission('Read', 'userHasReadAccess');
            return next();
        }, ['findAll', 'findCount', 'getTotalRow', 'findRange', 'readEntity'], result, crudStrategy);
        wrap(function () {
            var next = this;
            checkPermission('Create', 'userHasCreateAccess');
            return next();
        }, ['createEntity'], result, crudStrategy);
        wrap(function () {
            var next = this;
            checkPermission('Update', 'userHasUpdateAccess');
            return next();
        }, ['updateEntity'], result, crudStrategy);
        wrap(function () {
            var next = this;
            checkPermission('Delete', 'userHasDeleteAccess');
            return next();
        }, ['deleteEntity'], result, crudStrategy);

        wrap(function () {
            var next = this;
            var filteredFields = entityDescriptionService.readPermissionFilteredFields(crudId, injection.inject('User', true));
            return next().then(function (items) {
                return filterItems(items, filteredFields);
            });
        }, ['findAll', 'findRange'], result);

        wrap(function () {
            var next = this;
            var filteredFields = entityDescriptionService.readPermissionFilteredFields(crudId, injection.inject('User', true));
            return next().then(function (item) {
                return item && filterFields(item, filteredFields);
            });
        }, ['getTotalRow', 'readEntity'], result);

        wrap(function (item) {
            var next = this;
            var filteredFields = entityDescriptionService.writePermissionFilteredFields(crudId, injection.inject('User', true));
            filterFields(item, filteredFields);
            return next();
        }, ['createEntity', 'updateEntity'], result);

        return result;

        function filterItems(items, filteredFields) {
            _.forEach(items, function (item) {
                filterFields(item, filteredFields);
            });
            return items;
        }

        function filterFields(item, filteredFields) {
            _.forEach(item, function (value, fieldName) {
                if (!filteredFields[fieldName] && fieldName !== 'id') { //TODO is id really special here?
                    delete item[fieldName];
                }
            });
            return item;
        }

        function checkPermission(permissionName, permissionCheckMethod) {
            var user = injection.inject('User', true);
            if (!entityDescriptionService[permissionCheckMethod](crudId, user)) {
                throw new appUtil.ForbiddenError(permissionName + ' permission to ' + JSON.stringify(crudId) + ' denied for ' + (user ? '"' + user.username + '"' : 'unauthorized user'));
            }
        }
    }

    function systemCrudWrapper(crudStrategy) {
        var result = {};
        wrap(function () {
            var next = this;
            return securityService.asSystemUser(next);
        }, ['findAll', 'findCount', 'getTotalRow', 'findRange', 'readEntity', 'createEntity', 'updateEntity', 'deleteEntity'], result, crudStrategy);
        return result;
    }

    function wrap(proxyFn, methodsToWrap, obj, target) {
        target = target || obj;
        _.forEach(methodsToWrap, function (methodName) {
            var targetFn = target[methodName];
            obj[methodName] = function () {
                var args = arguments;
                return proxyFn.apply(function () {
                    return targetFn.apply(target, args);
                }, args);
            }
        });
    }

    return service;
};<|endoftext|>


<commit_before>/*
 * Utilities.js
 * Created by CreaturePhil
 *
 * This is where extraneous and important functions are stored.
 *
 */

 var Utilities = exports.Utilities = {

	HueToRgb: function (m1, m2, hue) {
	    var v;
	    if (hue < 0)
	        hue += 1;
	    else if (hue > 1)
	        hue -= 1;

	    if (6 * hue < 1)
	        v = m1 + (m2 - m1) * hue * 6;
	    else if (2 * hue < 1)
	        v = m2;
	    else if (3 * hue < 2)
	        v = m1 + (m2 - m1) * (2 / 3 - hue) * 6;
	    else
	        v = m1;

	    return (255 * v).toString(16);
	},

	hashColor: function (name) {
	    var crypto = require('crypto');
	    var hash = crypto.createHash('md5').update(name).digest('hex');
	    var H = parseInt(hash.substr(4, 4), 16) % 360;
	    var S = parseInt(hash.substr(0, 4), 16) % 50 + 50;
	    var L = parseInt(hash.substr(8, 4), 16) % 20 + 25;

	    var m1, m2, hue;
	    var r, g, b
	        S /= 100;
	    L /= 100;
	    if (S == 0)
	        r = g = b = (L * 255).toString(16);
	    else {
	        if (L <= 0.5)
	            m2 = L * (S + 1);
	        else
	            m2 = L + S - L * S;
	        m1 = L * 2 - m2;
	        hue = H / 360;
	        r = this.HueToRgb(m1, m2, hue + 1 / 3);
	        g = this.HueToRgb(m1, m2, hue);
	        b = this.HueToRgb(m1, m2, hue - 1 / 3);
	    }

	    return 'rgb(' + r + ', ' + g + ', ' + b + ');';
	},

	formatAMPM: function(date) {
		var hours = date.getHours();
		var minutes = date.getMinutes();
		var ampm = hours >= 12 ? 'PM' : 'AM';
		hours = hours % 12;
		hours = hours ? hours : 12; // the hour '0' should be '12'
		minutes = minutes < 10 ? '0'+minutes : minutes;
		var strTime = hours + ':' + minutes + ' ' + ampm;
		return strTime;
	},

	rank: function(user){
		var data = fs.readFileSync('config/db/tourWins.csv','utf8');
		var row = (''+data).split("\n");

		var list = [];

		for (var i = row.length; i > -1; i--) {
			if (!row[i]) continue;
			var parts = row[i].split(",");
			list.push([toId(parts[0]),Number(parts[1])]);
		}
		list.sort(function(a,b){
    		return a[1] - b[1];
		});
		var arr = list.filter( function( el ) {
   			 return !!~el.indexOf(toId(user));
		});
		if (list.indexOf(arr[0]) === -1) {
			return 'Not Ranked';
		} else {
			return 'Rank ' + (list.length-list.indexOf(arr[0])) + ' out of ' + list.length;
		}
	},

	calcElo: function(winner, loser) {
		var kFactor = 32;
  		var ratingDifference = loser.elo - winner.elo;
  		var expectedScoreWinner = 1 / ( 1 + Math.pow(10, ratingDifference/400) );

  		var e = kFactor * (1 - expectedScoreWinner);
 		winner.elo = winner.elo + e;
  		loser.elo = loser.elo - e;

  		var arr = [winner.elo, loser.elo];
  		return arr;
	},

	botDelay: function(botName, room, message) {
		setTimeout(function(){
			room.add('|c|' + Users.users[toId(botName)].group + botName + '|' + message);
		}, (Math.floor(Math.random() * 6) * 1000));
	},

	spamProtection: function(user, room, connection, message) {
		if (user.group === ' ') {

			// flooding check
			/*if (user.numMsg >= 5 && user.group === ' ') {
				room.add('|c|'+ user.name+'|'+message);
				user.popup(botName+' has muted you for 7 minutes. '+ '(spam)');
				room.add(''+user.name+' was muted by '+ botName +' for 7 minutes.' + ' (flooding)');
				var alts = user.getAlts();
				if (alts.length) room.add(""+user.name+"'s alts were also muted: "+alts.join(", "));
				room.add('|unlink|' + user.userid);

				user.mute(room.id, 7*60*1000);
				user.numMsg = 0;
				return false;
			}*/

			// numMsgs reset
			if (user.connected === false) {
				user.numMsg = 0;
				user.warnCounter = 0;
			}
			if (user.numMsg != 0){
				setTimeout(function() {
					user.numMsg = 0;
				}, 6000);
			}

			// caps check
			var capsMatch = message.replace(/[^A-Za-z]/g, '').match(/[A-Z]/g);
			if (capsMatch && this.toId(message).length > 18 && (capsMatch.length >= Math.floor(this.toId(message).length * 0.8))) {
				room.add('|c|'+ user.name+'|'+message);
						user.warnCounter++;
						if (user.warnCounter >= 3) {
							user.popup(botName+' has muted you for 7 minutes. (caps)');
							room.add(''+user.name+' was muted by '+botName+' for 7 minutes.' + ' (caps)');
							var alts = user.getAlts();
							if (alts.length) room.add(""+user.name+"'s alts were also muted: "+alts.join(", "));
							room.add('|unlink|' + user.userid);

							user.numMsg = 0;
							user.warnCounter = 0;
							user.mute(room.id, 7*60*1000);
							return false;
						}
						room.add(''+user.name+' was warned by '+botName+'.' +  ' (caps)');
						user.send('|c|~|/warn '+'caps');
						return false;

			}

			// stretch check
			var stretchMatch = message.toLowerCase().match(/(.)\1{7,}/g); // matches the same character 8 or more times in a row
			if (stretchMatch) {
				room.add('|c|'+ user.name+'|'+message);
				user.warnCounter++;
				if (user.warnCounter >= 3) {
					user.popup(botName+' has muted you for 7 minutes. (stretching)');
					room.add(''+user.name+' was muted by '+ botName +' for 7 minutes.' + ' (stretching)');
					var alts = user.getAlts();
					if (alts.length) room.add(""+user.name+"'s alts were also muted: "+alts.join(", "));
					room.add('|unlink|' + user.userid);

					user.numMsg = 0;
					user.warnCounter = 0;
					user.mute(room.id, 7*60*1000);
					return false;
				}
				room.add(''+user.name+' was warned by '+botName+'.' +  ' (stretching)');
				user.send('|c|~|/warn '+'stretching');
				return false;
			}

			/*var banWords = ['fuck','bitch','nigga','fag','shit','nigger'];
			for (var i=0;i<banWords.length;i++) {
				if (message.toLowerCase().indexOf(banWords[i]) >= 0) {
					room.add('|c|'+ user.name+'|'+message);
					if (user.warnCounter >= 3) {
						user.popup(botName+' has muted you for 7 minutes. (Inappropriate word: ' + banWords[i]+')');
						room.add(''+user.name+' was muted by '+ botName +' for 7 minutes. (Inappropriate word: ' + banWords[i]+')');
						var alts = user.getAlts();
						if (alts.length) room.add(""+user.name+"'s alts were also muted: "+alts.join(", "));
						room.add('|unlink|' + user.userid);

						user.numMsg = 0;
						user.warnCounter = 0;
						user.mute(room.id, 7*60*1000);
						return false;
					}
					var botMsg = user.name + ' -> Go ahead, make my day. [Inappropriate word: '+banWords[i]+'] [warning]';
					this.botDelay(botName, room, botMsg);
					user.warnCounter++;
					return false;
				}
			}*/

		}

	},

	toId: function(text) {
		return text.toLowerCase().replace(/[^a-z0-9]/g, '');
	},

	stdin: function(file, name) {
		var info = " ";
		var match = false;

    	var data = fs.readFileSync('config/'+file,'utf8');

        var row = (''+data).split("\n");
        for (var i = row.length; i > -1; i--) {
                if (!row[i]) continue;
                var parts = row[i].split(",");
                var userid = toId(parts[0]);
                if (toId(name) == userid) {
                	info = String(parts[1]);
                    match = true;
                    if (match === true) {
                            break;
                    }
                }
        }
        return info;
	},

	findAvatar: function(name) {
		var info = "";

		for (user in Config.customAvatars) {
			if (user === name) {
				return Config.customAvatars[user];
			}
		}
		return 0;
	},
	poll: function () {
        var poll = {};
        var customCommand = {

            reset: function (roomId) {
                poll[roomId] = {
                    question: undefined,
                    optionList: [],
                    options: {},
                    display: ''
                };
            },

            splint: function (target) {
                var parts = target.split(',');
                var len = parts.length;
                while (len--) {
                    parts[len] = parts[len].trim();
                }
                return parts;
            }

        };

        for (var i in customCommand) {
            if (customCommand.hasOwnProperty(i)) {
                poll[i] = customCommand[i];
            }
        }

        for (var id in Rooms.rooms) {
            if (Rooms.rooms[id].type === 'chat' && !poll[id]) {
                poll[id] = {};
                poll.reset(id);
            }
        }

        return poll;
    }

};
<commit_msg>Update utilities.js<commit_after>/*
 * Utilities.js
 * Created by CreaturePhil
 *
 * This is where extraneous and important functions are stored.
 *
 */

 var Utilities = exports.Utilities = {

	HueToRgb: function (m1, m2, hue) {
	    var v;
	    if (hue < 0)
	        hue += 1;
	    else if (hue > 1)
	        hue -= 1;

	    if (6 * hue < 1)
	        v = m1 + (m2 - m1) * hue * 6;
	    else if (2 * hue < 1)
	        v = m2;
	    else if (3 * hue < 2)
	        v = m1 + (m2 - m1) * (2 / 3 - hue) * 6;
	    else
	        v = m1;

	    return (255 * v).toString(16);
	},

	hashColor: function (name) {
	    var crypto = require('crypto');
	    var hash = crypto.createHash('md5').update(name).digest('hex');
	    var H = parseInt(hash.substr(4, 4), 16) % 360;
	    var S = parseInt(hash.substr(0, 4), 16) % 50 + 50;
	    var L = parseInt(hash.substr(8, 4), 16) % 20 + 25;

	    var m1, m2, hue;
	    var r, g, b
	        S /= 100;
	    L /= 100;
	    if (S == 0)
	        r = g = b = (L * 255).toString(16);
	    else {
	        if (L <= 0.5)
	            m2 = L * (S + 1);
	        else
	            m2 = L + S - L * S;
	        m1 = L * 2 - m2;
	        hue = H / 360;
	        r = this.HueToRgb(m1, m2, hue + 1 / 3);
	        g = this.HueToRgb(m1, m2, hue);
	        b = this.HueToRgb(m1, m2, hue - 1 / 3);
	    }

	    return 'rgb(' + r + ', ' + g + ', ' + b + ');';
	},

	formatAMPM: function(date) {
		var hours = date.getHours();
		var minutes = date.getMinutes();
		var ampm = hours >= 12 ? 'PM' : 'AM';
		hours = hours % 12;
		hours = hours ? hours : 12; // the hour '0' should be '12'
		minutes = minutes < 10 ? '0'+minutes : minutes;
		var strTime = hours + ':' + minutes + ' ' + ampm;
		return strTime;
	},

	rank: function(user){
		var data = fs.readFileSync('config/db/tourWins.csv','utf8');
		var row = (''+data).split("\n");

		var list = [];

		for (var i = row.length; i > -1; i--) {
			if (!row[i]) continue;
			var parts = row[i].split(",");
			list.push([toId(parts[0]),Number(parts[1])]);
		}
		list.sort(function(a,b){
    		return a[1] - b[1];
		});
		var arr = list.filter( function( el ) {
   			 return !!~el.indexOf(toId(user));
		});
		if (list.indexOf(arr[0]) === -1) {
			return 'Not Ranked';
		} else {
			return 'Rank ' + (list.length-list.indexOf(arr[0])) + ' out of ' + list.length;
		}
	},

	calcElo: function(winner, loser) {
		var kFactor = 32;
  		var ratingDifference = loser.elo - winner.elo;
  		var expectedScoreWinner = 1 / ( 1 + Math.pow(10, ratingDifference/400) );

  		var e = kFactor * (1 - expectedScoreWinner);
 		winner.elo = winner.elo + e;
  		loser.elo = loser.elo - e;

  		var arr = [winner.elo, loser.elo];
  		return arr;
	},

	botDelay: function(botName, room, message) {
		setTimeout(function(){
			room.add('|c|' + Users.users[toId(botName)].group + botName + '|' + message);
		}, (Math.floor(Math.random() * 6) * 1000));
	},

	spamProtection: function(user, room, connection, message) {
		if (user.group === ' ') {

			// flooding check
			/*if (user.numMsg >= 5 && user.group === ' ') {
				room.add('|c|'+ user.name+'|'+message);
				user.popup(botName+' has muted you for 7 minutes. '+ '(spam)');
				room.add(''+user.name+' was muted by '+ botName +' for 7 minutes.' + ' (flooding)');
				var alts = user.getAlts();
				if (alts.length) room.add(""+user.name+"'s alts were also muted: "+alts.join(", "));
				room.add('|unlink|' + user.userid);

				user.mute(room.id, 7*60*1000);
				user.numMsg = 0;
				return false;
			}*/

			// numMsgs reset
			if (user.connected === false) {
				user.numMsg = 0;
				user.warnCounter = 0;
			}
			if (user.numMsg != 0){
				setTimeout(function() {
					user.numMsg = 0;
				}, 6000);
			}

			// caps check
			var capsMatch = message.replace(/[^A-Za-z]/g, '').match(/[A-Z]/g);
			if (capsMatch && this.toId(message).length > 18 && (capsMatch.length >= Math.floor(this.toId(message).length * 0.8))) {
				room.add('|c|'+ user.name+'|'+message);
						user.warnCounter++;
						if (user.warnCounter >= 3) {
							user.popup(botName+' has muted you for 7 minutes. (caps)');
							room.add(''+user.name+' was muted by '+botName+' for 7 minutes.' + ' (caps)');
							var alts = user.getAlts();
							if (alts.length) room.add(""+user.name+"'s alts were also muted: "+alts.join(", "));
							room.add('|unlink|' + user.userid);

							user.numMsg = 0;
							user.warnCounter = 0;
							user.mute(room.id, 7*60*1000);
							return false;
						}
						room.add(''+user.name+' was warned by '+botName+'.' +  ' (caps)');
						user.send('|c|~|/warn '+'caps');
						return false;

			}

			// stretch check
			var stretchMatch = message.toLowerCase().match(/(.)\1{7,}/g); // matches the same character 8 or more times in a row
			if (stretchMatch) {
				room.add('|c|'+ user.name+'|'+message);
				user.warnCounter++;
				if (user.warnCounter >= 3) {
					user.popup(botName+' has muted you for 7 minutes. (stretching)');
					room.add(''+user.name+' was muted by '+ botName +' for 7 minutes.' + ' (stretching)');
					var alts = user.getAlts();
					if (alts.length) room.add(""+user.name+"'s alts were also muted: "+alts.join(", "));
					room.add('|unlink|' + user.userid);

					user.numMsg = 0;
					user.warnCounter = 0;
					user.mute(room.id, 7*60*1000);
					return false;
				}
				room.add(''+user.name+' was warned by '+botName+'.' +  ' (stretching)');
				user.send('|c|~|/warn '+'stretching');
				return false;
			}

			/*var banWords = ['fuck','bitch','nigga','fag','shit','nigger'];
			for (var i=0;i<banWords.length;i++) {
				if (message.toLowerCase().indexOf(banWords[i]) >= 0) {
					room.add('|c|'+ user.name+'|'+message);
					if (user.warnCounter >= 3) {
						user.popup(botName+' has muted you for 7 minutes. (Inappropriate word: ' + banWords[i]+')');
						room.add(''+user.name+' was muted by '+ botName +' for 7 minutes. (Inappropriate word: ' + banWords[i]+')');
						var alts = user.getAlts();
						if (alts.length) room.add(""+user.name+"'s alts were also muted: "+alts.join(", "));
						room.add('|unlink|' + user.userid);

						user.numMsg = 0;
						user.warnCounter = 0;
						user.mute(room.id, 7*60*1000);
						return false;
					}
					var botMsg = user.name + ' -> Go ahead, make my day. [Inappropriate word: '+banWords[i]+'] [warning]';
					this.botDelay(botName, room, botMsg);
					user.warnCounter++;
					return false;
				}
			}*/

		}

	},

	toId: function(text) {
		return text.toLowerCase().replace(/[^a-z0-9]/g, '');
	},

	stdin: function(file, name) {
		var info = " ";
		var match = false;

    	var data = fs.readFileSync('config/'+file,'utf8');

        var row = (''+data).split("\n");
        for (var i = row.length; i > -1; i--) {
                if (!row[i]) continue;
                var parts = row[i].split(",");
                var userid = toId(parts[0]);
                if (toId(name) == userid) {
                	info = String(parts[1]);
                    match = true;
                    if (match === true) {
                            break;
                    }
                }
        }
        return info;
	},

	findAvatar: function(name) {
		var info = "";

		for (user in Config.customAvatars) {
			if (user === name) {
				return Config.customAvatars[user];
			}
		}
		return 0;
	}

};
<|endoftext|>


<commit_before>elation.require(['janusweb.janusghost', 'engine.things.maskgenerator', 'engine.things.sound', 'janusweb.external.JanusVOIP'], function() {
elation.component.add('engine.things.remoteplayer', function() {
  this.postinit = function() {
    elation.engine.things.remoteplayer.extendclass.postinit.call(this);
    this.defineProperties({
      startposition: {type: 'vector3', default: new THREE.Vector3()},
      pickable: {type: 'boolean', default: false},
      collidable: {type: 'boolean', default: false},
      player_id: {type: 'string', default: 'UnknownPlayer'},
      player_name: {type: 'string', default: 'UnknownPlayer'},
    });
    this.properties.ghost_id = this.properties.player_name;
  };

/*
  this.createObject3D = function() {
    var geo = new THREE.CylinderGeometry(1, 1, 4, 8),
        mat = new THREE.MeshPhongMaterial({ color: 0x000000, transparent: true, opacity: 0.7 }),
        mesh = new THREE.Mesh(geo, mat);
    return mesh;
  };
*/

  this.createChildren = function() {
    elation.engine.things.remoteplayer.extendclass.createChildren.call(this);
    this.torso = this.spawn('janusbase', this.properties.player_name + '_torso', {
      'position': [0,1,0],
      'parent': this,
      'janus': this.janus,
      'room': this.room
    });
    this.shoulders = this.torso.spawn('janusbase', this.properties.player_id + '_shoulders', {
      'position': [0,0.6,-0.0],
      'parent': this,
      'janus': this.janus,
      'room': this.room
    });
    this.neck = this.torso.spawn('janusbase', this.properties.player_name + '_neck', {
      'position': [0,0.4,0],
      'parent': this,
      'janus': this.janus,
      'room': this.room
    });
    this.head = this.spawn('janusbase', this.properties.player_name + '_head', {
      'position': [0,1.4,0],
      'parent': this,
      'janus': this.janus,
      'room': this.room
    });
/*
    this.face = this.head.spawn('maskgenerator', this.properties.player_name + '_mask', {
      'seed': this.properties.player_name,
      'position': [0,0,-0.025],
      collidable: false,
      'tilesize': 0.05,
      'player_id': this.properties.player_name,
      pickable: false,
      collidable: false
    });
*/
/*
    this.label = this.createObject('text', {
      size: .1,
      thickness: .002,
      align: 'center',
      collidable: false,
      text: this.player_name,
      position: [0,2,0],
      orientation: [0,1,0,0],
      pickable: false,
      collidable: false,
      billboard: 'y'
    });
*/
    if (this.engine.client.player.usevoip && this.engine.systems.sound.canPlaySound) {
      this.mouth = this.head.spawn('sound', this.properties.player_name + '_voice', {
        //loop: true
      });
      this.mouth.createAudio();
      var context = this.mouth.audio.context;
      this.voip = new JanusVOIPPlayer();
      this.voip.start(context);
      this.audiobuffer = {readyCallbacks: []};//new THREE.AudioBuffer(this.mouth.audio.context);
      this.audiobuffer.buffer = this.voip.rawbuffer;

      //elation.events.add(this.voip, 'voip_player_data', elation.bind(this, this.handleVoipData));
      this.audiobuffer.ready = true;
      for ( var i = 0; i < this.audiobuffer.readyCallbacks.length; i ++ ) {

        this.audiobuffer.readyCallbacks[ i ]( this.voip.rawbuffer );

      }
    }

    //this.mouth.audio.setBuffer(this.audiobuffer);
    elation.events.add(this, 'thing_change', elation.bind(this, this.updateTransparency));
  };
  this.speak = function(noise) {
    this.voip.speak(noise);

    if (!this.mouth.audio.playing) {
      this.mouth.audio.play();
    }
    this.label.material.color.setHex(0x00ff00);
    if (this.talktimer) {
      clearTimeout(this.talktimer);
    }
    this.talktimer = setTimeout(elation.bind(this, this.shutup), this.bufferlength * 500);

  }
  this.shutup = function() {
    this.voip.silence();
/*
    if (this.mouth.audio.playing) {
      this.mouth.audio.stop();
    }
    var bufferLeft = this.rawbuffer.getChannelData(0);
    var bufferRight = this.rawbuffer.getChannelData(1);
    for (var i = 0; i < bufferLeft.length; i++) {
      bufferLeft[i] = bufferRight[i] = 0;
    }
    this.bufferoffset = 0;
*/
    this.label.material.color.setHex(0xcccccc);
  }
  this.handleVoipData = function(ev) {
    //this.mouth.audio.source.loopEnd = ev.data.end;
    if (!this.mouth.audio.isPlaying) {
      //this.mouth.audio.play(ev.data.start, ev.data.end);
    } else {
      //console.log('already playing');
    }
  }
}, elation.engine.things.janusghost);

});

<commit_msg>remoteplayer.addVoice()<commit_after>elation.require(['janusweb.janusghost', 'engine.things.maskgenerator', 'engine.things.sound', 'janusweb.external.JanusVOIP'], function() {
elation.component.add('engine.things.remoteplayer', function() {
  this.postinit = function() {
    elation.engine.things.remoteplayer.extendclass.postinit.call(this);
    this.defineProperties({
      startposition: {type: 'vector3', default: new THREE.Vector3()},
      pickable: {type: 'boolean', default: false},
      collidable: {type: 'boolean', default: false},
      player_id: {type: 'string', default: 'UnknownPlayer'},
      player_name: {type: 'string', default: 'UnknownPlayer'},
    });
    this.properties.ghost_id = this.properties.player_name;
  };

/*
  this.createObject3D = function() {
    var geo = new THREE.CylinderGeometry(1, 1, 4, 8),
        mat = new THREE.MeshPhongMaterial({ color: 0x000000, transparent: true, opacity: 0.7 }),
        mesh = new THREE.Mesh(geo, mat);
    return mesh;
  };
*/

  this.createChildren = function() {
    elation.engine.things.remoteplayer.extendclass.createChildren.call(this);
    this.torso = this.spawn('janusbase', this.properties.player_name + '_torso', {
      'position': [0,1,0],
      'parent': this,
      'janus': this.janus,
      'room': this.room
    });
    this.shoulders = this.torso.spawn('janusbase', this.properties.player_id + '_shoulders', {
      'position': [0,0.6,-0.0],
      'parent': this,
      'janus': this.janus,
      'room': this.room
    });
    this.neck = this.torso.spawn('janusbase', this.properties.player_name + '_neck', {
      'position': [0,0.4,0],
      'parent': this,
      'janus': this.janus,
      'room': this.room
    });
    this.head = this.spawn('janusbase', this.properties.player_name + '_head', {
      'position': [0,1.4,0],
      'parent': this,
      'janus': this.janus,
      'room': this.room
    });
/*
    this.face = this.head.spawn('maskgenerator', this.properties.player_name + '_mask', {
      'seed': this.properties.player_name,
      'position': [0,0,-0.025],
      collidable: false,
      'tilesize': 0.05,
      'player_id': this.properties.player_name,
      pickable: false,
      collidable: false
    });
*/
/*
    this.label = this.createObject('text', {
      size: .1,
      thickness: .002,
      align: 'center',
      collidable: false,
      text: this.player_name,
      position: [0,2,0],
      orientation: [0,1,0,0],
      pickable: false,
      collidable: false,
      billboard: 'y'
    });
*/
    if (this.engine.client.player.usevoip && this.engine.systems.sound.canPlaySound) {
      this.mouth = this.head.spawn('sound', this.properties.player_name + '_voice', {
        //loop: true
      });
      this.mouth.createAudio();
      var context = this.mouth.audio.context;
      this.voip = new JanusVOIPPlayer();
      this.voip.start(context);
      this.audiobuffer = {readyCallbacks: []};//new THREE.AudioBuffer(this.mouth.audio.context);
      this.audiobuffer.buffer = this.voip.rawbuffer;

      //elation.events.add(this.voip, 'voip_player_data', elation.bind(this, this.handleVoipData));
      this.audiobuffer.ready = true;
      for ( var i = 0; i < this.audiobuffer.readyCallbacks.length; i ++ ) {

        this.audiobuffer.readyCallbacks[ i ]( this.voip.rawbuffer );

      }
    }

    //this.mouth.audio.setBuffer(this.audiobuffer);
    elation.events.add(this, 'thing_change', elation.bind(this, this.updateTransparency));
  };
  this.speak = function(noise) {
    this.voip.speak(noise);

    if (!this.mouth.audio.playing) {
      this.mouth.audio.play();
    }
    this.label.material.color.setHex(0x00ff00);
    if (this.talktimer) {
      clearTimeout(this.talktimer);
    }
    this.talktimer = setTimeout(elation.bind(this, this.shutup), this.bufferlength * 500);

  }
  this.shutup = function() {
    this.voip.silence();
/*
    if (this.mouth.audio.playing) {
      this.mouth.audio.stop();
    }
    var bufferLeft = this.rawbuffer.getChannelData(0);
    var bufferRight = this.rawbuffer.getChannelData(1);
    for (var i = 0; i < bufferLeft.length; i++) {
      bufferLeft[i] = bufferRight[i] = 0;
    }
    this.bufferoffset = 0;
*/
    this.label.material.color.setHex(0xcccccc);
  }
  this.handleVoipData = function(ev) {
    //this.mouth.audio.source.loopEnd = ev.data.end;
    if (!this.mouth.audio.isPlaying) {
      //this.mouth.audio.play(ev.data.start, ev.data.end);
    } else {
      //console.log('already playing');
    }
  }
  this.addVoice = function(stream) {
    this.mouth = this.createObject('sound', { pos: V(0, 0, 0), distanceModel: 'exponential' });
    this.head.add(this.mouth._target);
    this.mouth.createAudio();

    let panner = this.mouth.audio.panner,
        context = panner.context,
        source = context.createMediaStreamSource(stream);

    if (this.engine.systems.sound.canPlaySound) {
      source.connect(panner);
      this.mouth.audio.play();
    } else {
      elation.events.add(this.engine.systems.sound, 'sound_enabled', (ev) => {
        source.connect(panner);
        this.mouth.audio.play();
      });
    }
  }
}, elation.engine.things.janusghost);

});

<|endoftext|>


<commit_before>const { execSync } = require('child_process');
const { mkdirpSync } = require('fs-extra');
const { join } = require('path');

const cwd = process.cwd();

const nodeModulesDocker = join(cwd, '.node_modules__docker');
//const dockerImage = 'uxaspects/buildenv:latest';
const dockerImage = 'cafinternal/prereleases:buildenv-1.3.0-EL-3727-SNAPSHOT';

// Ensure the docker node_modules__docker directory exists
mkdirpSync(nodeModulesDocker);

// access environment
const http_proxy = process.env.HTTP_PROXY || process.env.http_proxy;
const https_proxy = process.env.HTTPS_PROXY || process.env.https_proxy;

if (!http_proxy){
    console.warn(`Neither HTTP_PROXY nor http_proxy have been defined in the host environment.`);
}

if (!https_proxy){
    console.warn(`Neither HTTPS_PROXY nor https_proxy have been defined in the host environment.`);
}

// produce the docker command string
const dockerCommand = `docker run --rm -it --memory=4g -e "http_proxy=${http_proxy}" -e "https_proxy=${https_proxy}" -v "${cwd}:/wd" -v "${nodeModulesDocker}:/wd/node_modules" -w /wd --entrypoint /bin/bash ${dockerImage}`;

// run the command string with the inherited terminal
try {
    execSync(dockerCommand, { stdio: 'inherit' });
} catch (error) {
    console.warn(`Exited: ${error.message || error.signal}`);
}
<commit_msg>EL-3728: Update build env image<commit_after>const { execSync } = require('child_process');
const { mkdirpSync } = require('fs-extra');
const { join } = require('path');

const cwd = process.cwd();

const nodeModulesDocker = join(cwd, '.node_modules__docker');
const dockerImage = 'uxaspects/buildenv:latest';

// Ensure the docker node_modules__docker directory exists
mkdirpSync(nodeModulesDocker);

// access environment
const http_proxy = process.env.HTTP_PROXY || process.env.http_proxy;
const https_proxy = process.env.HTTPS_PROXY || process.env.https_proxy;

if (!http_proxy){
    console.warn(`Neither HTTP_PROXY nor http_proxy have been defined in the host environment.`);
}

if (!https_proxy){
    console.warn(`Neither HTTPS_PROXY nor https_proxy have been defined in the host environment.`);
}

// produce the docker command string
const dockerCommand = `docker run --rm -it --memory=4g -e "http_proxy=${http_proxy}" -e "https_proxy=${https_proxy}" -v "${cwd}:/wd" -v "${nodeModulesDocker}:/wd/node_modules" -w /wd --entrypoint /bin/bash ${dockerImage}`;

// run the command string with the inherited terminal
try {
    execSync(dockerCommand, { stdio: 'inherit' });
} catch (error) {
    console.warn(`Exited: ${error.message || error.signal}`);
}
<|endoftext|>


<commit_before>'use strict';

var xhr = require('../shared/xhr');
var throttle = require('../shared/throttler');

// For documentation purpose
var STATUS_OK = 0;
var STATUS_NO_RESULT = 1;
var STATUS_TOO_MANY_RESULTS = 2;
var STATUS_ERROR = -1;

var renderers = {
    0: renderResults,
    1: renderNoResult,
    2: renderTooManyResults
};
renderers[-1] = renderError;

function search(str) {
    return xhr('/api/search/' + str).then(function(response) {
        hideAlerts();
        return renderers[response.status](response.results);
    });
}

var searchInput = document.querySelector('#search');

searchInput.addEventListener('input', function() {
    window.history.pushState({}, '', '?' + this.value);
    window.onpopstate();
});

window.onpopstate = throttle(300, function() {
    if (searchInput.value === '') {
        clearResults();
        return;
    }
    search(window.location.search.slice(1));
});

if (window.location.search.length > 1) {
    search(window.location.search.slice(1));
    searchInput.value = window.location.search.slice(1);
}

var resultsTable = document.querySelector('#results');

function clearResults() {
    var trs = resultsTable.querySelectorAll('tbody > tr');
    for (var i = 0; i < trs.length; i++) {
        trs[i].remove();
    }
}

function renderResults(results) {
    clearResults();

    var tbody = resultsTable.querySelector('tbody');
    var newTr;
    for (var i = 0; i < results.length; i++) {
        newTr = makeRow(results[i], !(i % 2));
        tbody.appendChild(newTr);
    }
}

function makeRow(result, isEven) {
    var tr = document.createElement('tr');
    var distributionTd = document.createElement('td');
    var nameTd = document.createElement('td');
    var versionTd = document.createElement('td');
    var linkTd = document.createElement('td');

    tr.className = isEven ? 'even' : 'odd';

    distributionTd.textContent = result.distribution;
    nameTd.textContent = result.name;
    versionTd.textContent = result.version;

    var anchor = document.createElement('a');
    anchor.href = '/packages/' + result.distribution + '/' +
        result.name + '/' + result.version + '/';
    anchor.textContent = 'view source';
    linkTd.appendChild(anchor);

    tr.appendChild(distributionTd);
    tr.appendChild(nameTd);
    tr.appendChild(versionTd);
    tr.appendChild(linkTd);

    return tr;
}

function renderNoResult() {
    // Don't do anything
}

function renderTooManyResults(results) {
    renderResults(results);
    showWarning('There are many results, but only 20 are shown.');
}

function renderError() {
    showError('A server error occured. Please try again later.');
}

var warningDiv = document.querySelector('#warning');
function showWarning(msg) {
    warningDiv.hidden = false;
    warningDiv.textContent = msg;
}

var errorDiv = document.querySelector('#error');
function showError(msg) {
    errorDiv.hidden = false;
    errorDiv.textContent = msg;
}

function hideAlerts() {
    hideWarning();
    hideError();
}

function hideWarning() {
    warningDiv.hidden = true;
}

function hideError() {
    errorDiv.hidden = true;
}
<commit_msg>Hide alerts at the proper time.<commit_after>'use strict';

var xhr = require('../shared/xhr');
var throttle = require('../shared/throttler');

// For documentation purpose
var STATUS_OK = 0;
var STATUS_NO_RESULT = 1;
var STATUS_TOO_MANY_RESULTS = 2;
var STATUS_ERROR = -1;

var renderers = {
    0: renderResults,
    1: renderNoResult,
    2: renderTooManyResults
};
renderers[-1] = renderError;

function search(str) {
    return xhr('/api/search/' + str).then(function(response) {
        return renderers[response.status](response.results);
    });
}

var searchInput = document.querySelector('#search');

searchInput.addEventListener('input', function() {
    window.history.pushState({}, '', '?' + this.value);
    window.onpopstate();
});

window.onpopstate = throttle(300, function() {
    if (searchInput.value === '') {
        clearResults();
        return;
    }
    search(window.location.search.slice(1));
});

if (window.location.search.length > 1) {
    search(window.location.search.slice(1));
    searchInput.value = window.location.search.slice(1);
}

var resultsTable = document.querySelector('#results');

function clearResults() {
    var trs = resultsTable.querySelectorAll('tbody > tr');
    for (var i = 0; i < trs.length; i++) {
        trs[i].remove();
    }
    hideAlerts();
}

function renderResults(results) {
    clearResults();

    var tbody = resultsTable.querySelector('tbody');
    var newTr;
    for (var i = 0; i < results.length; i++) {
        newTr = makeRow(results[i], !(i % 2));
        tbody.appendChild(newTr);
    }
}

function makeRow(result, isEven) {
    var tr = document.createElement('tr');
    var distributionTd = document.createElement('td');
    var nameTd = document.createElement('td');
    var versionTd = document.createElement('td');
    var linkTd = document.createElement('td');

    tr.className = isEven ? 'even' : 'odd';

    distributionTd.textContent = result.distribution;
    nameTd.textContent = result.name;
    versionTd.textContent = result.version;

    var anchor = document.createElement('a');
    anchor.href = '/packages/' + result.distribution + '/' +
        result.name + '/' + result.version + '/';
    anchor.textContent = 'view source';
    linkTd.appendChild(anchor);

    tr.appendChild(distributionTd);
    tr.appendChild(nameTd);
    tr.appendChild(versionTd);
    tr.appendChild(linkTd);

    return tr;
}

function renderNoResult() {
    // Don't do anything
}

function renderTooManyResults(results) {
    renderResults(results);
    showWarning('There are many results, but only 20 are shown.');
}

function renderError() {
    showError('A server error occured. Please try again later.');
}

var warningDiv = document.querySelector('#warning');
function showWarning(msg) {
    warningDiv.hidden = false;
    warningDiv.textContent = msg;
}

var errorDiv = document.querySelector('#error');
function showError(msg) {
    errorDiv.hidden = false;
    errorDiv.textContent = msg;
}

function hideAlerts() {
    hideWarning();
    hideError();
}

function hideWarning() {
    warningDiv.hidden = true;
}

function hideError() {
    errorDiv.hidden = true;
}
<|endoftext|>


<commit_before>import fetch from 'node-fetch';
import _ from 'underscore';
import moment from 'moment';

module.exports = function(app) {
  var module = {};

  module.app = app;

  module.mine = function(uri, workflowId) {
    // This will min the stage definition first, then move on to runs.
    module.app.log.debug('mine(uri: ' + uri + ', workflowId: ' + workflowId + ')');

    module.fetchHubHeaders = { headers: { 'Content-Type': 'application/vnd.api+json', 'Authorization': module.app.token } };
    module.fetchJenkinsHeaders = { headers: { 'Content-Type': 'application/vnd.api+json', 'Accept': 'application/vnd.api+json' } };

    let stages = [];

    fetch(uri + 'wfapi/runs', Object.assign({ method: 'get' }, module.fetchJenkinsHeaders)).then(resp => resp.json())
    .then(json => {
     // module.app.log.debug(json);
      if(json.length > 0) {
        // just take the last run to identify stages.
        //let workflowRun = json[0];
        let workflowRun = _.max(json, (run) => run.stages.length);
        //module.app.log.debug(workflowRun.stages);
        for(let i = 0; i < workflowRun.stages.length; i++) {
          //module.app.log.debug(workflowRun.stages[i].name);
          let stageName = workflowRun.stages[i].name;
          let stageOrder = i;
          stages.push(new Promise((resolve, reject) => {
            //module.app.log.info('Processing async task: ' + stageName);
            fetch(module.app.config.hub.apiHost + '/api/workflowStep/?filter[name]=' + stageName + '&filter[workflowId]=' + workflowId,
              Object.assign(
                { method: 'get' },
                module.fetchHubHeaders
              )
            )
            .then(respLookup => respLookup.json())
            .then(respLookupJson => {
              //module.app.log.debug(respLookupJson);
              if (respLookupJson.data.length == 0) {
                // Create it
                var workflowStep = {
                  type: 'workflowStep',
                  attributes: {
                    workflowId: workflowId,
                    uri: 'n/a', /* No good URI here but the workflow one */
                    name: stageName,
                    description: stageName + ' description',
                    order: stageOrder
                  }
                }
                fetch(module.app.config.hub.apiHost + '/api/workflowStep/',
                Object.assign(
                  { method: 'post' },
                  module.fetchHubHeaders,
                  {
                    body: JSON.stringify({ data: workflowStep })
                  })
                )
                .then(respAdd => respAdd.json())
                .then(respAddJson => {
                  //module.app.log.info(respAddJson);
                  resolve();
                })
              } else {
                resolve();
              }
            }).catch(err => {
              module.app.log.error(err);
              reject(err);
            })
          }))
        }
        Promise.all(stages).then(() => {
          module.app.log.info('Done, waited like a good boy!');
          module.mineWorkflowRun(uri, workflowId);
        });
      }
    })
    .catch(err => {
      module.app.log.error(err)
    })
    /*
    for (var i = 0; i < 5; i++) {
      stages.push(new Promise((resolve, reject) => {
        module.app.log.info('Processing async task: ' + i);
        let index = i;
        setTimeout(() => {
          module.app.log.info('Processing async task complete: ' + index);
          resolve();
        }, i * 10000);
      }))
    }
    // shove in promise functions

    Promise.all(stages).then(() => {
      module.app.log.info('Done, waited like a good boy!');
    });
    */
  }

  module.mineWorkflowRun = function(uri, workflowId) {

    // Mine the stage definitions first.

    module.app.log.debug('mineWorkflowRun(' + uri + ', ' + workflowId + ')');
    // populate the workflow run info using /wfapi/runs and identify the steps from that as well.
    // module.app.log.debug(uri + 'wfapi/runs with token: ' + module.app.token);

    fetch(uri + 'wfapi/runs', Object.assign({ method: 'get' }, module.fetchJenkinsHeaders)).then(resp => resp.json())
    .then(json => {
      //module.app.log.info(json);
      // An array of the past runs (sample had 11, odd number.. not sure if that is the full history)
      for(var i = 0; i < json.length; i++) {
        let entry = json[i];
        let workflowRun = {
          type: 'workflowRun',
          attributes: {
            workflowId: workflowId,
            uri: module.app.config.jenkins.host + entry._links.self.href.replace('wfapi/describe', ''),
            status: entry.status,
            start: entry.startTimeMillis,
            duration: entry.durationMillis
          }
        }

        // Figure out if it exists already.
        fetch(module.app.config.hub.apiHost + '/api/workflowRun/?filter[uri]=' + workflowRun.attributes.uri,
          Object.assign(
            { method: 'get' },
            module.fetchHubHeaders
          )
        )
        .then(respLookup => respLookup.json())
        .then(respLookupJson => {
          //module.app.log.info(respLookupJson);

          if (respLookupJson.data.length == 0) {
            //module.app.log.info('Couldn\'t find item with id: ' + entry.id + ', create it');
            fetch(module.app.config.hub.apiHost + '/api/workflowRun/',
            Object.assign(
              { method: 'post' },
              module.fetchHubHeaders,
              {
                body: JSON.stringify({ data: workflowRun })
              })
            )
            .then(respAdd => respAdd.json())
            .then(respAddJson => {
              //module.app.log.info(respAddJson);
              module.mineStages(workflowId, entry);
            })
          } else {
            //module.app.log.info('Found item with id: ' + entry.id + ', update it');
            workflowRun.id = respLookupJson.data[0].id;
            fetch(module.app.config.hub.apiHost + '/api/workflowRun/' + respLookupJson.data[0].id,
            Object.assign(
              { method: 'patch' },
              module.fetchHubHeaders,
              {
                body: JSON.stringify({ data: workflowRun })
              })
            )
            .then(respAdd => respAdd.json())
            .then(respAddJson => {
              //module.app.log.info(respAddJson);
              module.mineStages(workflowId, entry);
            })
          }
        })
        .catch(err => {
          module.app.log.error(err)
        })
      }
    })
    .catch(err => {
      module.app.log.error(err);
    })
  }

  module.mineStages = function(workflowId, entry) {
    //module.app.log.debug(entry);
    for(let i = 0; i < entry.stages.length; i++) {
      let stageEntry = entry.stages[i];

      let workflowStep = {
        type: 'workflowStep',
        attributes: {
          workflowId: workflowId,
          uri: 'n/a', /* No good URI here but the workflow one */
          name: stageEntry.name,
          description: stageEntry.name + ' description'
        }
      }
      let workflowStepName = stageEntry.name;
      //module.app.log.debug(stage);
      // does it exist by name? no, add it and get id. yes? get id.

      // Deal with the stage definitions first.
      //module.app.log.debug('"' + module.app.config.hub.apiHost + '/api/workflowStep/?filter[name]=' + encodeURI(workflowStepName) + '&filter[workflowId]=' + workflowId + '"');
      fetch(module.app.config.hub.apiHost + '/api/workflowStep/?filter[name]=' + encodeURI(workflowStepName) + '&filter[workflowId]=' + workflowId,
          Object.assign(
            { method: 'get' },
            module.fetchHubHeaders
          )
        )
        .then(respLookup => respLookup.json())
        .then(respLookupJson => {
          //module.app.log.debug(respLookupJson);
          if (respLookupJson.data.length == 0) {
            module.app.log.info('Couldn\'t find workflow step with name: ' + workflowStepName + '! These should all have been present by now.');
          } else {
            module.app.log.info('Found workflow step with name: ' + workflowStepName);

            let stageRun = {
              type: 'workflowStepRun',
              attributes: {
                workflowStepId: respLookupJson.data[0].id,
                status: stageEntry.status,
                start: stageEntry.startTimeMillis,
                duration: stageEntry.durationMillis
              }
            }
            //module.app.log.debug(stageRun);

            module.app.log.debug(module.app.config.hub.apiHost + '/api/workflowStepRun/?filter[workflowStepId]=' + stageRun.attributes.workflowStepId + '&filter[start]=' + stageRun.attributes.start);
            fetch(module.app.config.hub.apiHost + '/api/workflowStepRun/?filter[workflowStepId]=' + stageRun.attributes.workflowStepId + '&filter[start]=' + stageRun.attributes.start,
              Object.assign(
                { method: 'get' },
                module.fetchHubHeaders
              )
            )
            .then(respStepRunLookup => respStepRunLookup.json())
            .then(respStepRunLookupJson => {
              module.app.log.debug(respStepRunLookupJson);
              /*
              if (respStepRunLookupJson.data.length == 0) {
                fetch(module.app.config.hub.apiHost + '/api/workflowStepRun/',
                  Object.assign(
                    { method: 'post' },
                    module.fetchHubHeaders,
                    {
                      body: JSON.stringify({ data: stageRun })
                    }
                  )
                )
                .then(respAdd => respAdd.json())
                .then(respAddJson => {
                  module.app.log.info('Successfully added step run');
                  module.app.log.info(respAddJson);
                })
              }
              */
            })
            .catch(err => {
              module.app.log.error(err)
            })
          }
        })
        .catch(err => {
          module.app.log.error(err)
        })
    }
  }

  module.mineChangeSets = function(entry) {
    module.app.log.debug('mine changesets (not implemented)');
    /*
      Basically will mine a format response like the following
      [
        {
          "kind": "git",
          "commitCount": 1,
          "commits": [
            {
              "commitId": "792e8827dcff06850cfadb2e3bb05a6791a930d4",
              "authorJenkinsId": "Quang.Truong",
              "message": "Select Connected host only",
              "timestamp": 1483573013000,
              "consoleUrl": "/job/FTW/job/WFM/job/WFM-Workflow/145/changes#792e8827dcff06850cfadb2e3bb05a6791a930d4"
            }
          ],
          "consoleUrl": "/job/FTW/job/WFM/job/WFM-Workflow/145/changes"
        }
      ]
    */
  }

  return module;
};<commit_msg>Update workflow step run data mining for proper date format.<commit_after>import fetch from 'node-fetch';
import _ from 'underscore';
import moment from 'moment';

module.exports = function(app) {
  var module = {};

  module.app = app;

  module.mine = function(uri, workflowId) {
    // This will min the stage definition first, then move on to runs.
    module.app.log.debug('mine(uri: ' + uri + ', workflowId: ' + workflowId + ')');

    module.fetchHubHeaders = { headers: { 'Content-Type': 'application/vnd.api+json', 'Authorization': module.app.token } };
    module.fetchJenkinsHeaders = { headers: { 'Content-Type': 'application/vnd.api+json', 'Accept': 'application/vnd.api+json' } };

    let stages = [];

    fetch(uri + 'wfapi/runs', Object.assign({ method: 'get' }, module.fetchJenkinsHeaders)).then(resp => resp.json())
    .then(json => {
     // module.app.log.debug(json);
      if(json.length > 0) {
        // just take the last run to identify stages.
        //let workflowRun = json[0];
        let workflowRun = _.max(json, (run) => run.stages.length);
        //module.app.log.debug(workflowRun.stages);
        for(let i = 0; i < workflowRun.stages.length; i++) {
          //module.app.log.debug(workflowRun.stages[i].name);
          let stageName = workflowRun.stages[i].name;
          let stageOrder = i;
          stages.push(new Promise((resolve, reject) => {
            //module.app.log.info('Processing async task: ' + stageName);
            fetch(module.app.config.hub.apiHost + '/api/workflowStep/?filter[name]=' + stageName + '&filter[workflowId]=' + workflowId,
              Object.assign(
                { method: 'get' },
                module.fetchHubHeaders
              )
            )
            .then(respLookup => respLookup.json())
            .then(respLookupJson => {
              //module.app.log.debug(respLookupJson);
              if (respLookupJson.data.length == 0) {
                // Create it
                var workflowStep = {
                  type: 'workflowStep',
                  attributes: {
                    workflowId: workflowId,
                    uri: 'n/a', /* No good URI here but the workflow one */
                    name: stageName,
                    description: stageName + ' description',
                    order: stageOrder
                  }
                }
                fetch(module.app.config.hub.apiHost + '/api/workflowStep/',
                Object.assign(
                  { method: 'post' },
                  module.fetchHubHeaders,
                  {
                    body: JSON.stringify({ data: workflowStep })
                  })
                )
                .then(respAdd => respAdd.json())
                .then(respAddJson => {
                  //module.app.log.info(respAddJson);
                  resolve();
                })
              } else {
                resolve();
              }
            }).catch(err => {
              module.app.log.error(err);
              reject(err);
            })
          }))
        }
        Promise.all(stages).then(() => {
          module.app.log.info('Done, waited like a good boy!');
          module.mineWorkflowRun(uri, workflowId);
        });
      }
    })
    .catch(err => {
      module.app.log.error(err)
    })
    /*
    for (var i = 0; i < 5; i++) {
      stages.push(new Promise((resolve, reject) => {
        module.app.log.info('Processing async task: ' + i);
        let index = i;
        setTimeout(() => {
          module.app.log.info('Processing async task complete: ' + index);
          resolve();
        }, i * 10000);
      }))
    }
    // shove in promise functions

    Promise.all(stages).then(() => {
      module.app.log.info('Done, waited like a good boy!');
    });
    */
  }

  module.mineWorkflowRun = function(uri, workflowId) {

    // Mine the stage definitions first.

    module.app.log.debug('mineWorkflowRun(' + uri + ', ' + workflowId + ')');
    // populate the workflow run info using /wfapi/runs and identify the steps from that as well.
    // module.app.log.debug(uri + 'wfapi/runs with token: ' + module.app.token);

    fetch(uri + 'wfapi/runs', Object.assign({ method: 'get' }, module.fetchJenkinsHeaders)).then(resp => resp.json())
    .then(json => {
      //module.app.log.info(json);
      // An array of the past runs (sample had 11, odd number.. not sure if that is the full history)
      for(var i = 0; i < json.length; i++) {
        let entry = json[i];
        let workflowRun = {
          type: 'workflowRun',
          attributes: {
            workflowId: workflowId,
            uri: module.app.config.jenkins.host + entry._links.self.href.replace('wfapi/describe', ''),
            status: entry.status,
            start: entry.startTimeMillis,
            duration: entry.durationMillis
          }
        }

        // Figure out if it exists already.
        fetch(module.app.config.hub.apiHost + '/api/workflowRun/?filter[uri]=' + workflowRun.attributes.uri,
          Object.assign(
            { method: 'get' },
            module.fetchHubHeaders
          )
        )
        .then(respLookup => respLookup.json())
        .then(respLookupJson => {
          //module.app.log.info(respLookupJson);

          if (respLookupJson.data.length == 0) {
            //module.app.log.info('Couldn\'t find item with id: ' + entry.id + ', create it');
            fetch(module.app.config.hub.apiHost + '/api/workflowRun/',
            Object.assign(
              { method: 'post' },
              module.fetchHubHeaders,
              {
                body: JSON.stringify({ data: workflowRun })
              })
            )
            .then(respAdd => respAdd.json())
            .then(respAddJson => {
              //module.app.log.info(respAddJson);
              module.mineStages(workflowId, entry);
            })
          } else {
            //module.app.log.info('Found item with id: ' + entry.id + ', update it');
            workflowRun.id = respLookupJson.data[0].id;
            fetch(module.app.config.hub.apiHost + '/api/workflowRun/' + respLookupJson.data[0].id,
            Object.assign(
              { method: 'patch' },
              module.fetchHubHeaders,
              {
                body: JSON.stringify({ data: workflowRun })
              })
            )
            .then(respAdd => respAdd.json())
            .then(respAddJson => {
              //module.app.log.info(respAddJson);
              module.mineStages(workflowId, entry);
            })
          }
        })
        .catch(err => {
          module.app.log.error(err)
        })
      }
    })
    .catch(err => {
      module.app.log.error(err);
    })
  }

  module.mineStages = function(workflowId, entry) {
    //module.app.log.debug(entry);
    for(let i = 0; i < entry.stages.length; i++) {
      let stageEntry = entry.stages[i];

      let workflowStep = {
        type: 'workflowStep',
        attributes: {
          workflowId: workflowId,
          uri: 'n/a', /* No good URI here but the workflow one */
          name: stageEntry.name,
          description: stageEntry.name + ' description'
        }
      }
      let workflowStepName = stageEntry.name;
      //module.app.log.debug(stage);
      // does it exist by name? no, add it and get id. yes? get id.

      // Deal with the stage definitions first.
      //module.app.log.debug('"' + module.app.config.hub.apiHost + '/api/workflowStep/?filter[name]=' + encodeURI(workflowStepName) + '&filter[workflowId]=' + workflowId + '"');
      fetch(module.app.config.hub.apiHost + '/api/workflowStep/?filter[name]=' + encodeURI(workflowStepName) + '&filter[workflowId]=' + workflowId,
          Object.assign(
            { method: 'get' },
            module.fetchHubHeaders
          )
        )
        .then(respLookup => respLookup.json())
        .then(respLookupJson => {
          //module.app.log.debug(respLookupJson);
          if (respLookupJson.data.length == 0) {
            module.app.log.info('Couldn\'t find workflow step with name: ' + workflowStepName + '! These should all have been present by now.');
          } else {
            module.app.log.info('Found workflow step with name: ' + workflowStepName);

            let stageRun = {
              type: 'workflowStepRun',
              attributes: {
                workflowStepId: respLookupJson.data[0].id,
                status: stageEntry.status,
                start: stageEntry.startTimeMillis,
                duration: stageEntry.durationMillis
              }
            }
            //module.app.log.debug(stageRun);

            // Sat, 12 Aug 1995 13:30:00 GMT
            let startDateFormattedForKatharsisStupidity = moment(stageRun.attributes.start).format("ddd, D MMM YYYY HH:mm:ss z");

            module.app.log.debug(module.app.config.hub.apiHost + '/api/workflowStepRun/?filter[workflowStepId]=' + stageRun.attributes.workflowStepId + '&filter[start]=' + startDateFormattedForKatharsisStupidity);
            fetch(module.app.config.hub.apiHost + '/api/workflowStepRun/?filter[workflowStepId]=' + stageRun.attributes.workflowStepId + '&filter[start]=' + startDateFormattedForKatharsisStupidity,
              Object.assign(
                { method: 'get' },
                module.fetchHubHeaders
              )
            )
            .then(respStepRunLookup => respStepRunLookup.json())
            .then(respStepRunLookupJson => {
              module.app.log.debug(respStepRunLookupJson);

              if (respStepRunLookupJson.data.length == 0) {
                fetch(module.app.config.hub.apiHost + '/api/workflowStepRun/',
                  Object.assign(
                    { method: 'post' },
                    module.fetchHubHeaders,
                    {
                      body: JSON.stringify({ data: stageRun })
                    }
                  )
                )
                .then(respAdd => respAdd.json())
                .then(respAddJson => {
                  module.app.log.info('Successfully added step run');
                  module.app.log.info(respAddJson);
                })
              }
            })
            .catch(err => {
              module.app.log.error(err)
            })
          }
        })
        .catch(err => {
          module.app.log.error(err)
        })
    }
  }

  module.mineChangeSets = function(entry) {
    module.app.log.debug('mine changesets (not implemented)');
    /*
      Basically will mine a format response like the following
      [
        {
          "kind": "git",
          "commitCount": 1,
          "commits": [
            {
              "commitId": "792e8827dcff06850cfadb2e3bb05a6791a930d4",
              "authorJenkinsId": "Quang.Truong",
              "message": "Select Connected host only",
              "timestamp": 1483573013000,
              "consoleUrl": "/job/FTW/job/WFM/job/WFM-Workflow/145/changes#792e8827dcff06850cfadb2e3bb05a6791a930d4"
            }
          ],
          "consoleUrl": "/job/FTW/job/WFM/job/WFM-Workflow/145/changes"
        }
      ]
    */
  }

  return module;
};<|endoftext|>


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

/**
 * @constructor
 * @implements {WebInspector.TargetManager.Observer}
 */
WebInspector.CSSWorkspaceBinding = function()
{
    /** @type {!Map.<!WebInspector.Target, !WebInspector.CSSWorkspaceBinding.TargetInfo>} */
    this._targetToTargetInfo = new Map();
    WebInspector.targetManager.observeTargets(this);

    WebInspector.targetManager.addModelListener(WebInspector.ResourceTreeModel, WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._mainFrameCreatedOrNavigated, this);
}

WebInspector.CSSWorkspaceBinding.prototype = {
    /**
     * @param {!WebInspector.Target} target
     */
    targetAdded: function(target)
    {
        this._targetToTargetInfo.put(target, new WebInspector.CSSWorkspaceBinding.TargetInfo(target, WebInspector.workspace, WebInspector.networkWorkspaceBinding));
    },

    /**
     * @param {!WebInspector.Target} target
     */
    targetRemoved: function(target)
    {
        this._targetToTargetInfo.remove(target)._dispose();
    },

    /**
     * @param {!WebInspector.CSSStyleSheetHeader} header
     * @param {!WebInspector.SourceMapping} mapping
     */
    pushSourceMapping: function(header, mapping)
    {
        this._ensureInfoForHeader(header)._pushSourceMapping(mapping);
    },

    /**
     * @param {!WebInspector.CSSStyleSheetHeader} header
     * @return {?WebInspector.CSSWorkspaceBinding.HeaderInfo}
     */
    _headerInfo: function(header)
    {
        var map = this._targetToTargetInfo.get(header.target());
        return map._headerInfo(header.id) || null;
    },

    /**
     * @param {!WebInspector.CSSStyleSheetHeader} header
     * @return {!WebInspector.CSSWorkspaceBinding.HeaderInfo}
     */
    _ensureInfoForHeader: function(header)
    {
        var targetInfo = this._targetToTargetInfo.get(header.target());
        if (!targetInfo) {
            targetInfo = new WebInspector.CSSWorkspaceBinding.TargetInfo(header.target(), WebInspector.workspace, WebInspector.networkWorkspaceBinding);
            this._targetToTargetInfo.put(header.target(), targetInfo);
        }
        return targetInfo._ensureInfoForHeader(header);
    },

    /**
     * @param {!WebInspector.Event} event
     */
    _mainFrameCreatedOrNavigated: function(event)
    {
        var target = /** @type {!WebInspector.ResourceTreeModel} */ (event.target).target();
        var info = this._targetToTargetInfo.remove(target);
        if (info)
            info._dispose();
        this._targetToTargetInfo.put(target, new WebInspector.CSSWorkspaceBinding.TargetInfo(target, WebInspector.workspace, WebInspector.networkWorkspaceBinding));
    },

    /**
     * @param {!WebInspector.CSSStyleSheetHeader} header
     */
    updateLocations: function(header)
    {
        var info = this._headerInfo(header);
        if (info)
            info._updateLocations();
    },

    /**
     * @param {!WebInspector.CSSLocation} rawLocation
     * @param {function(!WebInspector.UILocation):(boolean|undefined)} updateDelegate
     * @return {!WebInspector.CSSWorkspaceBinding.LiveLocation}
     */
    createLiveLocation: function(rawLocation, updateDelegate)
    {
        var header = rawLocation.styleSheetId ? rawLocation.target().cssModel.styleSheetHeaderForId(rawLocation.styleSheetId) : null;
        return new WebInspector.CSSWorkspaceBinding.LiveLocation(rawLocation.target().cssModel, header, rawLocation, updateDelegate);
    },

    /**
     * @param {!WebInspector.CSSWorkspaceBinding.LiveLocation} location
     */
    _addLiveLocation: function(location)
    {
        this._ensureInfoForHeader(location._header)._addLocation(location);
    },

    /**
     * @param {!WebInspector.CSSWorkspaceBinding.LiveLocation} location
     */
    _removeLiveLocation: function(location)
    {
        var info = this._headerInfo(location._header);
        if (info)
            info._removeLocation(location);
    },

    /**
     * @param {!WebInspector.CSSProperty} cssProperty
     * @param {boolean} forName
     * @return {?WebInspector.UILocation}
     */
    propertyUILocation: function(cssProperty, forName)
    {
        var style = cssProperty.ownerStyle;
        if (!style || !style.parentRule || !style.styleSheetId)
            return null;

        var range = cssProperty.range;
        if (!range)
            return null;

        var url = style.parentRule.resourceURL();
        if (!url)
            return null;

        var line = forName ? range.startLine : range.endLine;
        // End of range is exclusive, so subtract 1 from the end offset.
        var column = forName ? range.startColumn : range.endColumn - (cssProperty.text && cssProperty.text.endsWith(";") ? 2 : 1);
        var rawLocation = new WebInspector.CSSLocation(style.target(), style.styleSheetId, url, line, column);
        return this.rawLocationToUILocation(rawLocation);
    },

    /**
     * @param {?WebInspector.CSSLocation} rawLocation
     * @return {?WebInspector.UILocation}
     */
    rawLocationToUILocation: function(rawLocation)
    {
        if (!rawLocation)
            return null;
        var cssModel = rawLocation.target().cssModel;
        var frameIdToSheetIds = cssModel.styleSheetIdsByFrameIdForURL(rawLocation.url);
        if (!Object.values(frameIdToSheetIds).length)
            return null;
        var styleSheetIds = [];
        for (var frameId in frameIdToSheetIds)
            styleSheetIds = styleSheetIds.concat(frameIdToSheetIds[frameId]);
        var uiLocation;
        for (var i = 0; !uiLocation && i < styleSheetIds.length; ++i) {
            var header = cssModel.styleSheetHeaderForId(styleSheetIds[i]);
            if (!header)
                continue;
            var info = this._headerInfo(header);
            if (info)
                uiLocation = info._rawLocationToUILocation(rawLocation.lineNumber, rawLocation.columnNumber);
        }
        return uiLocation || null;
    }
}

/**
 * @constructor
 * @param {!WebInspector.Target} target
 * @param {!WebInspector.Workspace} workspace
 * @param {!WebInspector.NetworkWorkspaceBinding} networkWorkspaceBinding
 */
WebInspector.CSSWorkspaceBinding.TargetInfo = function(target, workspace, networkWorkspaceBinding)
{
    this._target = target;
    this._workspace = workspace;

    var cssModel = target.cssModel;
    this._stylesSourceMapping = new WebInspector.StylesSourceMapping(cssModel, workspace);
    this._sassSourceMapping = new WebInspector.SASSSourceMapping(cssModel, workspace, networkWorkspaceBinding);

    /** @type {!StringMap.<!WebInspector.CSSWorkspaceBinding.HeaderInfo>} */
    this._headerInfoById = new StringMap();

    cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this._styleSheetAdded, this);
    cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this);
}

WebInspector.CSSWorkspaceBinding.TargetInfo.prototype = {
    /**
     * @param {!WebInspector.Event} event
     */
    _styleSheetAdded: function(event)
    {
        var header = /** @type {!WebInspector.CSSStyleSheetHeader} */ (event.data);
        this._stylesSourceMapping.addHeader(header);
        this._sassSourceMapping.addHeader(header);
    },

    /**
     * @param {!WebInspector.Event} event
     */
    _styleSheetRemoved: function(event)
    {
        var header = /** @type {!WebInspector.CSSStyleSheetHeader} */ (event.data);
        this._stylesSourceMapping.removeHeader(header);
        this._sassSourceMapping.removeHeader(header);
        this._headerInfoById.remove(header.id);
    },

    /**
     * @param {!CSSAgent.StyleSheetId} id
     */
    _headerInfo: function(id)
    {
        return this._headerInfoById.get(id);
    },

    _ensureInfoForHeader: function(header)
    {
        var info = this._headerInfoById.get(header.id);
        if (!info) {
            info = new WebInspector.CSSWorkspaceBinding.HeaderInfo(header);
            this._headerInfoById.put(header.id, info);
        }
        return info;
    },

    _dispose: function()
    {
        this._target.cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this._styleSheetAdded, this);
        this._target.cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this);
    }
}

/**
 * @constructor
 * @param {!WebInspector.CSSStyleSheetHeader} header
 */
WebInspector.CSSWorkspaceBinding.HeaderInfo = function(header)
{
    this._header = header;

    /** @type {!Array.<!WebInspector.SourceMapping>} */
    this._sourceMappings = [];

    /** @type {!Set.<!WebInspector.LiveLocation>} */
    this._locations = new Set();
}

WebInspector.CSSWorkspaceBinding.HeaderInfo.prototype = {
    /**
     * @param {!WebInspector.LiveLocation} location
     */
    _addLocation: function(location)
    {
        this._locations.add(location);
        location.update();
    },

    /**
     * @param {!WebInspector.LiveLocation} location
     */
    _removeLocation: function(location)
    {
        this._locations.remove(location);
    },

    _updateLocations: function()
    {
        var items = this._locations.values();
        for (var i = 0; i < items.length; ++i)
            items[i].update();
    },

    /**
     * @param {number} lineNumber
     * @param {number=} columnNumber
     * @return {?WebInspector.UILocation}
     */
    _rawLocationToUILocation: function(lineNumber, columnNumber)
    {
        var uiLocation = null;
        var rawLocation = new WebInspector.CSSLocation(this._header.target(), this._header.id, this._header.resourceURL(), lineNumber, columnNumber);
        for (var i = this._sourceMappings.length - 1; !uiLocation && i >= 0; --i)
            uiLocation = this._sourceMappings[i].rawLocationToUILocation(rawLocation);
        return uiLocation;
    },

    /**
     * @param {!WebInspector.SourceMapping} sourceMapping
     */
    _pushSourceMapping: function(sourceMapping)
    {
        this._sourceMappings.push(sourceMapping);
        this._updateLocations();
    }
}

/**
 * @constructor
 * @extends {WebInspector.LiveLocation}
 * @param {!WebInspector.CSSStyleModel} cssModel
 * @param {?WebInspector.CSSStyleSheetHeader} header
 * @param {!WebInspector.CSSLocation} rawLocation
 * @param {function(!WebInspector.UILocation):(boolean|undefined)} updateDelegate
 */
WebInspector.CSSWorkspaceBinding.LiveLocation = function(cssModel, header, rawLocation, updateDelegate)
{
    WebInspector.LiveLocation.call(this, rawLocation, updateDelegate);
    this._cssModel = cssModel;
    if (!header)
        this._clearStyleSheet();
    else
        this._setStyleSheet(header);
}

WebInspector.CSSWorkspaceBinding.LiveLocation.prototype = {
    /**
     * @param {!WebInspector.Event} event
     */
    _styleSheetAdded: function(event)
    {
        console.assert(!this._header);
        var header = /** @type {!WebInspector.CSSStyleSheetHeader} */ (event.data);
        if (header.sourceURL && header.sourceURL === this.rawLocation().url)
            this._setStyleSheet(header);
    },

    /**
     * @param {!WebInspector.Event} event
     */
    _styleSheetRemoved: function(event)
    {
        console.assert(this._header);
        var header = /** @type {!WebInspector.CSSStyleSheetHeader} */ (event.data);
        if (this._header !== header)
            return;
        WebInspector.cssWorkspaceBinding._removeLiveLocation(this);
        this._clearStyleSheet();
    },

    /**
     * @param {!WebInspector.CSSStyleSheetHeader} header
     */
    _setStyleSheet: function(header)
    {
        this._header = header;
        WebInspector.cssWorkspaceBinding._addLiveLocation(this);
        this._cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this._styleSheetAdded, this);
        this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this);
    },

    _clearStyleSheet: function()
    {
        delete this._header;
        this._cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this);
        this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this._styleSheetAdded, this);
    },

    /**
     * @return {?WebInspector.UILocation}
     */
    uiLocation: function()
    {
        var cssLocation = /** @type WebInspector.CSSLocation */ (this.rawLocation());
        if (this._header) {
            var headerInfo = WebInspector.cssWorkspaceBinding._headerInfo(this._header);
            return headerInfo._rawLocationToUILocation(cssLocation.lineNumber, cssLocation.columnNumber);
        }
        var uiSourceCode = WebInspector.workspace.uiSourceCodeForURL(cssLocation.url);
        if (!uiSourceCode)
            return null;
        return uiSourceCode.uiLocation(cssLocation.lineNumber, cssLocation.columnNumber);
    },

    dispose: function()
    {
        WebInspector.LiveLocation.prototype.dispose.call(this);
        if (this._header)
            WebInspector.cssWorkspaceBinding._removeLiveLocation(this);
        this._cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this._styleSheetAdded, this);
        this._cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this);
    },

    __proto__: WebInspector.LiveLocation.prototype
}

/**
 * @type {!WebInspector.CSSWorkspaceBinding}
 */
WebInspector.cssWorkspaceBinding;
<commit_msg>DevTools: Do not re-create CSSWorkspaceBinding TargetInfo on MainFrameNavigated<commit_after>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/**
 * @constructor
 * @implements {WebInspector.TargetManager.Observer}
 */
WebInspector.CSSWorkspaceBinding = function()
{
    /** @type {!Map.<!WebInspector.Target, !WebInspector.CSSWorkspaceBinding.TargetInfo>} */
    this._targetToTargetInfo = new Map();
    WebInspector.targetManager.observeTargets(this);

    WebInspector.targetManager.addModelListener(WebInspector.ResourceTreeModel, WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._mainFrameCreatedOrNavigated, this);
}

WebInspector.CSSWorkspaceBinding.prototype = {
    /**
     * @param {!WebInspector.Target} target
     */
    targetAdded: function(target)
    {
        this._targetToTargetInfo.put(target, new WebInspector.CSSWorkspaceBinding.TargetInfo(target, WebInspector.workspace, WebInspector.networkWorkspaceBinding));
    },

    /**
     * @param {!WebInspector.Target} target
     */
    targetRemoved: function(target)
    {
        this._targetToTargetInfo.remove(target)._dispose();
    },

    /**
     * @param {!WebInspector.CSSStyleSheetHeader} header
     * @param {!WebInspector.SourceMapping} mapping
     */
    pushSourceMapping: function(header, mapping)
    {
        this._ensureInfoForHeader(header)._pushSourceMapping(mapping);
    },

    /**
     * @param {!WebInspector.CSSStyleSheetHeader} header
     * @return {?WebInspector.CSSWorkspaceBinding.HeaderInfo}
     */
    _headerInfo: function(header)
    {
        var map = this._targetToTargetInfo.get(header.target());
        return map._headerInfo(header.id) || null;
    },

    /**
     * @param {!WebInspector.CSSStyleSheetHeader} header
     * @return {!WebInspector.CSSWorkspaceBinding.HeaderInfo}
     */
    _ensureInfoForHeader: function(header)
    {
        var targetInfo = this._targetToTargetInfo.get(header.target());
        if (!targetInfo) {
            targetInfo = new WebInspector.CSSWorkspaceBinding.TargetInfo(header.target(), WebInspector.workspace, WebInspector.networkWorkspaceBinding);
            this._targetToTargetInfo.put(header.target(), targetInfo);
        }
        return targetInfo._ensureInfoForHeader(header);
    },

    /**
     * @param {!WebInspector.Event} event
     */
    _mainFrameCreatedOrNavigated: function(event)
    {
        var target = /** @type {!WebInspector.ResourceTreeModel} */ (event.target).target();
        this._targetToTargetInfo.get(target)._reset();
    },

    /**
     * @param {!WebInspector.CSSStyleSheetHeader} header
     */
    updateLocations: function(header)
    {
        var info = this._headerInfo(header);
        if (info)
            info._updateLocations();
    },

    /**
     * @param {!WebInspector.CSSLocation} rawLocation
     * @param {function(!WebInspector.UILocation):(boolean|undefined)} updateDelegate
     * @return {!WebInspector.CSSWorkspaceBinding.LiveLocation}
     */
    createLiveLocation: function(rawLocation, updateDelegate)
    {
        var header = rawLocation.styleSheetId ? rawLocation.target().cssModel.styleSheetHeaderForId(rawLocation.styleSheetId) : null;
        return new WebInspector.CSSWorkspaceBinding.LiveLocation(rawLocation.target().cssModel, header, rawLocation, updateDelegate);
    },

    /**
     * @param {!WebInspector.CSSWorkspaceBinding.LiveLocation} location
     */
    _addLiveLocation: function(location)
    {
        this._ensureInfoForHeader(location._header)._addLocation(location);
    },

    /**
     * @param {!WebInspector.CSSWorkspaceBinding.LiveLocation} location
     */
    _removeLiveLocation: function(location)
    {
        var info = this._headerInfo(location._header);
        if (info)
            info._removeLocation(location);
    },

    /**
     * @param {!WebInspector.CSSProperty} cssProperty
     * @param {boolean} forName
     * @return {?WebInspector.UILocation}
     */
    propertyUILocation: function(cssProperty, forName)
    {
        var style = cssProperty.ownerStyle;
        if (!style || !style.parentRule || !style.styleSheetId)
            return null;

        var range = cssProperty.range;
        if (!range)
            return null;

        var url = style.parentRule.resourceURL();
        if (!url)
            return null;

        var line = forName ? range.startLine : range.endLine;
        // End of range is exclusive, so subtract 1 from the end offset.
        var column = forName ? range.startColumn : range.endColumn - (cssProperty.text && cssProperty.text.endsWith(";") ? 2 : 1);
        var rawLocation = new WebInspector.CSSLocation(style.target(), style.styleSheetId, url, line, column);
        return this.rawLocationToUILocation(rawLocation);
    },

    /**
     * @param {?WebInspector.CSSLocation} rawLocation
     * @return {?WebInspector.UILocation}
     */
    rawLocationToUILocation: function(rawLocation)
    {
        if (!rawLocation)
            return null;
        var cssModel = rawLocation.target().cssModel;
        var frameIdToSheetIds = cssModel.styleSheetIdsByFrameIdForURL(rawLocation.url);
        if (!Object.values(frameIdToSheetIds).length)
            return null;
        var styleSheetIds = [];
        for (var frameId in frameIdToSheetIds)
            styleSheetIds = styleSheetIds.concat(frameIdToSheetIds[frameId]);
        var uiLocation;
        for (var i = 0; !uiLocation && i < styleSheetIds.length; ++i) {
            var header = cssModel.styleSheetHeaderForId(styleSheetIds[i]);
            if (!header)
                continue;
            var info = this._headerInfo(header);
            if (info)
                uiLocation = info._rawLocationToUILocation(rawLocation.lineNumber, rawLocation.columnNumber);
        }
        return uiLocation || null;
    }
}

/**
 * @constructor
 * @param {!WebInspector.Target} target
 * @param {!WebInspector.Workspace} workspace
 * @param {!WebInspector.NetworkWorkspaceBinding} networkWorkspaceBinding
 */
WebInspector.CSSWorkspaceBinding.TargetInfo = function(target, workspace, networkWorkspaceBinding)
{
    this._target = target;
    this._workspace = workspace;

    var cssModel = target.cssModel;
    this._stylesSourceMapping = new WebInspector.StylesSourceMapping(cssModel, workspace);
    this._sassSourceMapping = new WebInspector.SASSSourceMapping(cssModel, workspace, networkWorkspaceBinding);

    /** @type {!StringMap.<!WebInspector.CSSWorkspaceBinding.HeaderInfo>} */
    this._headerInfoById = new StringMap();

    cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this._styleSheetAdded, this);
    cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this);
}

WebInspector.CSSWorkspaceBinding.TargetInfo.prototype = {
    /**
     * @param {!WebInspector.Event} event
     */
    _styleSheetAdded: function(event)
    {
        var header = /** @type {!WebInspector.CSSStyleSheetHeader} */ (event.data);
        this._stylesSourceMapping.addHeader(header);
        this._sassSourceMapping.addHeader(header);
    },

    /**
     * @param {!WebInspector.Event} event
     */
    _styleSheetRemoved: function(event)
    {
        var header = /** @type {!WebInspector.CSSStyleSheetHeader} */ (event.data);
        this._stylesSourceMapping.removeHeader(header);
        this._sassSourceMapping.removeHeader(header);
        this._headerInfoById.remove(header.id);
    },

    /**
     * @param {!CSSAgent.StyleSheetId} id
     */
    _headerInfo: function(id)
    {
        return this._headerInfoById.get(id);
    },

    _ensureInfoForHeader: function(header)
    {
        var info = this._headerInfoById.get(header.id);
        if (!info) {
            info = new WebInspector.CSSWorkspaceBinding.HeaderInfo(header);
            this._headerInfoById.put(header.id, info);
        }
        return info;
    },

    _dispose: function()
    {
        this._reset();
        this._target.cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this._styleSheetAdded, this);
        this._target.cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this);
    },

    _reset: function()
    {
        this._headerInfoById.clear();
    }
}

/**
 * @constructor
 * @param {!WebInspector.CSSStyleSheetHeader} header
 */
WebInspector.CSSWorkspaceBinding.HeaderInfo = function(header)
{
    this._header = header;

    /** @type {!Array.<!WebInspector.SourceMapping>} */
    this._sourceMappings = [];

    /** @type {!Set.<!WebInspector.LiveLocation>} */
    this._locations = new Set();
}

WebInspector.CSSWorkspaceBinding.HeaderInfo.prototype = {
    /**
     * @param {!WebInspector.LiveLocation} location
     */
    _addLocation: function(location)
    {
        this._locations.add(location);
        location.update();
    },

    /**
     * @param {!WebInspector.LiveLocation} location
     */
    _removeLocation: function(location)
    {
        this._locations.remove(location);
    },

    _updateLocations: function()
    {
        var items = this._locations.values();
        for (var i = 0; i < items.length; ++i)
            items[i].update();
    },

    /**
     * @param {number} lineNumber
     * @param {number=} columnNumber
     * @return {?WebInspector.UILocation}
     */
    _rawLocationToUILocation: function(lineNumber, columnNumber)
    {
        var uiLocation = null;
        var rawLocation = new WebInspector.CSSLocation(this._header.target(), this._header.id, this._header.resourceURL(), lineNumber, columnNumber);
        for (var i = this._sourceMappings.length - 1; !uiLocation && i >= 0; --i)
            uiLocation = this._sourceMappings[i].rawLocationToUILocation(rawLocation);
        return uiLocation;
    },

    /**
     * @param {!WebInspector.SourceMapping} sourceMapping
     */
    _pushSourceMapping: function(sourceMapping)
    {
        this._sourceMappings.push(sourceMapping);
        this._updateLocations();
    }
}

/**
 * @constructor
 * @extends {WebInspector.LiveLocation}
 * @param {!WebInspector.CSSStyleModel} cssModel
 * @param {?WebInspector.CSSStyleSheetHeader} header
 * @param {!WebInspector.CSSLocation} rawLocation
 * @param {function(!WebInspector.UILocation):(boolean|undefined)} updateDelegate
 */
WebInspector.CSSWorkspaceBinding.LiveLocation = function(cssModel, header, rawLocation, updateDelegate)
{
    WebInspector.LiveLocation.call(this, rawLocation, updateDelegate);
    this._cssModel = cssModel;
    if (!header)
        this._clearStyleSheet();
    else
        this._setStyleSheet(header);
}

WebInspector.CSSWorkspaceBinding.LiveLocation.prototype = {
    /**
     * @param {!WebInspector.Event} event
     */
    _styleSheetAdded: function(event)
    {
        console.assert(!this._header);
        var header = /** @type {!WebInspector.CSSStyleSheetHeader} */ (event.data);
        if (header.sourceURL && header.sourceURL === this.rawLocation().url)
            this._setStyleSheet(header);
    },

    /**
     * @param {!WebInspector.Event} event
     */
    _styleSheetRemoved: function(event)
    {
        console.assert(this._header);
        var header = /** @type {!WebInspector.CSSStyleSheetHeader} */ (event.data);
        if (this._header !== header)
            return;
        WebInspector.cssWorkspaceBinding._removeLiveLocation(this);
        this._clearStyleSheet();
    },

    /**
     * @param {!WebInspector.CSSStyleSheetHeader} header
     */
    _setStyleSheet: function(header)
    {
        this._header = header;
        WebInspector.cssWorkspaceBinding._addLiveLocation(this);
        this._cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this._styleSheetAdded, this);
        this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this);
    },

    _clearStyleSheet: function()
    {
        delete this._header;
        this._cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this);
        this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this._styleSheetAdded, this);
    },

    /**
     * @return {?WebInspector.UILocation}
     */
    uiLocation: function()
    {
        var cssLocation = /** @type WebInspector.CSSLocation */ (this.rawLocation());
        if (this._header) {
            var headerInfo = WebInspector.cssWorkspaceBinding._headerInfo(this._header);
            return headerInfo._rawLocationToUILocation(cssLocation.lineNumber, cssLocation.columnNumber);
        }
        var uiSourceCode = WebInspector.workspace.uiSourceCodeForURL(cssLocation.url);
        if (!uiSourceCode)
            return null;
        return uiSourceCode.uiLocation(cssLocation.lineNumber, cssLocation.columnNumber);
    },

    dispose: function()
    {
        WebInspector.LiveLocation.prototype.dispose.call(this);
        if (this._header)
            WebInspector.cssWorkspaceBinding._removeLiveLocation(this);
        this._cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this._styleSheetAdded, this);
        this._cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this);
    },

    __proto__: WebInspector.LiveLocation.prototype
}

/**
 * @type {!WebInspector.CSSWorkspaceBinding}
 */
WebInspector.cssWorkspaceBinding;
<|endoftext|>