<commit_before>/*
 @author Zakai Hamilton
 @component StorageDB
 */

screens.storage.db = function StorageDB(me, { core, db }) {
    me.init = async function () {
        me.mongodb = require("mongodb");
        me.clusterHandle = null;
        core.mutex.enable(me.id, true);
        me.keys = await core.private.keys("mongodb");
    };
    me.supported = function () {
        return !(!me.keys);
    };
    me.cluster = async function () {
        if (!me.keys) {
            me.keys = await core.private.keys("mongodb");
            if (!me.keys) {
                throw "No private keys for database";
            }
        }
        var clusterHandle = null;
        me.log("waiting to connect to cluster...");
        var unlock = await core.mutex.lock(me.id);
        try {
            clusterHandle = me.clusterHandle;
            if (clusterHandle) {
                unlock();
                return clusterHandle;
            }
            var url = me.keys.url;
            me.log("connecting to cluster: " + url);
            clusterHandle = await me.mongodb.MongoClient.connect(url, { useUnifiedTopology: true, useNewUrlParser: true });
            me.clusterHandle = clusterHandle;
            me.log("connected to cluster: " + url);
        }
        finally {
            unlock();
        }
        return clusterHandle;
    };
    me.database = async function (name) {
        var cluster = await me.cluster();
        var db = null;
        var info = me.keys[name];
        if (!info) {
            var err = name + " mongodb key not defined in private";
            me.log_error(err);
            throw err;
        }
        db = cluster.db(info.db);
        return db;
    };
    me.collection = async function (location) {
        var db = await me.database(location.db);
        if (!db) {
            throw "Cannot find database for location: " + location.toString();
        }
        var collection = await new Promise((resolve, reject) => {
            db.collection(location.collection, { strict: location.options ? true : false }, async (error, handle) => {
                if (error) {
                    try {
                        handle = await db.createCollection(location.collection, location.options);
                        resolve(handle);
                    }
                    catch (createError) {
                        try {
                            handle = await db.collection(location.collection);
                        }
                        catch (getError) {
                            me.clusterHandle = null;
                            reject(createError);
                        }
                    }
                }
                else {
                    resolve(handle);
                }
            });
        });
        if (!collection) {
            throw "Cannot find collection for location: " + location.collection;
        }
        if (location.indexes) {
            for (let index of location.indexes) {
                collection.createIndex(index);
            }
            location.indexes = null;
        }
        return collection;
    };
    me.objectId = function (id) {
        id = id.toString();
        var object = me.mongodb.ObjectID(id);
        return object;
    };
    me.findByIds = async function (location, ids) {
        var collection = await me.collection(location);
        ids = ids.map(id => id.toString());
        var results = await collection.find({ "_id": { "$in": ids } }).toArray();
        return results;
    };
    me.findById = async function (location, id) {
        var query = { _id: id };
        var [array, hash] = me.getCache(location, query, "find");
        if (array) {
            return array;
        }
        var collection = await me.collection(location);
        var result = await core.util.performance(location.componentId + ".findById: " + id, async () => {
            return await collection.findOne(query);
        });
        me.setCache(location, hash, result);
        return result;
    };
    me.find = async function (location, query) {
        var [array, hash] = me.getCache(location, query, "find");
        if (array) {
            return array;
        }
        var collection = await me.collection(location);
        var result = await core.util.performance(location.componentId + ".find: " + JSON.stringify(query), async () => {
            return await collection.findOne(query);
        });
        me.setCache(location, hash, result);
        return result;
    };
    me.store = async function (location, listOrSingle) {
        var collection = await me.collection(location);
        var isSingle = false;
        var list = listOrSingle;
        if (!Array.isArray(listOrSingle)) {
            isSingle = true;
            list = [listOrSingle];
        }
        for (var data of list) {
            if (data) {
                if (!data._id) {
                    data._id = me.mongodb.ObjectID().toString();
                }
                if (data._id) {
                    await collection.replaceOne({ _id: data._id }, data, { upsert: true });
                }
            }
        }
        listOrSingle = list;
        if (isSingle) {
            listOrSingle = list[0];
        }
        me.notifyCache(location);
        return listOrSingle;
    };
    me.push = async function (location, data) {
        var collection = await me.collection(location);
        var isArray = true;
        if (!Array.isArray(data)) {
            isArray = true;
            data = [data];
        }
        data.map(async data => {
            if (data) {
                if (!data._id) {
                    data._id = me.mongodb.ObjectID().toString();
                }
                if (data._id) {
                    await collection.insertOne(data);
                }
            }
        });
        if (!isArray) {
            data = data[0];
        }
        me.notifyCache(location);
        return data;
    };
    me.remove = async function (location, query, removeOne = true) {
        var collection = await me.collection(location);
        var result = null;
        if (removeOne) {
            result = await collection.deleteOne(query);
        }
        else {
            if (location.options && location.options.capped) {
                result = await collection.drop();
                let db = await me.database(location.db);
                await db.createCollection(location.collection, location.options);
            }
            else {
                result = await collection.deleteMany(query);
            }
        }
        me.notifyCache(location);
        if (result) {
            delete result.connection;
        }
        return result;
    };
    me.list = async function (location, query = {}, params) {
        var [array, hash, queryString] = me.getCache(location, query, params);
        if (array) {
            return array;
        }
        var collection = await me.collection(location);
        array = await core.util.performance(location.componentId + ".list: " + queryString, async () => {
            var cursor = await collection.find(query);
            if (params) {
                for (var param in params) {
                    cursor = cursor[param](params[param]);
                }
            }
            const items = await cursor.toArray();
            if (params && params.project && params.project.user) {
                const users = await db.shared.user.list();
                for (const item of items) {
                    const user = users.find(user => user.user === item.user);
                    item.user = user ? user.name.split("@")[0] : "Unknown";
                }
            }
            return items;
        }, 500);
        me.setCache(location, hash, array);
        return array;
    };
    me.use = async function (location, query, data) {
        if (!data) {
            return me.remove(location, query);
        }
        data = Object.assign({}, query, data);
        delete data._id;
        var collection = await me.collection(location);
        var result = await collection.replaceOne(query, data, { upsert: true });
        me.notifyCache(location);
        if (result) {
            delete result.connection;
        }
        return result;
    };
    me.createIndex = async function (location, index) {
        var collection = await me.collection(location);
        collection.createIndex(index);
    };
    me.queryAsString = function (query) {
        var string = JSON.stringify(core.json.map(query, item => {
            if (item && item.source) {
                return item.source;
            }
            return item;
        }));
        return string;
    };
    me.getCache = function (location, ...params) {
        var result = null;
        var string = me.queryAsString(params);
        var hash = core.string.hash(string);
        if (location.cache) {
            result = location.cache[hash];
        }
        return [result, hash, string];
    };
    me.setCache = function (location, hash, value) {
        if (location.cache) {
            location.cache[hash] = value;
        }
    };
    me.notifyCache = function (location) {
        if (location.cache && location.componentId) {
            me.emptyCache(location);
            if (!location.timer) {
                location.timer = setTimeout(async () => {
                    location.timer = null;
                    await db.events.msg.send(location.componentId + ".emptyCache");
                }, 5000);
            }
        }
    };
    me.emptyCache = function (location) {
        if (location.cache) {
            location.cache = {};
        }
    };
    me.handle = async function (location, query, callback) {
        var data = await me.find(location, query);
        if (!data) {
            data = await callback();
        }
        return data;
    };
    me.extension = function (component) {
        var getLocation = function (name) {
            var location = {};
            var tokens = name.split(".");
            location.collection = tokens.pop();
            location.db = tokens.pop();
            location.options = component.options;
            location.indexes = component.indexes;
            location.cache = component.cache;
            location.componentId = component.id;
            return location;
        };
        var mapping = [
            "remove",
            "store",
            "findById",
            "find",
            "use",
            "findByIds",
            "list",
            "createIndex",
            "push",
            "emptyCache",
            "handle"
        ];
        var location = getLocation(component.id);
        for (var name of mapping) {
            component[name] = me[name].bind(null, location);
        }
    };
    return "server";
};<commit_msg>bug fix<commit_after>/*
 @author Zakai Hamilton
 @component StorageDB
 */

screens.storage.db = function StorageDB(me, { core, db }) {
    me.init = async function () {
        me.mongodb = require("mongodb");
        me.clusterHandle = null;
        core.mutex.enable(me.id, true);
        me.keys = await core.private.keys("mongodb");
    };
    me.supported = function () {
        return !(!me.keys);
    };
    me.cluster = async function () {
        if (!me.keys) {
            me.keys = await core.private.keys("mongodb");
            if (!me.keys) {
                throw "No private keys for database";
            }
        }
        var clusterHandle = null;
        var unlock = await core.mutex.lock(me.id);
        try {
            clusterHandle = me.clusterHandle;
            if (clusterHandle) {
                unlock();
                return clusterHandle;
            }
            var url = me.keys.url;
            clusterHandle = await me.mongodb.MongoClient.connect(url, { useUnifiedTopology: true, useNewUrlParser: true });
            me.clusterHandle = clusterHandle;
            me.log("connected to cluster: " + url);
        }
        finally {
            unlock();
        }
        return clusterHandle;
    };
    me.database = async function (name) {
        var cluster = await me.cluster();
        var db = null;
        var info = me.keys[name];
        if (!info) {
            var err = name + " mongodb key not defined in private";
            me.log_error(err);
            throw err;
        }
        db = cluster.db(info.db);
        return db;
    };
    me.collection = async function (location) {
        var db = await me.database(location.db);
        if (!db) {
            throw "Cannot find database for location: " + location.toString();
        }
        var collection = await new Promise((resolve, reject) => {
            db.collection(location.collection, { strict: location.options ? true : false }, async (error, handle) => {
                if (error) {
                    try {
                        handle = await db.createCollection(location.collection, location.options);
                        resolve(handle);
                    }
                    catch (createError) {
                        try {
                            handle = await db.collection(location.collection);
                        }
                        catch (getError) {
                            me.clusterHandle = null;
                            reject(createError);
                        }
                    }
                }
                else {
                    resolve(handle);
                }
            });
        });
        if (!collection) {
            throw "Cannot find collection for location: " + location.collection;
        }
        if (location.indexes) {
            for (let index of location.indexes) {
                collection.createIndex(index);
            }
            location.indexes = null;
        }
        return collection;
    };
    me.objectId = function (id) {
        id = id.toString();
        var object = me.mongodb.ObjectID(id);
        return object;
    };
    me.findByIds = async function (location, ids) {
        var collection = await me.collection(location);
        ids = ids.map(id => id.toString());
        var results = await collection.find({ "_id": { "$in": ids } }).toArray();
        return results;
    };
    me.findById = async function (location, id) {
        var query = { _id: id };
        var [array, hash] = me.getCache(location, query, "find");
        if (array) {
            return array;
        }
        var collection = await me.collection(location);
        var result = await core.util.performance(location.componentId + ".findById: " + id, async () => {
            return await collection.findOne(query);
        });
        me.setCache(location, hash, result);
        return result;
    };
    me.find = async function (location, query) {
        var [array, hash] = me.getCache(location, query, "find");
        if (array) {
            return array;
        }
        var collection = await me.collection(location);
        var result = await core.util.performance(location.componentId + ".find: " + JSON.stringify(query), async () => {
            return await collection.findOne(query);
        });
        me.setCache(location, hash, result);
        return result;
    };
    me.store = async function (location, listOrSingle) {
        var collection = await me.collection(location);
        var isSingle = false;
        var list = listOrSingle;
        if (!Array.isArray(listOrSingle)) {
            isSingle = true;
            list = [listOrSingle];
        }
        for (var data of list) {
            if (data) {
                if (!data._id) {
                    data._id = me.mongodb.ObjectID().toString();
                }
                if (data._id) {
                    await collection.replaceOne({ _id: data._id }, data, { upsert: true });
                }
            }
        }
        listOrSingle = list;
        if (isSingle) {
            listOrSingle = list[0];
        }
        me.notifyCache(location);
        return listOrSingle;
    };
    me.push = async function (location, data) {
        var collection = await me.collection(location);
        var isArray = true;
        if (!Array.isArray(data)) {
            isArray = true;
            data = [data];
        }
        data.map(async data => {
            if (data) {
                if (!data._id) {
                    data._id = me.mongodb.ObjectID().toString();
                }
                if (data._id) {
                    await collection.insertOne(data);
                }
            }
        });
        if (!isArray) {
            data = data[0];
        }
        me.notifyCache(location);
        return data;
    };
    me.remove = async function (location, query, removeOne = true) {
        var collection = await me.collection(location);
        var result = null;
        if (removeOne) {
            result = await collection.deleteOne(query);
        }
        else {
            if (location.options && location.options.capped) {
                result = await collection.drop();
                let db = await me.database(location.db);
                await db.createCollection(location.collection, location.options);
            }
            else {
                result = await collection.deleteMany(query);
            }
        }
        me.notifyCache(location);
        if (result) {
            delete result.connection;
        }
        return result;
    };
    me.list = async function (location, query = {}, params) {
        var [array, hash, queryString] = me.getCache(location, query, params);
        if (array) {
            return array;
        }
        var collection = await me.collection(location);
        array = await core.util.performance(location.componentId + ".list: " + queryString, async () => {
            var cursor = await collection.find(query);
            if (params) {
                for (var param in params) {
                    cursor = cursor[param](params[param]);
                }
            }
            const items = await cursor.toArray();
            if (params && params.project && params.project.user) {
                const users = await db.shared.user.list();
                for (const item of items) {
                    const user = users.find(user => user.user === item.user);
                    item.user = user ? user.name.split("@")[0] : "Unknown";
                }
            }
            return items;
        }, 500);
        me.setCache(location, hash, array);
        return array;
    };
    me.use = async function (location, query, data) {
        if (!data) {
            return me.remove(location, query);
        }
        data = Object.assign({}, query, data);
        delete data._id;
        var collection = await me.collection(location);
        var result = await collection.replaceOne(query, data, { upsert: true });
        me.notifyCache(location);
        if (result) {
            delete result.connection;
        }
        return result;
    };
    me.createIndex = async function (location, index) {
        var collection = await me.collection(location);
        collection.createIndex(index);
    };
    me.queryAsString = function (query) {
        var string = JSON.stringify(core.json.map(query, item => {
            if (item && item.source) {
                return item.source;
            }
            return item;
        }));
        return string;
    };
    me.getCache = function (location, ...params) {
        var result = null;
        var string = me.queryAsString(params);
        var hash = core.string.hash(string);
        if (location.cache) {
            result = location.cache[hash];
        }
        return [result, hash, string];
    };
    me.setCache = function (location, hash, value) {
        if (location.cache) {
            location.cache[hash] = value;
        }
    };
    me.notifyCache = function (location) {
        if (location.cache && location.componentId) {
            me.emptyCache(location);
            if (!location.timer) {
                location.timer = setTimeout(async () => {
                    location.timer = null;
                    await db.events.msg.send(location.componentId + ".emptyCache");
                }, 5000);
            }
        }
    };
    me.emptyCache = function (location) {
        if (location.cache) {
            location.cache = {};
        }
    };
    me.handle = async function (location, query, callback) {
        var data = await me.find(location, query);
        if (!data) {
            data = await callback();
        }
        return data;
    };
    me.extension = function (component) {
        var getLocation = function (name) {
            var location = {};
            var tokens = name.split(".");
            location.collection = tokens.pop();
            location.db = tokens.pop();
            location.options = component.options;
            location.indexes = component.indexes;
            location.cache = component.cache;
            location.componentId = component.id;
            return location;
        };
        var mapping = [
            "remove",
            "store",
            "findById",
            "find",
            "use",
            "findByIds",
            "list",
            "createIndex",
            "push",
            "emptyCache",
            "handle"
        ];
        var location = getLocation(component.id);
        for (var name of mapping) {
            component[name] = me[name].bind(null, location);
        }
    };
    return "server";
};<|endoftext|>


<commit_before>'use strict';

var fs = require('fs');
var absorb = require('absorb');
var path = require('path');
var util = require('util');
var yeoman = require('yeoman-generator');
var install = '';

var Generator = module.exports = function Generator(args, options) {
  yeoman.generators.Base.apply(this, arguments);
};

util.inherits(Generator, yeoman.generators.Base);

Generator.prototype.askFor = function askFor(argument) {
    var cb = this.async();
    var options = ['yes', 'no'];
    var prompts = [{
        type: 'list',
        name: 'install',
        message: 'Would you like to install a frontsize theme?',
        choices: options
    }];

    this.prompt(prompts, function (props) {
        this.install = props.install;
        cb();
    }.bind(this));
};

Generator.prototype.frontsizeFiles = function frontsizeFiles() {
    this.bowerInstall('frontsize-sass', { save: true });

    var directory = 'bower_components';
    var pattern = /\/$/;
    if (fs.existsSync('./.bowerrc')) {
        var obj = JSON.parse(fs.readFileSync('./.bowerrc', 'utf8'));
        if(obj.directory !== undefined){
            directory = obj.directory;
        }
    }
    directory = directory.replace(pattern, '');

    //check if package.json exists in root
    if (fs.existsSync('./package.json')) {
        var dependenciesFrontsize = '';
        var dependenciesRoot = '';

        var packageJsonFrontsize = JSON.parse(fs.readFileSync(directory + '/frontsize-sass/package.json', 'utf8'));
        if(packageJsonFrontsize.dependencies !== undefined){
            dependenciesFrontsize = packageJsonFrontsize.dependencies;
        }
        var packageJsonRoot = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
        if(packageJsonRoot.dependencies !== undefined){
            dependenciesRoot = packageJsonRoot.dependencies;
        }

        if(dependenciesRoot != ''){
            packageJsonRoot.dependencies = absorb(dependenciesRoot, dependenciesFrontsize);
            fs.writeFile('./package.json', JSON.stringify(packageJsonRoot), function(err) {
                if(err) {
                    return console.log(err);
                }

            });
        }
        else{

        }
    }
    else{
        fs.createReadStream(directory + '/frontsize-sass/package.json').pipe(fs.createWriteStream('./package.json'));
    }

    if(this.install == 'yes'){

    }
    else{

    }
};
<commit_msg>create or overwrite package.json file<commit_after>'use strict';

var fs = require('fs');
var absorb = require('absorb');
var path = require('path');
var util = require('util');
var yeoman = require('yeoman-generator');
var install = '';

var Generator = module.exports = function Generator(args, options) {
  yeoman.generators.Base.apply(this, arguments);
};

util.inherits(Generator, yeoman.generators.Base);

Generator.prototype.askFor = function askFor(argument) {
    var cb = this.async();
    var options = ['yes', 'no'];
    var prompts = [{
        type: 'list',
        name: 'install',
        message: 'Would you like to install a frontsize theme?',
        choices: options
    }];

    this.prompt(prompts, function (props) {
        this.install = props.install;
        cb();
    }.bind(this));
};

Generator.prototype.frontsizeFiles = function frontsizeFiles() {
    this.bowerInstall('frontsize-sass', { save: true });

    var directory = 'bower_components';
    var pattern = /\/$/;
    if (fs.existsSync('./.bowerrc')) {
        var obj = JSON.parse(fs.readFileSync('./.bowerrc', 'utf8'));
        if(obj.directory !== undefined){
            directory = obj.directory;
        }
    }
    directory = directory.replace(pattern, '');

    //check if package.json exists in root
    if (fs.existsSync('./package.json')) {
        var dependenciesFrontsize = '';
        var dependenciesRoot = '';

        var packageJsonFrontsize = JSON.parse(fs.readFileSync(directory + '/frontsize-sass/package.json', 'utf8'));
        if(packageJsonFrontsize.dependencies !== undefined){
            dependenciesFrontsize = packageJsonFrontsize.dependencies;
        }
        var packageJsonRoot = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
        if(packageJsonRoot.dependencies !== undefined){
            dependenciesRoot = packageJsonRoot.dependencies;
        }

        if(dependenciesRoot != ''){
            packageJsonRoot.dependencies = absorb(dependenciesRoot, dependenciesFrontsize);
        }
        else{
            packageJsonRoot.dependencies = dependenciesFrontsize;
        }

        fs.writeFile('./package.json', JSON.stringify(packageJsonRoot, null, 2), function(err) {
            if(err) {
                return console.log(err);
            }
        });
    }
    else{
        fs.createReadStream(directory + '/frontsize-sass/package.json').pipe(fs.createWriteStream('./package.json'));
    }

    if(this.install == 'yes'){

    }
    else{

    }
};
<|endoftext|>


<commit_before>'use strict';

/* Controllers */

function NavBarCtrl($scope, $location) {
  $scope.path = function() {
    return $location.path();
  };
}

function SideBarCtrl($scope, $http, $routeParams, socket) {
  socket.on('matches:new', function(data) {
    $scope.matches.push(data);
  });
  $http.get('/api/matches')
    .success(function(data, status, headers, config) {
      $scope.matches = data.matches;
    });
  $scope.isActive = function() {
    return this.match._id === parseInt($routeParams.id,10);
  };
}

function StatsCtrl($scope, $routeParams, socket, resolvedData) {
  $scope.stats = resolvedData.stats;
  $scope.playerMetaData = resolvedData.playerdata;

  // Socket.io
  socket.emit('stats:subscribe', $routeParams.id);
  socket.on('stats:send', function (data) {
    $scope.stats = data.stats;
    $scope.playerMetaData = data.playerdata;
  });

  // Helpers
  $scope.sort = 'name';
  $scope.reverse = false;
  $scope.sortClass = function(sortColumn) {
    if ($scope.sort === sortColumn) {
      return $scope.reverse ? 'sort-true' : 'sort-false';
    }
    return '';
  };
  var sumArray = function(array) {
    var sum = 0;
    angular.forEach(array, function(value) {
      if (value) sum += value;
    });
    return sum;
  };
  var sumArray2 = function(array) {
    if (!array.length) return '-'; // this is a hack
    var sum = 0;
    angular.forEach(array, function(value) {
      if (value) sum += value;
    });
    return sum;
  };

  // Watch $scope.stats, recalculate on change
  $scope.$watch("stats", function() {
    var stats = $scope.stats;
    var numRounds = stats.redscore.length;
    // Ask sizzling to send only individual round scores instead of cumulative
    // It will make things a lot easier.
    var redScore = $scope.redScore = stats.redscore[numRounds-1];
    var bluScore = $scope.bluScore = stats.bluscore[numRounds-1];
    $scope.scoreComparison = redScore > bluScore ? '>' : redScore < bluScore ? '<' : '==';
    var redRoundScores = $scope.redRoundScores = [stats.redscore[0]];
    var bluRoundScores = $scope.bluRoundScores = [stats.bluscore[0]];
    for (var i=1; i<numRounds; i++) {
      redRoundScores.push(stats.redscore[i] - stats.redscore[i-1]);
      bluRoundScores.push(stats.bluscore[i] - stats.bluscore[i-1]);
    }
    // Calculate total damage for each team
    var totalDamage = $scope.totalDamage = [0,0,0,0];
    angular.forEach(stats.players, function(player) {
      totalDamage[player.team] += sumArray(player.damagedone);
    });
    // Calculate total frags for each team
    var totalFrags = $scope.totalFrags = [0,0,0,0];
    angular.forEach(stats.players, function(player) {
      totalFrags[player.team] += sumArray(player.kills);
    });
    // Sum up individual players' stats from each round
    angular.forEach(stats.players, function(player) {
      player.stats = [];
      player.stats.push(sumArray2(player.points));
      player.stats.push(sumArray2(player.kills));
      player.stats.push(sumArray2(player.killassists));
      player.stats.push(sumArray2(player.deaths));
      player.stats.push(sumArray2(player.damagedone));
      player.stats.push(sumArray2(player.medpicks));
      player.stats.push(sumArray2(player.captures));
      player.stats.push(sumArray2(player.defenses));
      player.stats.push(sumArray2(player.suicides));
      player.stats.push(sumArray2(player.dominations));
      player.stats.push(sumArray2(player.revenge));
      player.stats.push(sumArray2(player.buildingsbuilt));
      player.stats.push(sumArray2(player.buildingsdestroyed));
      player.stats.push(sumArray2(player.headshots));
      player.stats.push(sumArray2(player.backstabs));
      player.stats.push(sumArray2(player.healpoints));
      player.stats.push(sumArray2(player.invulns));
      player.stats.push(sumArray2(player.teleports));
      player.stats.push(sumArray2(player.crits));
      player.stats.push(sumArray2(player.resupplypoints));
      player.stats.push(sumArray2(player.bonuspoints));
      player.stats.push(sumArray2(player.healsreceived));
      player.stats.push(sumArray2(player.ubersdropped));
      player.tr = '' + player.name + '' + player.stats.join('	') + '	';
    });
  });
}
StatsCtrl.resolve = {
  resolvedData: function($q, $http, $route) {
    var deferred = $q.defer();

    $http({
      method: 'GET',
      url: '/api/stats/' + $route.current.params.id
    })
      .success(function(data) {
        deferred.resolve(data);
      })
      .error(function(data) {
        deferred.reject(data);
      });
    return deferred.promise;
  }
};
<commit_msg>rejiggered stats arr<commit_after>'use strict';

/* Controllers */

function NavBarCtrl($scope, $location) {
  $scope.path = function() {
    return $location.path();
  };
}

function SideBarCtrl($scope, $http, $routeParams, socket) {
  socket.on('matches:new', function(data) {
    $scope.matches.push(data);
  });
  $http.get('/api/matches')
    .success(function(data, status, headers, config) {
      $scope.matches = data.matches;
    });
  $scope.isActive = function() {
    return this.match._id === parseInt($routeParams.id,10);
  };
}

function StatsCtrl($scope, $routeParams, socket, resolvedData) {
  $scope.stats = resolvedData.stats;
  $scope.playerMetaData = resolvedData.playerdata;

  // Socket.io
  socket.emit('stats:subscribe', $routeParams.id);
  socket.on('stats:send', function (data) {
    $scope.stats = data.stats;
    $scope.playerMetaData = data.playerdata;
  });

  // Helpers
  $scope.sort = 'name';
  $scope.reverse = false;
  $scope.sortClass = function(sortColumn) {
    if ($scope.sort === sortColumn) {
      return $scope.reverse ? 'sort-true' : 'sort-false';
    }
    return '';
  };
  var sumArray = function(array) {
    var sum = 0;
    angular.forEach(array, function(value) {
      if (value) sum += value;
    });
    return sum;
  };
  var sumArray2 = function(array) {
    if (!array.length) return '-'; // this is a hack
    var sum = 0;
    angular.forEach(array, function(value) {
      if (value) sum += value;
    });
    return sum;
  };

  // Watch $scope.stats, recalculate on change
  $scope.$watch("stats", function() {
    var stats = $scope.stats;
    var numRounds = stats.redscore.length;
    // Ask sizzling to send only individual round scores instead of cumulative
    // It will make things a lot easier.
    var redScore = $scope.redScore = stats.redscore[numRounds-1];
    var bluScore = $scope.bluScore = stats.bluscore[numRounds-1];
    $scope.scoreComparison = redScore > bluScore ? '>' : redScore < bluScore ? '<' : '==';
    var redRoundScores = $scope.redRoundScores = [stats.redscore[0]];
    var bluRoundScores = $scope.bluRoundScores = [stats.bluscore[0]];
    for (var i=1; i<numRounds; i++) {
      redRoundScores.push(stats.redscore[i] - stats.redscore[i-1]);
      bluRoundScores.push(stats.bluscore[i] - stats.bluscore[i-1]);
    }
    // Calculate total damage for each team
    var totalDamage = $scope.totalDamage = [0,0,0,0];
    angular.forEach(stats.players, function(player) {
      totalDamage[player.team] += sumArray(player.damagedone);
    });
    // Calculate total frags for each team
    var totalFrags = $scope.totalFrags = [0,0,0,0];
    angular.forEach(stats.players, function(player) {
      totalFrags[player.team] += sumArray(player.kills);
    });
    // Sum up individual players' stats from each round
    angular.forEach(stats.players, function(player) {
      player.stats = [];
      player.stats.push(sumArray2(player.points));
      player.stats.push(sumArray2(player.kills));
      player.stats.push(sumArray2(player.killassists));
      player.stats.push(sumArray2(player.deaths));
      player.stats.push(sumArray2(player.damagedone));
      player.stats.push(sumArray2(player.medpicks));
      player.stats.push(sumArray2(player.captures));
      player.stats.push(sumArray2(player.defenses));
      player.stats.push(sumArray2(player.suicides));
      player.stats.push(sumArray2(player.dominations));
      player.stats.push(sumArray2(player.revenge));
      player.stats.push(sumArray2(player.buildingsbuilt));
      player.stats.push(sumArray2(player.buildingsdestroyed));
      player.stats.push(sumArray2(player.headshots));
      player.stats.push(sumArray2(player.backstabs));
      player.stats.push(sumArray2(player.crits));
      player.stats.push(sumArray2(player.resupplypoints));
      player.stats.push(sumArray2(player.bonuspoints));
      player.stats.push(sumArray2(player.healsreceived));
      player.stats.push(sumArray2(player.healpoints));
      player.stats.push(sumArray2(player.invulns));
      player.stats.push(sumArray2(player.ubersdropped));
      player.stats.push(sumArray2(player.teleports));
      player.tr = '' + player.name + '' + player.stats.join('	') + '	';
    });
  });
}
StatsCtrl.resolve = {
  resolvedData: function($q, $http, $route) {
    var deferred = $q.defer();

    $http({
      method: 'GET',
      url: '/api/stats/' + $route.current.params.id
    })
      .success(function(data) {
        deferred.resolve(data);
      })
      .error(function(data) {
        deferred.reject(data);
      });
    return deferred.promise;
  }
};
<|endoftext|>


<commit_before>'use strict';

var util = require( '../../../util' );
var math = require( '../../../math' );

var CRp = {};

CRp.eleTextBiggerThanMin = function( ele, scale ){
  if( !scale ){
    var zoom = ele.cy().zoom();
    var pxRatio = this.getPixelRatio();
    var lvl = Math.ceil( math.log2( zoom * pxRatio ) ); // the effective texture level

    scale = Math.pow( 2, lvl );
  }

  var computedSize = ele.pstyle( 'font-size' ).pfValue * scale;
  var minSize = ele.pstyle( 'min-zoomed-font-size' ).pfValue;

  if( computedSize < minSize ){
    return false;
  }

  return true;
};

CRp.drawElementText = function( context, ele, force ){
  var r = this;

  if( force === undefined ){
    if( !r.eleTextBiggerThanMin( ele ) ){ return; }
  } else {
    if( !force ){ return; }
  }

  if( ele.isNode() ){
    var label = ele.pstyle( 'label' );

    if( !label || !label.value ){ return; }

    var textHalign = ele.pstyle( 'text-halign' ).strValue;
    var textValign = ele.pstyle( 'text-valign' ).strValue;

    switch( textHalign ){
      case 'left':
        context.textAlign = 'right';
        break;

      case 'right':
        context.textAlign = 'left';
        break;

      default: // e.g. center
        context.textAlign = 'center';
    }

    context.textBaseline = 'bottom';
  } else {
    var label = ele.pstyle( 'label' );
    var srcLabel = ele.pstyle( 'source-label' );
    var tgtLabel = ele.pstyle( 'target-label' );

    if(
      ( !label || !label.value )
      && ( !srcLabel || !srcLabel.value )
      && ( !tgtLabel || !tgtLabel.value )
    ){
      return;
    }

    context.textAlign = 'center';
    context.textBaseline = 'bottom';
  }

  r.drawText( context, ele );

  if( ele.isEdge() ){
    r.drawText( context, ele, 'source' );

    r.drawText( context, ele, 'target' );
  }
};

CRp.drawNodeText = CRp.drawEdgeText = CRp.drawElementText;

CRp.getFontCache = function( context ){
  var cache;

  this.fontCaches = this.fontCaches || [];

  for( var i = 0; i < this.fontCaches.length; i++ ){
    cache = this.fontCaches[ i ];

    if( cache.context === context ){
      return cache;
    }
  }

  cache = {
    context: context
  };
  this.fontCaches.push( cache );

  return cache;
};

// set up canvas context with font
// returns transformed text string
CRp.setupTextStyle = function( context, ele ){
  // Font style
  var parentOpacity = ele.effectiveOpacity();
  var labelStyle = ele.pstyle( 'font-style' ).strValue;
  var labelSize = ele.pstyle( 'font-size' ).pfValue + 'px';
  var labelFamily = ele.pstyle( 'font-family' ).strValue;
  var labelWeight = ele.pstyle( 'font-weight' ).strValue;
  var opacity = ele.pstyle( 'text-opacity' ).value * ele.pstyle( 'opacity' ).value * parentOpacity;
  var outlineOpacity = ele.pstyle( 'text-outline-opacity' ).value * opacity;
  var color = ele.pstyle( 'color' ).value;
  var outlineColor = ele.pstyle( 'text-outline-color' ).value;
  var shadowBlur = ele.pstyle( 'text-shadow-blur' ).pfValue;
  var shadowOpacity = ele.pstyle( 'text-shadow-opacity' ).value;
  var shadowColor = ele.pstyle( 'text-shadow-color' ).value;
  var shadowOffsetX = ele.pstyle( 'text-shadow-offset-x' ).pfValue;
  var shadowOffsetY = ele.pstyle( 'text-shadow-offset-y' ).pfValue;

  var fontCacheKey = ele._private.fontKey;
  var cache = this.getFontCache( context );

  if( cache.key !== fontCacheKey ){
    context.font = labelStyle + ' ' + labelWeight + ' ' + labelSize + ' ' + labelFamily;

    cache.key = fontCacheKey;
  }

  // Calculate text draw position based on text alignment

  // so text outlines aren't jagged
  context.lineJoin = 'round';

  this.fillStyle( context, color[ 0 ], color[ 1 ], color[ 2 ], opacity );

  this.strokeStyle( context, outlineColor[ 0 ], outlineColor[ 1 ], outlineColor[ 2 ], outlineOpacity );

  this.shadowStyle( context, shadowColor, shadowOpacity, shadowBlur, shadowOffsetX, shadowOffsetY );
};

function roundRect( ctx, x, y, width, height, radius ){
  var radius = radius || 5;
  ctx.beginPath();
  ctx.moveTo( x + radius, y );
  ctx.lineTo( x + width - radius, y );
  ctx.quadraticCurveTo( x + width, y, x + width, y + radius );
  ctx.lineTo( x + width, y + height - radius );
  ctx.quadraticCurveTo( x + width, y + height, x + width - radius, y + height );
  ctx.lineTo( x + radius, y + height );
  ctx.quadraticCurveTo( x, y + height, x, y + height - radius );
  ctx.lineTo( x, y + radius );
  ctx.quadraticCurveTo( x, y, x + radius, y );
  ctx.closePath();
  ctx.fill();
}

// Draw text
CRp.drawText = function( context, ele, prefix ){
  var _p = ele._private;
  var rscratch = _p.rscratch;
  var parentOpacity = ele.effectiveOpacity();
  if( parentOpacity === 0 || ele.pstyle( 'text-opacity' ).value === 0 ){
    return;
  }

  var textX = util.getPrefixedProperty( rscratch, 'labelX', prefix );
  var textY = util.getPrefixedProperty( rscratch, 'labelY', prefix );
  var text = this.getLabelText( ele, prefix );

  if( text != null && text !== '' && !isNaN( textX ) && !isNaN( textY ) ){
    this.setupTextStyle( context, ele );

    var pdash = prefix ? prefix + '-' : '';
    var textW = util.getPrefixedProperty( rscratch, 'labelWidth', prefix );
    var textH = util.getPrefixedProperty( rscratch, 'labelHeight', prefix );
    var textAngle = util.getPrefixedProperty( rscratch, 'labelAngle', prefix );
    var marginX = ele.pstyle( pdash + 'text-margin-x' ).pfValue;
    var marginY = ele.pstyle( pdash + 'text-margin-y' ).pfValue;

    var isEdge = ele.isEdge();
    var isNode = ele.isNode();

    var halign = ele.pstyle( 'text-halign' ).value;
    var valign = ele.pstyle( 'text-valign' ).value;

    if( isEdge ){
      halign = 'center';
      valign = 'center';
    }

    textX += marginX;
    textY += marginY;

    var rotation = ele.pstyle( 'text-rotation' );
    var theta;

    if( rotation.strValue === 'autorotate' ){
      theta = isEdge ? textAngle : 0;
    } else if( rotation.strValue === 'none' ){
      theta = 0;
    } else {
      theta = rotation.pfValue;
    }

    if( theta !== 0 ){
      var orgTextX = textX;
      var orgTextY = textY;

      context.translate( orgTextX, orgTextY );
      context.rotate( theta );

      textX = 0;
      textY = 0;
    }

    if( isNode ){
      var pLeft = ele.pstyle( 'padding-left' ).pfValue;
      var pRight = ele.pstyle( 'padding-right' ).pfValue;
      var pTop = ele.pstyle( 'padding-top' ).pfValue;
      var pBottom = ele.pstyle( 'padding-bottom' ).pfValue;

      textX += pLeft / 2;
      textX -= pRight / 2;

      textY += pTop / 2;
      textY -= pBottom / 2;
    }

    switch( valign ){
      case 'top':
        break;
      case 'center':
        textY += textH / 2;
        break;
      case 'bottom':
        textY += textH;
        break;
    }

    var backgroundOpacity = ele.pstyle( 'text-background-opacity' ).value;
    var borderOpacity = ele.pstyle( 'text-border-opacity' ).value;
    var textBorderWidth = ele.pstyle( 'text-border-width' ).pfValue;

    if( backgroundOpacity > 0 || ( textBorderWidth > 0 && borderOpacity > 0 ) ){
      var bgX = textX;

      switch( halign ){
        case 'left':
          bgX -= textW;
          break;
        case 'center':
          bgX -= textW / 2;
          break;
        case 'right':
          break;
      }

      var bgY = textY;

      switch( valign ){
        case 'top':
          bgY -= textH;
          break;
        case 'center':
          bgY -= textH / 2;
          break;
        case 'bottom':
          break;
      }

      if( backgroundOpacity > 0 ){
        var textFill = context.fillStyle;
        var textBackgroundColor = ele.pstyle( 'text-background-color' ).value;

        context.fillStyle = 'rgba(' + textBackgroundColor[ 0 ] + ',' + textBackgroundColor[ 1 ] + ',' + textBackgroundColor[ 2 ] + ',' + backgroundOpacity * parentOpacity + ')';
        var styleShape = ele.pstyle( 'text-background-shape' ).strValue;
        if( styleShape == 'roundrectangle' ){
          roundRect( context, bgX, bgY, textW, textH, 2 );
        } else {
          context.fillRect( bgX, bgY, textW, textH );
        }
        context.fillStyle = textFill;
      }

      if( textBorderWidth > 0 && borderOpacity > 0 ){
        var textStroke = context.strokeStyle;
        var textLineWidth = context.lineWidth;
        var textBorderColor = ele.pstyle( 'text-border-color' ).value;
        var textBorderStyle = ele.pstyle( 'text-border-style' ).value;

        context.strokeStyle = 'rgba(' + textBorderColor[ 0 ] + ',' + textBorderColor[ 1 ] + ',' + textBorderColor[ 2 ] + ',' + borderOpacity * parentOpacity + ')';
        context.lineWidth = textBorderWidth;

        if( context.setLineDash ){ // for very outofdate browsers
          switch( textBorderStyle ){
            case 'dotted':
              context.setLineDash( [ 1, 1 ] );
              break;
            case 'dashed':
              context.setLineDash( [ 4, 2 ] );
              break;
            case 'double':
              context.lineWidth = textBorderWidth / 4; // 50% reserved for white between the two borders
              context.setLineDash( [] );
              break;
            case 'solid':
              context.setLineDash( [] );
              break;
          }
        }

        context.strokeRect( bgX, bgY, textW, textH );

        if( textBorderStyle === 'double' ){
          var whiteWidth = textBorderWidth / 2;

          context.strokeRect( bgX + whiteWidth, bgY + whiteWidth, textW - whiteWidth * 2, textH - whiteWidth * 2 );
        }

        if( context.setLineDash ){ // for very outofdate browsers
          context.setLineDash( [] );
        }
        context.lineWidth = textLineWidth;
        context.strokeStyle = textStroke;
      }

    }

    var lineWidth = 2 * ele.pstyle( 'text-outline-width' ).pfValue; // *2 b/c the stroke is drawn centred on the middle

    if( lineWidth > 0 ){
      context.lineWidth = lineWidth;
    }

    if( ele.pstyle( 'text-wrap' ).value === 'wrap' ){
      var lines = rscratch.labelWrapCachedLines;
      var lineHeight = textH / lines.length;

      switch( valign ){
        case 'top':
          textY -= ( lines.length - 1 ) * lineHeight;
          break;

        case 'bottom':
          // nothing required
          break;

        default:
        case 'center':
          textY -= ( lines.length - 1 ) * lineHeight / 2;
      }

      for( var l = 0; l < lines.length; l++ ){
        if( lineWidth > 0 ){
          context.strokeText( lines[ l ], textX, textY );
        }

        context.fillText( lines[ l ], textX, textY );

        textY += lineHeight;
      }

    } else {
      if( lineWidth > 0 ){
        context.strokeText( text, textX, textY );
      }

      context.fillText( text, textX, textY );
    }

    if( theta !== 0 ){
      context.rotate( -theta );
      context.translate( -orgTextX, -orgTextY );
    }

    this.shadowStyle( context, 'transparent', 0 ); // reset for next guy
  }
};

module.exports = CRp;
<commit_msg>Incorrect formatting on multiline text wrapping #1503<commit_after>'use strict';

var util = require( '../../../util' );
var math = require( '../../../math' );

var CRp = {};

CRp.eleTextBiggerThanMin = function( ele, scale ){
  if( !scale ){
    var zoom = ele.cy().zoom();
    var pxRatio = this.getPixelRatio();
    var lvl = Math.ceil( math.log2( zoom * pxRatio ) ); // the effective texture level

    scale = Math.pow( 2, lvl );
  }

  var computedSize = ele.pstyle( 'font-size' ).pfValue * scale;
  var minSize = ele.pstyle( 'min-zoomed-font-size' ).pfValue;

  if( computedSize < minSize ){
    return false;
  }

  return true;
};

CRp.drawElementText = function( context, ele, force ){
  var r = this;

  if( force === undefined ){
    if( !r.eleTextBiggerThanMin( ele ) ){ return; }
  } else {
    if( !force ){ return; }
  }

  if( ele.isNode() ){
    var label = ele.pstyle( 'label' );

    if( !label || !label.value ){ return; }

    var textHalign = ele.pstyle( 'text-halign' ).strValue;
    var textValign = ele.pstyle( 'text-valign' ).strValue;

    switch( textHalign ){
      case 'left':
        context.textAlign = 'right';
        break;

      case 'right':
        context.textAlign = 'left';
        break;

      default: // e.g. center
        context.textAlign = 'center';
    }

    context.textBaseline = 'bottom';
  } else {
    var label = ele.pstyle( 'label' );
    var srcLabel = ele.pstyle( 'source-label' );
    var tgtLabel = ele.pstyle( 'target-label' );

    if(
      ( !label || !label.value )
      && ( !srcLabel || !srcLabel.value )
      && ( !tgtLabel || !tgtLabel.value )
    ){
      return;
    }

    context.textAlign = 'center';
    context.textBaseline = 'bottom';
  }

  r.drawText( context, ele );

  if( ele.isEdge() ){
    r.drawText( context, ele, 'source' );

    r.drawText( context, ele, 'target' );
  }
};

CRp.drawNodeText = CRp.drawEdgeText = CRp.drawElementText;

CRp.getFontCache = function( context ){
  var cache;

  this.fontCaches = this.fontCaches || [];

  for( var i = 0; i < this.fontCaches.length; i++ ){
    cache = this.fontCaches[ i ];

    if( cache.context === context ){
      return cache;
    }
  }

  cache = {
    context: context
  };
  this.fontCaches.push( cache );

  return cache;
};

// set up canvas context with font
// returns transformed text string
CRp.setupTextStyle = function( context, ele ){
  // Font style
  var parentOpacity = ele.effectiveOpacity();
  var labelStyle = ele.pstyle( 'font-style' ).strValue;
  var labelSize = ele.pstyle( 'font-size' ).pfValue + 'px';
  var labelFamily = ele.pstyle( 'font-family' ).strValue;
  var labelWeight = ele.pstyle( 'font-weight' ).strValue;
  var opacity = ele.pstyle( 'text-opacity' ).value * ele.pstyle( 'opacity' ).value * parentOpacity;
  var outlineOpacity = ele.pstyle( 'text-outline-opacity' ).value * opacity;
  var color = ele.pstyle( 'color' ).value;
  var outlineColor = ele.pstyle( 'text-outline-color' ).value;
  var shadowBlur = ele.pstyle( 'text-shadow-blur' ).pfValue;
  var shadowOpacity = ele.pstyle( 'text-shadow-opacity' ).value;
  var shadowColor = ele.pstyle( 'text-shadow-color' ).value;
  var shadowOffsetX = ele.pstyle( 'text-shadow-offset-x' ).pfValue;
  var shadowOffsetY = ele.pstyle( 'text-shadow-offset-y' ).pfValue;

  var fontCacheKey = ele._private.fontKey;
  var cache = this.getFontCache( context );

  if( cache.key !== fontCacheKey ){
    context.font = labelStyle + ' ' + labelWeight + ' ' + labelSize + ' ' + labelFamily;

    cache.key = fontCacheKey;
  }

  // Calculate text draw position based on text alignment

  // so text outlines aren't jagged
  context.lineJoin = 'round';

  this.fillStyle( context, color[ 0 ], color[ 1 ], color[ 2 ], opacity );

  this.strokeStyle( context, outlineColor[ 0 ], outlineColor[ 1 ], outlineColor[ 2 ], outlineOpacity );

  this.shadowStyle( context, shadowColor, shadowOpacity, shadowBlur, shadowOffsetX, shadowOffsetY );
};

function roundRect( ctx, x, y, width, height, radius ){
  var radius = radius || 5;
  ctx.beginPath();
  ctx.moveTo( x + radius, y );
  ctx.lineTo( x + width - radius, y );
  ctx.quadraticCurveTo( x + width, y, x + width, y + radius );
  ctx.lineTo( x + width, y + height - radius );
  ctx.quadraticCurveTo( x + width, y + height, x + width - radius, y + height );
  ctx.lineTo( x + radius, y + height );
  ctx.quadraticCurveTo( x, y + height, x, y + height - radius );
  ctx.lineTo( x, y + radius );
  ctx.quadraticCurveTo( x, y, x + radius, y );
  ctx.closePath();
  ctx.fill();
}

// Draw text
CRp.drawText = function( context, ele, prefix ){
  var _p = ele._private;
  var rscratch = _p.rscratch;
  var parentOpacity = ele.effectiveOpacity();
  if( parentOpacity === 0 || ele.pstyle( 'text-opacity' ).value === 0 ){
    return;
  }

  var textX = util.getPrefixedProperty( rscratch, 'labelX', prefix );
  var textY = util.getPrefixedProperty( rscratch, 'labelY', prefix );
  var text = this.getLabelText( ele, prefix );

  if( text != null && text !== '' && !isNaN( textX ) && !isNaN( textY ) ){
    this.setupTextStyle( context, ele );

    var pdash = prefix ? prefix + '-' : '';
    var textW = util.getPrefixedProperty( rscratch, 'labelWidth', prefix );
    var textH = util.getPrefixedProperty( rscratch, 'labelHeight', prefix );
    var textAngle = util.getPrefixedProperty( rscratch, 'labelAngle', prefix );
    var marginX = ele.pstyle( pdash + 'text-margin-x' ).pfValue;
    var marginY = ele.pstyle( pdash + 'text-margin-y' ).pfValue;

    var isEdge = ele.isEdge();
    var isNode = ele.isNode();

    var halign = ele.pstyle( 'text-halign' ).value;
    var valign = ele.pstyle( 'text-valign' ).value;

    if( isEdge ){
      halign = 'center';
      valign = 'center';
    }

    textX += marginX;
    textY += marginY;

    var rotation = ele.pstyle( 'text-rotation' );
    var theta;

    if( rotation.strValue === 'autorotate' ){
      theta = isEdge ? textAngle : 0;
    } else if( rotation.strValue === 'none' ){
      theta = 0;
    } else {
      theta = rotation.pfValue;
    }

    if( theta !== 0 ){
      var orgTextX = textX;
      var orgTextY = textY;

      context.translate( orgTextX, orgTextY );
      context.rotate( theta );

      textX = 0;
      textY = 0;
    }

    if( isNode ){
      var pLeft = ele.pstyle( 'padding-left' ).pfValue;
      var pRight = ele.pstyle( 'padding-right' ).pfValue;
      var pTop = ele.pstyle( 'padding-top' ).pfValue;
      var pBottom = ele.pstyle( 'padding-bottom' ).pfValue;

      textX += pLeft / 2;
      textX -= pRight / 2;

      textY += pTop / 2;
      textY -= pBottom / 2;
    }

    switch( valign ){
      case 'top':
        break;
      case 'center':
        textY += textH / 2;
        break;
      case 'bottom':
        textY += textH;
        break;
    }

    var backgroundOpacity = ele.pstyle( 'text-background-opacity' ).value;
    var borderOpacity = ele.pstyle( 'text-border-opacity' ).value;
    var textBorderWidth = ele.pstyle( 'text-border-width' ).pfValue;

    if( backgroundOpacity > 0 || ( textBorderWidth > 0 && borderOpacity > 0 ) ){
      var bgX = textX;

      switch( halign ){
        case 'left':
          bgX -= textW;
          break;
        case 'center':
          bgX -= textW / 2;
          break;
        case 'right':
          break;
      }

      var bgY = textY;

      switch( valign ){
        case 'top':
          bgY -= textH;
          break;
        case 'center':
          bgY -= textH / 2;
          break;
        case 'bottom':
          break;
      }

      if( backgroundOpacity > 0 ){
        var textFill = context.fillStyle;
        var textBackgroundColor = ele.pstyle( 'text-background-color' ).value;

        context.fillStyle = 'rgba(' + textBackgroundColor[ 0 ] + ',' + textBackgroundColor[ 1 ] + ',' + textBackgroundColor[ 2 ] + ',' + backgroundOpacity * parentOpacity + ')';
        var styleShape = ele.pstyle( 'text-background-shape' ).strValue;
        if( styleShape == 'roundrectangle' ){
          roundRect( context, bgX, bgY, textW, textH, 2 );
        } else {
          context.fillRect( bgX, bgY, textW, textH );
        }
        context.fillStyle = textFill;
      }

      if( textBorderWidth > 0 && borderOpacity > 0 ){
        var textStroke = context.strokeStyle;
        var textLineWidth = context.lineWidth;
        var textBorderColor = ele.pstyle( 'text-border-color' ).value;
        var textBorderStyle = ele.pstyle( 'text-border-style' ).value;

        context.strokeStyle = 'rgba(' + textBorderColor[ 0 ] + ',' + textBorderColor[ 1 ] + ',' + textBorderColor[ 2 ] + ',' + borderOpacity * parentOpacity + ')';
        context.lineWidth = textBorderWidth;

        if( context.setLineDash ){ // for very outofdate browsers
          switch( textBorderStyle ){
            case 'dotted':
              context.setLineDash( [ 1, 1 ] );
              break;
            case 'dashed':
              context.setLineDash( [ 4, 2 ] );
              break;
            case 'double':
              context.lineWidth = textBorderWidth / 4; // 50% reserved for white between the two borders
              context.setLineDash( [] );
              break;
            case 'solid':
              context.setLineDash( [] );
              break;
          }
        }

        context.strokeRect( bgX, bgY, textW, textH );

        if( textBorderStyle === 'double' ){
          var whiteWidth = textBorderWidth / 2;

          context.strokeRect( bgX + whiteWidth, bgY + whiteWidth, textW - whiteWidth * 2, textH - whiteWidth * 2 );
        }

        if( context.setLineDash ){ // for very outofdate browsers
          context.setLineDash( [] );
        }
        context.lineWidth = textLineWidth;
        context.strokeStyle = textStroke;
      }

    }

    var lineWidth = 2 * ele.pstyle( 'text-outline-width' ).pfValue; // *2 b/c the stroke is drawn centred on the middle

    if( lineWidth > 0 ){
      context.lineWidth = lineWidth;
    }

    if( ele.pstyle( 'text-wrap' ).value === 'wrap' ){
      var lines = rscratch.labelWrapCachedLines;
      var lineHeight = textH / lines.length;

      switch( valign ){
        case 'top':
          textY -= ( lines.length - 1 ) * lineHeight;
          break;
        case 'center':
        case 'bottom':
          textY -= ( lines.length - 1 ) * lineHeight;
          break;
      }

      for( var l = 0; l < lines.length; l++ ){
        if( lineWidth > 0 ){
          context.strokeText( lines[ l ], textX, textY );
        }

        context.fillText( lines[ l ], textX, textY );

        textY += lineHeight;
      }

    } else {
      if( lineWidth > 0 ){
        context.strokeText( text, textX, textY );
      }

      context.fillText( text, textX, textY );
    }

    if( theta !== 0 ){
      context.rotate( -theta );
      context.translate( -orgTextX, -orgTextY );
    }

    this.shadowStyle( context, 'transparent', 0 ); // reset for next guy
  }
};

module.exports = CRp;
<|endoftext|>


<commit_before>var ballRadius = 9;
var rowcolors = ["#f2665e", "#fcb040", "#6ac071", "#57cbf5", "#f2665e"];
var paddlecolor = "#656565";
var ballcolor = "#f2665e";
var backcolor = "#f4f0ed";
var paddlePosition = {
    x: 0,
    y: 0
};
var ballPosition = {
    x: 25,
    y: 250,
}
var ballSpeed = {
    x: 1.5,
    y: -4,
}
// Used to calculate where the ball is going/what it's hitting
var tempBallPosition = {
    x: 0,
    y: 0,
}

function draw() {
    ctx.fillStyle = backcolor;
    clear();
    ctx.fillStyle = ballcolor;
    circle(ballPosition.x, ballPosition.y, ballRadius);

    paddlePosition = {
        x: paddlex + PADDLE_POSITION_OFFSET.x,
        y: HEIGHT - paddleh + PADDLE_POSITION_OFFSET.y
    };

    tempBallPosition = {
        x: ballPosition.x + ballSpeed.x,
        y: ballPosition.y + ballSpeed.y
    };

    drawPaddle();
    drawbricks();
    updateBricks();

    // If the ball has hit the wall
    if (hasBallHitWall()) {
        ballSpeed.x = -ballSpeed.x;
    }

    if (hasBallHitTop()) {
        ballSpeed.y = -ballSpeed.y;
    } else if (isBallNearPaddle()) {
        // Ball has hit paddle
        if (hasBallHitPaddle()) {
            //move the ball differently based on where it hit the paddle
            ballSpeed.x = 8 * ((ballPosition.x - (paddlex + paddlew / 2)) / paddlew);
            ballSpeed.y = -ballSpeed.y;
        } else if (isBallOutOfBounds()) {
            clearInterval(intervalId);
        }
    }

    ballPosition = tempBallPosition;
}

function updateBricks() {
    //want to learn about real collision detection? go read
    // http://www.harveycartel.org/metanet/tutorials/tutorialA.html
    rowheight = BRICKHEIGHT + PADDING;
    colwidth = BRICKWIDTH + PADDING;
    row = Math.floor(ballPosition.y/rowheight);
    col = Math.floor(ballPosition.x/colwidth);
    //reverse the ball and mark the brick as broken
    if (ballPosition.y < NROWS * rowheight && row >= 0 && col >= 0 && bricks[row][col] == 1) {
        ballSpeed.y = -ballSpeed.y;
        bricks[row][col] = 0;
    }
}

function drawPaddle() {

    // Move paddle
    if (rightDown) {
        paddlex += 5;
    } else if (leftDown) {
        paddlex -= 5;
    }
    ctx.fillStyle = paddlecolor;

    // Draw paddle
    rect(paddlePosition.x, paddlePosition.y, paddlew, paddleh);
}

function hasBallHitWall() {
    return (tempBallPosition.x + ballRadius > WIDTH
            || tempBallPosition.x - ballRadius < 0);
}

function hasBallHitTop() {
    return (ballPosition.y + ballSpeed.y - ballRadius < 0);
}

/**
 * Is the ball about to hit the paddle. Check whether the ball is currently hittable
 * or whether it's too late/early
 */
function isBallNearPaddle() {
    return (tempBallPosition.y + ballRadius > HEIGHT - paddleh + PADDLE_POSITION_OFFSET.y);
}

function hasBallHitPaddle() {
    return (ballPosition.x > paddlePosition.x && ballPosition.x < paddlePosition.y);
}

function isBallOutOfBounds() {
    return (ballPosition.y + ballSpeed.y + ballRadius > HEIGHT);
}

init();
initbricks();
<commit_msg>Amending hasBallHitPaddle() function to take the paddle's width into account<commit_after>var ballRadius = 9;
var rowcolors = ["#f2665e", "#fcb040", "#6ac071", "#57cbf5", "#f2665e"];
var paddlecolor = "#656565";
var ballcolor = "#f2665e";
var backcolor = "#f4f0ed";
var paddlePosition = {
    x: 0,
    y: 0
};
var ballPosition = {
    x: 25,
    y: 250,
}
var ballSpeed = {
    x: 1.5,
    y: -4,
}
// Used to calculate where the ball is going/what it's hitting
var tempBallPosition = {
    x: 0,
    y: 0,
}

function draw() {
    ctx.fillStyle = backcolor;
    clear();
    ctx.fillStyle = ballcolor;
    circle(ballPosition.x, ballPosition.y, ballRadius);

    paddlePosition = {
        x: paddlex + PADDLE_POSITION_OFFSET.x,
        y: HEIGHT - paddleh + PADDLE_POSITION_OFFSET.y
    };

    tempBallPosition = {
        x: ballPosition.x + ballSpeed.x,
        y: ballPosition.y + ballSpeed.y
    };

    drawPaddle();
    drawbricks();
    updateBricks();

    // If the ball has hit the wall
    if (hasBallHitWall()) {
        ballSpeed.x = -ballSpeed.x;
    }

    if (isBallNearPaddle()) {
        // Ball has hit paddle
        if (hasBallHitPaddle()) {
            //move the ball differently based on where it hit the paddle
            ballSpeed.x = 8 * ((ballPosition.x - (paddlex + paddlew / 2)) / paddlew);
            ballSpeed.y = -ballSpeed.y;
        } else if (isBallOutOfBounds()) {
            clearInterval(intervalId);
        }
    } else if (hasBallHitTop()) {
        ballSpeed.y = -ballSpeed.y;
    }

    ballPosition = tempBallPosition;
}

function updateBricks() {
    //want to learn about real collision detection? go read
    // http://www.harveycartel.org/metanet/tutorials/tutorialA.html
    rowheight = BRICKHEIGHT + PADDING;
    colwidth = BRICKWIDTH + PADDING;
    row = Math.floor(ballPosition.y / rowheight);
    col = Math.floor(ballPosition.x / colwidth);
    //reverse the ball and mark the brick as broken
    if (ballPosition.y < NROWS * rowheight && row >= 0 && col >= 0 && bricks[row][col] == 1) {
        ballSpeed.y = -ballSpeed.y;
        bricks[row][col] = 0;
    }
}

function drawPaddle() {

    // Move paddle
    if (rightDown) {
        paddlex += 5;
    } else if (leftDown) {
        paddlex -= 5;
    }
    ctx.fillStyle = paddlecolor;

    // Draw paddle
    rect(paddlePosition.x, paddlePosition.y, paddlew, paddleh);
}

function hasBallHitWall() {
    return (tempBallPosition.x + ballRadius > WIDTH
            || tempBallPosition.x - ballRadius < 0);
}

function hasBallHitTop() {
    return (ballPosition.y + ballSpeed.y - ballRadius < 0);
}

/**
 * Is the ball about to hit the paddle. Check whether the ball is currently hittable
 * or whether it's too late/early
 */
function isBallNearPaddle() {
    return (tempBallPosition.y + ballRadius > HEIGHT - paddleh + PADDLE_POSITION_OFFSET.y);
}

function hasBallHitPaddle() {
    return (ballPosition.x > paddlePosition.x && ballPosition.x < paddlePosition.x + paddlew);
}

function isBallOutOfBounds() {
    return (ballPosition.y + ballSpeed.y + ballRadius > HEIGHT);
}

init();
initbricks();
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'

import {Row, Col, Button} from 'react-bootstrap'

import { setQueryParam } from '../../actions/form'
import ModeButton from './mode-button'
import {
  getIcon,
  isAccessMode,
  hasBike,
  isTransit,
  hasMicromobility,
  hasHail,
  hasRental,
  hasTransit,
  getTransitModes
} from '../../util/itinerary'
import GeneralSettingsPanel from './general-settings-panel'

class SettingsSelectorPanel extends Component {
  static propTypes = {
    icons: PropTypes.object
  }

  constructor (props) {
    super(props)
    this.state = { activePanel: 'MODES' }
  }

  // returns whether a micromobility company is selected or not
  _companyIsActive (company) {
    const {companies} = this.props
    return companies && companies.indexOf(company.id) > -1
  }

  // Returns whether a particular mode or TNC agency is active
  _modeIsActive (mode) {
    const {companies, queryModes} = this.props
    if (mode.mode === 'CAR_HAIL' || mode.mode === 'CAR_RENT') {
      return Boolean(companies && mode.company && companies.includes(mode.company.toUpperCase()))
    }

    for (const m of queryModes) {
      if (m === mode.mode) return true
    }
    return false
  }

  _setSoloMode (mode) {
    // save current access/transit modes
    if (hasTransit(this.props.mode)) this._lastTransitMode = this.props.mode
    this.props.setQueryParam({ mode })
  }

  _setWalkOnly = () => { this._setSoloMode('WALK') }

  _setBikeOnly = () => { this._setSoloMode('BICYCLE') }

  _setMicromobilityOnly = () => { this._setSoloMode('MICROMOBILITY') }

  /**
   * Replace own mode with new mode. The only mode will have already been set,
   * so this toggles whether the own mode includes a rental.
   */
  _replaceOwnMode = (newMode, referenceOwnMode) => {
    const { queryModes, setQueryParam } = this.props
    const nonOwnModes = queryModes.filter(m => !m.startsWith(referenceOwnMode))
    setQueryParam({ mode: [...nonOwnModes, newMode].join(',') })
  }

  _setOwnBike = () => this._replaceOwnMode('BICYCLE', 'BICYCLE')

  _setRentedBike = () => this._replaceOwnMode('BICYCLE_RENT', 'BICYCLE')

  _setOwnMicromobility = () => this._replaceOwnMode('MICROMOBILITY', 'MICROMOBILITY')

  _setRentedMicromobility = () => {
    this._replaceOwnMode('MICROMOBILITY_RENT', 'MICROMOBILITY')
    this.props.setQueryParam({ companies: this._getCompaniesForMode('MICROMOBILITY_RENT') })
  }

  _getCompaniesForMode = (modeStr) => {
    const {config} = this.props
    return config.companies
      .filter(co => co.modes.indexOf(modeStr) > -1)
      .map(co => co.id)
      .join(',')
  }

  _toggleCompany (company) {
    const {companies, setQueryParam} = this.props

    // set company if no companies set yet
    if (!companies) {
      setQueryParam({ companies: company })
      return
    }

    // add or remove from existing companies
    if (companies.indexOf(company) > -1) {
      // company already present in query, remove
      setQueryParam({
        companies: companies
          .split(',')
          .filter(co => co !== company)
          .join(',')
      })
    } else {
      // company not yet present, add to string list
      setQueryParam({ companies: `${companies},${company}` })
    }
  }

  _toggleTransitMode (mode) {
    const {queryModes, setQueryParam} = this.props
    const modeStr = mode.mode || mode
    let newQueryModes = queryModes.slice(0) // Clone the modes array

    // do not allow the last transit mode to be deselected
    const transitModes = newQueryModes.filter(m => isTransit(m))
    if (transitModes.length === 1 && transitModes[0] === modeStr) return

    // If mode is currently selected, deselect it
    if (newQueryModes.includes(modeStr)) {
      newQueryModes = newQueryModes.filter(m => m !== modeStr)
    // Or, if mode is currently not selected, select it
    } else if (!newQueryModes.includes(modeStr)) {
      newQueryModes.push(modeStr)
    }
    setQueryParam({ mode: newQueryModes.join(',') })
  }

  _setAccessMode = (mode) => {
    const {config, queryModes} = this.props
    let newQueryModes = queryModes.slice(0) // Clone the modes array
    const modeStr = mode.mode || mode

    // Create object to contain multiple parameter updates if needed (i.e. 'mode', 'compainies')
    const queryParamUpdate = {}

    if (this._lastTransitMode) {
      // Restore previous transit selection, if present
      newQueryModes = this._lastTransitMode.split(',').filter(m => !isAccessMode(m))
      this._lastTransitMode = null
    } else {
      // Otherwise, retain any currently selected transit modes
      newQueryModes = newQueryModes.filter(m => !isAccessMode(m))
    }

    // If no transit modes selected, select all
    if (!newQueryModes || newQueryModes.length === 0) {
      newQueryModes = getTransitModes(config)
    }

    // Add the access mode
    newQueryModes.push(modeStr)

    // apply needed companies to query
    queryParamUpdate.companies = mode.company
      // mode is associated with a specific company
      ? mode.company.toUpperCase()
      // mode is either a rental or hailing mode, but not associated with
      // a specific company
      : (hasRental(modeStr) || hasHail(modeStr))
        // when switching, add all companies at first
        ? this._getCompaniesForMode(modeStr)
        // mode is not renting or hailing and not associated with any company
        : null

    queryParamUpdate.mode = newQueryModes.join(',')

    this.props.setQueryParam(queryParamUpdate)
  }

  _renderCompanies = () => {
    const {companies: queryCompanies, config, icons, mode} = this.props
    const {companies: configCompanies, modes} = config
    const {accessModes} = modes

    // check if a single company has an exclusive button
    if (queryCompanies && accessModes.some(
      accessMode => accessMode.company === queryCompanies.toUpperCase())
    ) {
      // a match has been found for an access mode that exclusively belongs to
      // a particular company
      return null
    }

    // hack for TriMet-MOD project, don't show companies if Biketown enabled
    // when using just bike rentals
    if (mode && mode.indexOf('BICYCLE_RENT') > -1) {
      return null
    }

    // check if renting or hailing
    if (hasRental(mode) || hasHail(mode)) {
      const queryModes = mode.split(',')
      const activeCompanies = configCompanies
        .filter(company =>
          company.modes
            .split(',')
            .some(companyMode => queryModes.indexOf(companyMode) > -1)
        )

      return (

Use Companies

            {activeCompanies.length === 0 &&

No comapnies available for this mode!

            }
            {activeCompanies.map((company) => {
              let classNames = ['select-button']
              if (this._companyIsActive(company)) classNames.push('active')
              return <Button key={company.id}
                className={classNames.join(' ')}
                style={{ marginTop: 3, marginBottom: 3, marginLeft: 0, marginRight: 5 }}
                onClick={() => this._toggleCompany(company.id)}
              >

                  {getIcon(company.id, icons)}

                {company.label}
              </Button>
            })}

      )
    }
  }

  render () {
    const { config, mode, icons, queryModes } = this.props

    const modeHasTransit = hasTransit(mode)

    const { transitModes, accessModes, bicycleModes, micromobilityModes } = config.modes

    return (

          {/* Take Transit button */}
          <Row className='mode-group-row'>
            <Col xs={12}>
              <ModeButton
                enabled
                active={modeHasTransit && this._modeIsActive({ mode: 'WALK' })}
                icons={icons}
                mode={'TRANSIT'}
                height={54}
                label={'Take Transit'}
                inlineLabel
                onClick={() => this._setAccessMode('WALK')}
              />
            </Col>
          </Row>

          {/* transit access mode selector */}
          <Row className='mode-group-row'>
            {accessModes.map((mode, k) => {
              return <Col xs={4} key={k}>
                <ModeButton
                  enabled
                  active={modeHasTransit && this._modeIsActive(mode)}
                  company={mode.company}
                  icons={icons}
                  mode={mode}
                  height={46}
                  label={mode.label}
                  showPlusTransit
                  onClick={() => this._setAccessMode(mode)}
                />
              </Col>
            })}
          </Row>

          <Row className='mode-group-row'>
            <Col xs={1} />
            <Col xs={3}>
              <ModeButton
                enabled
                active={mode === 'WALK'}
                icons={icons}
                mode={'WALK'}
                height={36}
                label={'Walk Only'}
                inlineLabel
                onClick={this._setWalkOnly}
              />
            </Col>
            <Col xs={3}>
              <ModeButton
                enabled
                active={!modeHasTransit && hasBike(mode)}
                icons={icons}
                mode={'BICYCLE'}
                height={36}
                label={'Bike Only'}
                inlineLabel
                onClick={this._setBikeOnly}
              />
            </Col>
            <Col xs={4}>
              <ModeButton
                enabled
                active={!modeHasTransit && hasMicromobility(mode)}
                icons={icons}
                mode={'MICROMOBILITY'}
                height={36}
                label={'eScooter Only'}
                inlineLabel
                onClick={this._setMicromobilityOnly}
              />
            </Col>
            <Col xs={1} />
          </Row>

          {/* Transit mode selector */}
          {/* <Row className='mode-group-row'>
            <Col xs={12}>

Filter Transit Modes

            </Col>
            <Col xs={12} style={{ textAlign: 'center' }}>
              {transitModes.map((mode, k) => {
                return (

                  <ModeButton
                    enabled={modeHasTransit}
                    active={this._modeIsActive(mode)}
                    icons={icons}
                    mode={mode}
                    label={mode.label}
                    showCheck
                    height={44}
                    onClick={() => this._toggleTransitMode(mode)}
                  />

)
              })}
            </Col>
          </Row> */}

        {/* Travel Preferences */}
        <Row>
          <Col xs={12} className='general-settings-panel'>

Travel Preferences

            {/* The bike trip type selector */}
            {hasBike(mode) && !hasTransit(mode) && (

Use

                  {bicycleModes.map((option, k) => {
                    let action = this._setOwnBike
                    if (option.mode === 'BICYCLE_RENT') action = this._setRentedBike
                    let classNames = ['select-button']
                    if (queryModes.includes(option.mode)) classNames.push('active')
                    // TODO: Handle different bikeshare networks
                    return (
                      <Button key={k}
                        className={classNames.join(' ')}
                        onClick={action}
                      >

                          {getIcon(option.mode, icons)}

                        {option.label}
                      </Button>
                    )
                  })}

            )}

            {/* The micromobility trip type selector */}
            {hasMicromobility(mode) && !hasTransit(mode) && (

Use

                  {micromobilityModes.map((option, k) => {
                    let action = this._setOwnMicromobility
                    if (option.mode === 'MICROMOBILITY_RENT') action = this._setRentedMicromobility
                    let classNames = ['select-button']
                    if (queryModes.includes(option.mode)) classNames.push('active')
                    // TODO: Handle different bikeshare networks
                    return (
                      <Button key={k}
                        className={classNames.join(' ')}
                        onClick={action}
                      >

                          {getIcon(option.mode, icons)}

                        {option.label}
                      </Button>
                    )
                  })}

            )}

            {this._renderCompanies()}

            {/* The transit mode selected */}
            {hasTransit(mode) && (

Use

                {transitModes.map((mode, k) => {
                  let classNames = ['select-button']
                  if (this._modeIsActive(mode)) classNames.push('active')
                  return <Button key={mode.mode}
                    className={classNames.join(' ')}
                    style={{ marginTop: 3, marginBottom: 3, marginLeft: 0, marginRight: 5 }}
                    onClick={() => this._toggleTransitMode(mode)}
                  >

                      {getIcon(mode.mode, icons)}

                    {mode.label}
                  </Button>
                })}

)}

            {/* Other general settings */}
            <GeneralSettingsPanel />
          </Col>
        </Row>

    )
  }
}

// connect to redux store

const mapStateToProps = (state, ownProps) => {
  const { companies, mode, routingType } = state.otp.currentQuery
  return {
    config: state.otp.config,
    mode,
    companies,
    modeGroups: state.otp.config.modeGroups,
    queryModes: !mode || mode.length === 0 ? [] : mode.split(','),
    routingType
  }
}

const mapDispatchToProps = { setQueryParam }

export default connect(mapStateToProps, mapDispatchToProps)(SettingsSelectorPanel)
<commit_msg>refactor(form): remove unneeded ModeButton prop<commit_after>import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'

import {Row, Col, Button} from 'react-bootstrap'

import { setQueryParam } from '../../actions/form'
import ModeButton from './mode-button'
import {
  getIcon,
  isAccessMode,
  hasBike,
  isTransit,
  hasMicromobility,
  hasHail,
  hasRental,
  hasTransit,
  getTransitModes
} from '../../util/itinerary'
import GeneralSettingsPanel from './general-settings-panel'

class SettingsSelectorPanel extends Component {
  static propTypes = {
    icons: PropTypes.object
  }

  constructor (props) {
    super(props)
    this.state = { activePanel: 'MODES' }
  }

  // returns whether a micromobility company is selected or not
  _companyIsActive (company) {
    const {companies} = this.props
    return companies && companies.indexOf(company.id) > -1
  }

  // Returns whether a particular mode or TNC agency is active
  _modeIsActive (mode) {
    const {companies, queryModes} = this.props
    if (mode.mode === 'CAR_HAIL' || mode.mode === 'CAR_RENT') {
      return Boolean(companies && mode.company && companies.includes(mode.company.toUpperCase()))
    }

    for (const m of queryModes) {
      if (m === mode.mode) return true
    }
    return false
  }

  _setSoloMode (mode) {
    // save current access/transit modes
    if (hasTransit(this.props.mode)) this._lastTransitMode = this.props.mode
    this.props.setQueryParam({ mode })
  }

  _setWalkOnly = () => { this._setSoloMode('WALK') }

  _setBikeOnly = () => { this._setSoloMode('BICYCLE') }

  _setMicromobilityOnly = () => { this._setSoloMode('MICROMOBILITY') }

  /**
   * Replace own mode with new mode. The only mode will have already been set,
   * so this toggles whether the own mode includes a rental.
   */
  _replaceOwnMode = (newMode, referenceOwnMode) => {
    const { queryModes, setQueryParam } = this.props
    const nonOwnModes = queryModes.filter(m => !m.startsWith(referenceOwnMode))
    setQueryParam({ mode: [...nonOwnModes, newMode].join(',') })
  }

  _setOwnBike = () => this._replaceOwnMode('BICYCLE', 'BICYCLE')

  _setRentedBike = () => this._replaceOwnMode('BICYCLE_RENT', 'BICYCLE')

  _setOwnMicromobility = () => this._replaceOwnMode('MICROMOBILITY', 'MICROMOBILITY')

  _setRentedMicromobility = () => {
    this._replaceOwnMode('MICROMOBILITY_RENT', 'MICROMOBILITY')
    this.props.setQueryParam({ companies: this._getCompaniesForMode('MICROMOBILITY_RENT') })
  }

  _getCompaniesForMode = (modeStr) => {
    const {config} = this.props
    return config.companies
      .filter(co => co.modes.indexOf(modeStr) > -1)
      .map(co => co.id)
      .join(',')
  }

  _toggleCompany (company) {
    const {companies, setQueryParam} = this.props

    // set company if no companies set yet
    if (!companies) {
      setQueryParam({ companies: company })
      return
    }

    // add or remove from existing companies
    if (companies.indexOf(company) > -1) {
      // company already present in query, remove
      setQueryParam({
        companies: companies
          .split(',')
          .filter(co => co !== company)
          .join(',')
      })
    } else {
      // company not yet present, add to string list
      setQueryParam({ companies: `${companies},${company}` })
    }
  }

  _toggleTransitMode (mode) {
    const {queryModes, setQueryParam} = this.props
    const modeStr = mode.mode || mode
    let newQueryModes = queryModes.slice(0) // Clone the modes array

    // do not allow the last transit mode to be deselected
    const transitModes = newQueryModes.filter(m => isTransit(m))
    if (transitModes.length === 1 && transitModes[0] === modeStr) return

    // If mode is currently selected, deselect it
    if (newQueryModes.includes(modeStr)) {
      newQueryModes = newQueryModes.filter(m => m !== modeStr)
    // Or, if mode is currently not selected, select it
    } else if (!newQueryModes.includes(modeStr)) {
      newQueryModes.push(modeStr)
    }
    setQueryParam({ mode: newQueryModes.join(',') })
  }

  _setAccessMode = (mode) => {
    const {config, queryModes} = this.props
    let newQueryModes = queryModes.slice(0) // Clone the modes array
    const modeStr = mode.mode || mode

    // Create object to contain multiple parameter updates if needed (i.e. 'mode', 'compainies')
    const queryParamUpdate = {}

    if (this._lastTransitMode) {
      // Restore previous transit selection, if present
      newQueryModes = this._lastTransitMode.split(',').filter(m => !isAccessMode(m))
      this._lastTransitMode = null
    } else {
      // Otherwise, retain any currently selected transit modes
      newQueryModes = newQueryModes.filter(m => !isAccessMode(m))
    }

    // If no transit modes selected, select all
    if (!newQueryModes || newQueryModes.length === 0) {
      newQueryModes = getTransitModes(config)
    }

    // Add the access mode
    newQueryModes.push(modeStr)

    // apply needed companies to query
    queryParamUpdate.companies = mode.company
      // mode is associated with a specific company
      ? mode.company.toUpperCase()
      // mode is either a rental or hailing mode, but not associated with
      // a specific company
      : (hasRental(modeStr) || hasHail(modeStr))
        // when switching, add all companies at first
        ? this._getCompaniesForMode(modeStr)
        // mode is not renting or hailing and not associated with any company
        : null

    queryParamUpdate.mode = newQueryModes.join(',')

    this.props.setQueryParam(queryParamUpdate)
  }

  _renderCompanies = () => {
    const {companies: queryCompanies, config, icons, mode} = this.props
    const {companies: configCompanies, modes} = config
    const {accessModes} = modes

    // check if a single company has an exclusive button
    if (queryCompanies && accessModes.some(
      accessMode => accessMode.company === queryCompanies.toUpperCase())
    ) {
      // a match has been found for an access mode that exclusively belongs to
      // a particular company
      return null
    }

    // hack for TriMet-MOD project, don't show companies if Biketown enabled
    // when using just bike rentals
    if (mode && mode.indexOf('BICYCLE_RENT') > -1) {
      return null
    }

    // check if renting or hailing
    if (hasRental(mode) || hasHail(mode)) {
      const queryModes = mode.split(',')
      const activeCompanies = configCompanies
        .filter(company =>
          company.modes
            .split(',')
            .some(companyMode => queryModes.indexOf(companyMode) > -1)
        )

      return (

Use Companies

            {activeCompanies.length === 0 &&

No comapnies available for this mode!

            }
            {activeCompanies.map((company) => {
              let classNames = ['select-button']
              if (this._companyIsActive(company)) classNames.push('active')
              return <Button key={company.id}
                className={classNames.join(' ')}
                style={{ marginTop: 3, marginBottom: 3, marginLeft: 0, marginRight: 5 }}
                onClick={() => this._toggleCompany(company.id)}
              >

                  {getIcon(company.id, icons)}

                {company.label}
              </Button>
            })}

      )
    }
  }

  render () {
    const { config, mode, icons, queryModes } = this.props

    const modeHasTransit = hasTransit(mode)

    const { transitModes, accessModes, bicycleModes, micromobilityModes } = config.modes

    return (

          {/* Take Transit button */}
          <Row className='mode-group-row'>
            <Col xs={12}>
              <ModeButton
                enabled
                active={modeHasTransit && this._modeIsActive({ mode: 'WALK' })}
                icons={icons}
                mode={'TRANSIT'}
                height={54}
                label={'Take Transit'}
                inlineLabel
                onClick={() => this._setAccessMode('WALK')}
              />
            </Col>
          </Row>

          {/* transit access mode selector */}
          <Row className='mode-group-row'>
            {accessModes.map((mode, k) => {
              return <Col xs={4} key={k}>
                <ModeButton
                  enabled
                  active={modeHasTransit && this._modeIsActive(mode)}
                  icons={icons}
                  mode={mode}
                  height={46}
                  label={mode.label}
                  showPlusTransit
                  onClick={() => this._setAccessMode(mode)}
                />
              </Col>
            })}
          </Row>

          <Row className='mode-group-row'>
            <Col xs={1} />
            <Col xs={3}>
              <ModeButton
                enabled
                active={mode === 'WALK'}
                icons={icons}
                mode={'WALK'}
                height={36}
                label={'Walk Only'}
                inlineLabel
                onClick={this._setWalkOnly}
              />
            </Col>
            <Col xs={3}>
              <ModeButton
                enabled
                active={!modeHasTransit && hasBike(mode)}
                icons={icons}
                mode={'BICYCLE'}
                height={36}
                label={'Bike Only'}
                inlineLabel
                onClick={this._setBikeOnly}
              />
            </Col>
            <Col xs={4}>
              <ModeButton
                enabled
                active={!modeHasTransit && hasMicromobility(mode)}
                icons={icons}
                mode={'MICROMOBILITY'}
                height={36}
                label={'eScooter Only'}
                inlineLabel
                onClick={this._setMicromobilityOnly}
              />
            </Col>
            <Col xs={1} />
          </Row>

          {/* Transit mode selector */}
          {/* <Row className='mode-group-row'>
            <Col xs={12}>

Filter Transit Modes

            </Col>
            <Col xs={12} style={{ textAlign: 'center' }}>
              {transitModes.map((mode, k) => {
                return (

                  <ModeButton
                    enabled={modeHasTransit}
                    active={this._modeIsActive(mode)}
                    icons={icons}
                    mode={mode}
                    label={mode.label}
                    showCheck
                    height={44}
                    onClick={() => this._toggleTransitMode(mode)}
                  />

)
              })}
            </Col>
          </Row> */}

        {/* Travel Preferences */}
        <Row>
          <Col xs={12} className='general-settings-panel'>

Travel Preferences

            {/* The bike trip type selector */}
            {hasBike(mode) && !hasTransit(mode) && (

Use

                  {bicycleModes.map((option, k) => {
                    let action = this._setOwnBike
                    if (option.mode === 'BICYCLE_RENT') action = this._setRentedBike
                    let classNames = ['select-button']
                    if (queryModes.includes(option.mode)) classNames.push('active')
                    // TODO: Handle different bikeshare networks
                    return (
                      <Button key={k}
                        className={classNames.join(' ')}
                        onClick={action}
                      >

                          {getIcon(option.mode, icons)}

                        {option.label}
                      </Button>
                    )
                  })}

            )}

            {/* The micromobility trip type selector */}
            {hasMicromobility(mode) && !hasTransit(mode) && (

Use

                  {micromobilityModes.map((option, k) => {
                    let action = this._setOwnMicromobility
                    if (option.mode === 'MICROMOBILITY_RENT') action = this._setRentedMicromobility
                    let classNames = ['select-button']
                    if (queryModes.includes(option.mode)) classNames.push('active')
                    // TODO: Handle different bikeshare networks
                    return (
                      <Button key={k}
                        className={classNames.join(' ')}
                        onClick={action}
                      >

                          {getIcon(option.mode, icons)}

                        {option.label}
                      </Button>
                    )
                  })}

            )}

            {this._renderCompanies()}

            {/* The transit mode selected */}
            {hasTransit(mode) && (

Use

                {transitModes.map((mode, k) => {
                  let classNames = ['select-button']
                  if (this._modeIsActive(mode)) classNames.push('active')
                  return <Button key={mode.mode}
                    className={classNames.join(' ')}
                    style={{ marginTop: 3, marginBottom: 3, marginLeft: 0, marginRight: 5 }}
                    onClick={() => this._toggleTransitMode(mode)}
                  >

                      {getIcon(mode.mode, icons)}

                    {mode.label}
                  </Button>
                })}

)}

            {/* Other general settings */}
            <GeneralSettingsPanel />
          </Col>
        </Row>

    )
  }
}

// connect to redux store

const mapStateToProps = (state, ownProps) => {
  const { companies, mode, routingType } = state.otp.currentQuery
  return {
    config: state.otp.config,
    mode,
    companies,
    modeGroups: state.otp.config.modeGroups,
    queryModes: !mode || mode.length === 0 ? [] : mode.split(','),
    routingType
  }
}

const mapDispatchToProps = { setQueryParam }

export default connect(mapStateToProps, mapDispatchToProps)(SettingsSelectorPanel)
<|endoftext|>