<commit_before>var async = require('async');
var utility = require('./utility');
var convert64to32 = utility.convert64to32;
var queueReq = utility.queueReq;
var compute = require('./compute');
var computePlayerMatchData = compute.computePlayerMatchData;
var computeMatchData = compute.computeMatchData;
var aggregator = require('./aggregator');
var constants = require('./constants');
var filter = require('./filter');
var util = require('util');
var columnInfo = {};

function getSets(redis, cb)
{
    async.parallel(
    {
        "trackedPlayers": function(cb)
        {
            redis.get("trackedPlayers", function(err, tps)
            {
                cb(err, JSON.parse(tps || "{}"));
            });
        },
        "userPlayers": function(cb)
        {
            redis.get("userPlayers", function(err, ups)
            {
                cb(err, JSON.parse(ups || "{}"));
            });
        },
        "donators": function(cb)
        {
            redis.get("donators", function(err, ds)
            {
                cb(err, JSON.parse(ds || "{}"));
            });
        }
    }, function(err, results)
    {
        cb(err, results);
    });
}

function getColumnInfo(db, table, cb)
{
    if (columnInfo[table])
    {
        return cb();
    }
    else
    {
        db(table).columnInfo().asCallback(function(err, result)
        {
            columnInfo[table] = result;
            cb(err);
        });
    }
}

function upsert(db, table, row, conflict, cb)
{
    getColumnInfo(db, table, function(err)
    {
        if (err)
        {
            return cb(err);
        }
        for (var key in row)
        {
            if (!(key in columnInfo[table]))
            {
                delete row[key];
                //console.error(key);
            }
        }
        /*
        var query1 = db(table).insert(row);
        var query2 = db(table).update(row).where(conflict);
        query1.asCallback(function(err)
        {
            if (err && err.detail.indexOf("already exists") !== -1)
            {
                query2.asCallback(cb);
            }
            else
            {
                cb(err);
            }
        });
        */
        var values = Object.keys(row).map(function(key)
        {
            return genValue(row, key);
        }).join(',');
        var update = Object.keys(row).map(function(key)
        {
            return util.format("%s=%s", key, "EXCLUDED." + key);
        }).join(',');
        var query = util.format("insert into %s (%s) values (%s) on conflict(%s) do update set %s", table, Object.keys(row).join(','), values, Object.keys(conflict).join(','), update);
        require('fs').writeFileSync('output.json', query);
        db.raw(query).asCallback(cb);
    });
}

function genValue(row, key)
{
    if (row[key] && row[key].constructor === Array)
    {
        return util.format("'{%s}'", row[key].map(function(e)
        {
            return JSON.stringify(JSON.stringify(e));
        }).join(','));
    }
    else if (typeof(row[key]) === "object")
    {
        return util.format("'%s'", JSON.stringify(row[key]));
    }
    else if (typeof(row[key] === "string"))
    {
        return util.format("'%s'", row[key]);
    }
    else
    {
        console.log(row[key]);
        return row[key];
    }
}

function insertMatch(db, redis, queue, match, options, cb)
{
    var players = match.players ? JSON.parse(JSON.stringify(match.players)) : undefined;
    //build match.pgroup so after parse we can figure out the player ids for each slot (for caching update without db read)
    if (players && !match.pgroup)
    {
        match.pgroup = {};
        players.forEach(function(p, i)
        {
            match.pgroup[p.player_slot] = {
                account_id: p.account_id,
                hero_id: p.hero_id,
                player_slot: p.player_slot
            };
        });
    }
    //put ability_upgrades data in redis
    if (players && !options.skipAbilityUpgrades)
    {
        var ability_upgrades = {};
        players.forEach(function(p)
        {
            ability_upgrades[p.player_slot] = p.ability_upgrades ? p.ability_upgrades.map(function(au)
            {
                return au.ability;
            }) : null;
        });
        redis.setex("ability_upgrades:" + match.match_id, 60 * 60 * 24 * 7, JSON.stringify(ability_upgrades));
    }
    //options.type specify api, parse, or skill
    //we want to insert into matches, then insert into player_matches for each entry in players
    //db.transaction(function(trx){
    async.series(
    {
        "imt": insertMatchTable,
        "ipmt": insertPlayerMatchesTable,
        "ep": ensurePlayers,
        "pc": updatePlayerCaches,
        "cmc": clearMatchCache,
        "dp": decideParse
    }, function(err, results)
    {
        /*
        if (err)
        {
            trx.rollback(err);
        }
        else
        {
            trx.commit();
        }
        */
        return cb(err, results.dp);
    });
    //}).catch(cb);
    function insertMatchTable(cb)
    {
        var row = match;
        upsert(db, 'matches', row,
        {
            match_id: match.match_id
        }, cb);
    }

    function insertPlayerMatchesTable(cb)
    {
        //we can skip this if we have no players (skill case)
        async.each(players || [], function(pm, cb)
        {
            pm.match_id = match.match_id;
            upsert(db, 'player_matches', pm,
            {
                match_id: pm.match_id,
                player_slot: pm.player_slot
            }, cb);
        }, cb);
    }
    /**
     * Inserts a placeholder player into db with just account ID for each player in this match
     **/
    function ensurePlayers(cb)
    {
        if (options.skipInsertPlayers)
        {
            return cb();
        }
        async.each(players || [], function(p, cb)
        {
            insertPlayer(db,
            {
                account_id: p.account_id
            }, cb);
        }, cb);
    }

    function updatePlayerCaches(cb)
    {
        if (options.skipCacheUpdate)
        {
            return cb();
        }
        var copy = JSON.parse(JSON.stringify(match));
        copy.players = players;
        copy.insert_type = options.type;
        queueReq(queue, "cache", copy,
        {}, cb);
    }

    function clearMatchCache(cb)
    {
        redis.del("match:" + match.match_id, cb);
    }

    function decideParse(cb)
    {
        if (match.parse_status !== 0)
        {
            //not parsing this match
            //this isn't a error, although we want to report that we refused to parse back to user if it was a request
            return cb();
        }
        else
        {
            //queue it and finish, callback with the queued parse job
            return queueReq(queue, "parse", match, options, function(err, job2)
            {
                cb(err, job2);
            });
        }
    }
}

function insertPlayer(db, player, cb)
{
    if (player.steamid)
    {
        //this is a login, compute the account_id from steamid
        player.account_id = Number(convert64to32(player.steamid));
    }
    if (!player.account_id || player.account_id === constants.anonymous_account_id)
    {
        return cb();
    }
    upsert(db, 'players', player,
    {
        account_id: player.account_id
    }, cb);
}

function insertPlayerRating(db, row, cb)
{
    db('player_ratings').insert(row).asCallback(cb);
}

function insertMatchSkill(db, row, cb)
{
    upsert(db, 'match_skill', row,
    {
        match_id: row.match_id
    }, cb);
}

function getMatch(db, match_id, cb)
{
    db.first().from('matches').where(
    {
        match_id: Number(match_id)
    }).asCallback(function(err, match)
    {
        if (err)
        {
            return cb(err);
        }
        else if (!match)
        {
            return cb("match not found");
        }
        else
        {
            //join to get personaname, last_login, avatar
            db.select().from('player_matches').where(
            {
                "player_matches.match_id": Number(match_id)
            }).leftJoin('players', 'player_matches.account_id', 'players.account_id').innerJoin('matches', 'player_matches.match_id', 'matches.match_id').orderBy("player_slot", "asc").asCallback(function(err, players)
            {
                if (err)
                {
                    return cb(err);
                }
                players.forEach(function(p)
                {
                    computePlayerMatchData(p);
                });
                match.players = players;
                computeMatchData(match);
                return cb(err, match);
            });
        }
    });
}

function getPlayerMatches(db, queryObj, cb)
{
    var result = {
        aggData: aggregator([], queryObj.js_agg),
        raw: []
    };
    var stream = db.select(queryObj.project).from('player_matches').where(queryObj.db_select).limit(queryObj.limit).orderBy('player_matches.match_id', 'desc').innerJoin('matches', 'player_matches.match_id', 'matches.match_id').leftJoin('match_skill', 'player_matches.match_id', 'match_skill.match_id').stream();
    stream.on('end', function(err)
    {
        cb(err, result);
    });
    stream.on('error', cb);
    stream.on('data', function(m)
    {
        computePlayerMatchData(m);
        if (filter([m], queryObj.js_select).length)
        {
            result.aggData = aggregator([m], queryObj.js_agg, result.aggData);
            result.raw.push(m);
        }
    });
}

function getPlayerRatings(db, account_id, cb)
{
    if (!isNaN(account_id))
    {
        db.from('player_ratings').where(
        {
            account_id: Number(account_id)
        }).orderBy('time', 'asc').asCallback(cb);
    }
    else
    {
        cb();
    }
}

function getPlayer(db, account_id, cb)
{
    if (!isNaN(account_id))
    {
        db.first().from('players').where(
        {
            account_id: Number(account_id)
        }).asCallback(cb);
    }
    else
    {
        cb();
    }
}
module.exports = {
    getSets: getSets,
    insertPlayer: insertPlayer,
    insertMatch: insertMatch,
    insertPlayerRating: insertPlayerRating,
    insertMatchSkill: insertMatchSkill,
    getMatch: getMatch,
    getPlayerMatches: getPlayerMatches,
    getPlayerRatings: getPlayerRatings,
    getPlayer: getPlayer,
};
<commit_msg>experiment with upsert<commit_after>var async = require('async');
var utility = require('./utility');
var convert64to32 = utility.convert64to32;
var queueReq = utility.queueReq;
var compute = require('./compute');
var computePlayerMatchData = compute.computePlayerMatchData;
var computeMatchData = compute.computeMatchData;
var aggregator = require('./aggregator');
var constants = require('./constants');
var filter = require('./filter');
var util = require('util');
var columnInfo = {};

function getSets(redis, cb)
{
    async.parallel(
    {
        "trackedPlayers": function(cb)
        {
            redis.get("trackedPlayers", function(err, tps)
            {
                cb(err, JSON.parse(tps || "{}"));
            });
        },
        "userPlayers": function(cb)
        {
            redis.get("userPlayers", function(err, ups)
            {
                cb(err, JSON.parse(ups || "{}"));
            });
        },
        "donators": function(cb)
        {
            redis.get("donators", function(err, ds)
            {
                cb(err, JSON.parse(ds || "{}"));
            });
        }
    }, function(err, results)
    {
        cb(err, results);
    });
}

function getColumnInfo(db, table, cb)
{
    if (columnInfo[table])
    {
        return cb();
    }
    else
    {
        db(table).columnInfo().asCallback(function(err, result)
        {
            columnInfo[table] = result;
            cb(err);
        });
    }
}

function upsert(db, table, row, conflict, cb)
{
    getColumnInfo(db, table, function(err)
    {
        if (err)
        {
            return cb(err);
        }
        for (var key in row)
        {
            if (!(key in columnInfo[table]))
            {
                delete row[key];
                //console.error(key);
            }
        }

        var query1 = db(table).insert(row);
        var query2 = db(table).update(row).where(conflict);
        query1.asCallback(function(err)
        {
            if (err && err.detail.indexOf("already exists") !== -1)
            {
                query2.asCallback(cb);
            }
            else
            {
                cb(err);
            }
        });
        /*
        var query1 = db(table).insert(row);
        var update = Object.keys(row).map(function(key)
        {
            return util.format("%s=%s", key, "EXCLUDED." + key);
        }).join(',');
        var query = util.format("%s on conflict(%s) do update set %s", query1, Object.keys(conflict).join(','), update);
        require('fs').writeFileSync('output.json', query);
        db.raw(query).asCallback(cb);
        */
    });
}

function insertMatch(db, redis, queue, match, options, cb)
{
    var players = match.players ? JSON.parse(JSON.stringify(match.players)) : undefined;
    //build match.pgroup so after parse we can figure out the player ids for each slot (for caching update without db read)
    if (players && !match.pgroup)
    {
        match.pgroup = {};
        players.forEach(function(p, i)
        {
            match.pgroup[p.player_slot] = {
                account_id: p.account_id,
                hero_id: p.hero_id,
                player_slot: p.player_slot
            };
        });
    }
    //put ability_upgrades data in redis
    if (players && !options.skipAbilityUpgrades)
    {
        var ability_upgrades = {};
        players.forEach(function(p)
        {
            ability_upgrades[p.player_slot] = p.ability_upgrades ? p.ability_upgrades.map(function(au)
            {
                return au.ability;
            }) : null;
        });
        redis.setex("ability_upgrades:" + match.match_id, 60 * 60 * 24 * 7, JSON.stringify(ability_upgrades));
    }
    //options.type specify api, parse, or skill
    //we want to insert into matches, then insert into player_matches for each entry in players
    //db.transaction(function(trx){
    async.series(
    {
        "imt": insertMatchTable,
        "ipmt": insertPlayerMatchesTable,
        "ep": ensurePlayers,
        "pc": updatePlayerCaches,
        "cmc": clearMatchCache,
        "dp": decideParse
    }, function(err, results)
    {
        /*
        if (err)
        {
            trx.rollback(err);
        }
        else
        {
            trx.commit();
        }
        */
        return cb(err, results.dp);
    });
    //}).catch(cb);
    function insertMatchTable(cb)
    {
        var row = match;
        upsert(db, 'matches', row,
        {
            match_id: match.match_id
        }, cb);
    }

    function insertPlayerMatchesTable(cb)
    {
        //we can skip this if we have no players (skill case)
        async.each(players || [], function(pm, cb)
        {
            pm.match_id = match.match_id;
            upsert(db, 'player_matches', pm,
            {
                match_id: pm.match_id,
                player_slot: pm.player_slot
            }, cb);
        }, cb);
    }
    /**
     * Inserts a placeholder player into db with just account ID for each player in this match
     **/
    function ensurePlayers(cb)
    {
        if (options.skipInsertPlayers)
        {
            return cb();
        }
        async.each(players || [], function(p, cb)
        {
            insertPlayer(db,
            {
                account_id: p.account_id
            }, cb);
        }, cb);
    }

    function updatePlayerCaches(cb)
    {
        if (options.skipCacheUpdate)
        {
            return cb();
        }
        var copy = JSON.parse(JSON.stringify(match));
        copy.players = players;
        copy.insert_type = options.type;
        queueReq(queue, "cache", copy,
        {}, cb);
    }

    function clearMatchCache(cb)
    {
        redis.del("match:" + match.match_id, cb);
    }

    function decideParse(cb)
    {
        if (match.parse_status !== 0)
        {
            //not parsing this match
            //this isn't a error, although we want to report that we refused to parse back to user if it was a request
            return cb();
        }
        else
        {
            //queue it and finish, callback with the queued parse job
            return queueReq(queue, "parse", match, options, function(err, job2)
            {
                cb(err, job2);
            });
        }
    }
}

function insertPlayer(db, player, cb)
{
    if (player.steamid)
    {
        //this is a login, compute the account_id from steamid
        player.account_id = Number(convert64to32(player.steamid));
    }
    if (!player.account_id || player.account_id === constants.anonymous_account_id)
    {
        return cb();
    }
    upsert(db, 'players', player,
    {
        account_id: player.account_id
    }, cb);
}

function insertPlayerRating(db, row, cb)
{
    db('player_ratings').insert(row).asCallback(cb);
}

function insertMatchSkill(db, row, cb)
{
    upsert(db, 'match_skill', row,
    {
        match_id: row.match_id
    }, cb);
}

function getMatch(db, match_id, cb)
{
    db.first().from('matches').where(
    {
        match_id: Number(match_id)
    }).asCallback(function(err, match)
    {
        if (err)
        {
            return cb(err);
        }
        else if (!match)
        {
            return cb("match not found");
        }
        else
        {
            //join to get personaname, last_login, avatar
            db.select().from('player_matches').where(
            {
                "player_matches.match_id": Number(match_id)
            }).leftJoin('players', 'player_matches.account_id', 'players.account_id').innerJoin('matches', 'player_matches.match_id', 'matches.match_id').orderBy("player_slot", "asc").asCallback(function(err, players)
            {
                if (err)
                {
                    return cb(err);
                }
                players.forEach(function(p)
                {
                    computePlayerMatchData(p);
                });
                match.players = players;
                computeMatchData(match);
                return cb(err, match);
            });
        }
    });
}

function getPlayerMatches(db, queryObj, cb)
{
    var result = {
        aggData: aggregator([], queryObj.js_agg),
        raw: []
    };
    var stream = db.select(queryObj.project).from('player_matches').where(queryObj.db_select).limit(queryObj.limit).orderBy('player_matches.match_id', 'desc').innerJoin('matches', 'player_matches.match_id', 'matches.match_id').leftJoin('match_skill', 'player_matches.match_id', 'match_skill.match_id').stream();
    stream.on('end', function(err)
    {
        cb(err, result);
    });
    stream.on('error', cb);
    stream.on('data', function(m)
    {
        computePlayerMatchData(m);
        if (filter([m], queryObj.js_select).length)
        {
            result.aggData = aggregator([m], queryObj.js_agg, result.aggData);
            result.raw.push(m);
        }
    });
}

function getPlayerRatings(db, account_id, cb)
{
    if (!isNaN(account_id))
    {
        db.from('player_ratings').where(
        {
            account_id: Number(account_id)
        }).orderBy('time', 'asc').asCallback(cb);
    }
    else
    {
        cb();
    }
}

function getPlayer(db, account_id, cb)
{
    if (!isNaN(account_id))
    {
        db.first().from('players').where(
        {
            account_id: Number(account_id)
        }).asCallback(cb);
    }
    else
    {
        cb();
    }
}
module.exports = {
    getSets: getSets,
    insertPlayer: insertPlayer,
    insertMatch: insertMatch,
    insertPlayerRating: insertPlayerRating,
    insertMatchSkill: insertMatchSkill,
    getMatch: getMatch,
    getPlayerMatches: getPlayerMatches,
    getPlayerRatings: getPlayerRatings,
    getPlayer: getPlayer,
};
<|endoftext|>


<commit_before>var utility = require('./utility');
var db = utility.db;
var async = require('async');

function mergeObjects(merge, val) {
    for (var attr in val) {
        if (val[attr].constructor === Array) {
            merge[attr] = merge[attr].concat(val[attr]);
        }
        else if (typeof val[attr] === "object") {
            mergeObjects(merge[attr], val[attr]);
        }
        else {
            //does property exist?
            if (!merge[attr]) {
                merge[attr] = val[attr];
            }
            else {
                merge[attr] += val[attr];
            }
        }
    }
}

function mergeMatchData(match, constants) {
    var heroes = match.parsed_data.heroes;
    //loop through all units
    //look up corresponding hero_id
    //hero if can find in constants
    //find player slot associated with that unit(hero_to_slot)
    //merge into player's primary unit
    //if not hero attempt to associate with a hero
    for (var key in heroes) {
        var val = heroes[key];
        var primary = key;
        if (constants.hero_names[key]) {
            //is a hero
            //merging multiple heroes together, only occurs in ARDM
            //doesn't work for 1v1, but ARDM is only played with 10 players
            var hero_id = constants.hero_names[key].id;
            var slot = match.parsed_data.hero_to_slot[hero_id];
            if (match.players[slot]) {
                var primary_id = match.players[slot].hero_id;
                primary = constants.heroes[primary_id].name;
                //build hero_ids for each player
                if (!match.players[slot].hero_ids) {
                    match.players[slot].hero_ids = [];
                }
                match.players[slot].hero_ids.push(hero_id);
            }
            else {
                console.log("couldn't find slot for hero id %s", hero_id);
            }
        }
        else {
            //is not a hero
            primary = getAssociatedHero(key, heroes);
        }
        if (key !== primary) {
            //merge the objects into primary, but not with itself
            mergeObjects(heroes[primary], val);
        }
    }
    return match;
}

function getAssociatedHero(unit, heroes) {
    //assume all illusions belong to that hero
    if (unit.slice(0, "illusion_".length) === "illusion_") {
        unit = unit.slice("illusion_".length);
    }
    //attempt to recover hero name from unit
    if (unit.slice(0, "npc_dota_".length) === "npc_dota_") {
        //split by _
        var split = unit.split("_");
        //get the third element
        var identifiers = [split[2], split[2] + "_" + split[3]];
        identifiers.forEach(function(id) {
            //append to npc_dota_hero_, see if matches
            var attempt = "npc_dota_hero_" + id;
            if (heroes[attempt]) {
                unit = attempt;
            }
        });
    }
    return unit;
}

function generateGraphData(match, constants) {
    var oneVone = (match.players.length === 2);
    if (oneVone) {
        //rebuild parsed data players array if 1v1 match
        match.parsed_data.players = [match.parsed_data.players[0], match.parsed_data.players[5]];
    }
    //compute graphs
    var goldDifference = ['Gold'];
    var xpDifference = ['XP'];
    for (var i = 0; i < match.parsed_data.times.length; i++) {
        var goldtotal = 0;
        var xptotal = 0;
        match.parsed_data.players.forEach(function(elem, j) {
            if (match.players[j].player_slot < 64) {
                goldtotal += elem.gold[i];
                xptotal += elem.xp[i];
            }
            else {
                xptotal -= elem.xp[i];
                goldtotal -= elem.gold[i];
            }
        });
        goldDifference.push(goldtotal);
        xpDifference.push(xptotal);
    }
    var time = ["time"].concat(match.parsed_data.times);
    var data = {
        difference: [time, goldDifference, xpDifference],
        gold: [time],
        xp: [time],
        lh: [time]
    };
    match.parsed_data.players.forEach(function(elem, i) {
        var hero = constants.heroes[match.players[i].hero_id].localized_name + (oneVone ? " - " + match.players[i].personaname : "");
        data.gold.push([hero].concat(elem.gold));
        data.xp.push([hero].concat(elem.xp));
        data.lh.push([hero].concat(elem.lh));
    });

    //data for income chart
    var gold_reasons = [];
    var columns = [];
    var categories = [];
    var orderedPlayers = match.players.slice(0);
    orderedPlayers.sort(function(a, b) {
        return b.gold_per_min - a.gold_per_min;
    });
    //console.log(orderedPlayers);
    orderedPlayers.forEach(function(player) {
        var hero = constants.heroes[player.hero_id];
        categories.push(hero.localized_name);
    });
    for (var key in constants.gold_reasons) {
        var reason = constants.gold_reasons[key];
        gold_reasons.push(reason);
        var col = [reason];
        orderedPlayers.forEach(function(player) {
            var hero = constants.heroes[player.hero_id];
            var parsedHero = match.parsed_data.heroes[hero.name];
            col.push(parsedHero.gold_log[key] || 0);
        });
        columns.push(col);
    }

    data.cats = categories;
    data.goldCols = columns;
    data.gold_reasons = gold_reasons;
    match.graphData = data;
    return match;
}

function fillPlayerNames(players, cb) {
    async.mapSeries(players, function(player, cb) {
        db.players.findOne({
            account_id: player.account_id
        }, function(err, dbPlayer) {
            if (dbPlayer) {
                for (var prop in dbPlayer) {
                    player[prop] = dbPlayer[prop];
                }
            }
            cb(err);
        });
    }, function(err) {
        cb(err);
    });
}

function computeStatistics(player, cb) {
    var playerMatches = player.matches;
    db.matches.find({
        'players.account_id': player.account_id
    }, {
        fields: {
            players: 1
        }
    }, {
        sort: {
            match_id: -1
        }
    }, function(err, matches) {
        if (err) {
            return cb(err);
        }
        var counts = {};
        var against = {};
        var together = {};
        for (var i = 0; i < matches.length; i++) {
            for (var j = 0; j < matches[i].players.length; j++) {
                var tm = matches[i].players[j];
                var tm_hero = tm.hero_id;
                if (utility.isRadiant(tm) === playerMatches[i].playerRadiant) {
                    //count teammate players
                    if (!counts[tm.account_id]) {
                        counts[tm.account_id] = {
                            account_id: tm.account_id,
                            win: 0,
                            lose: 0,
                            games: 0
                        };
                    }
                    counts[tm.account_id].games += 1;
                    playerMatches[i].player_win ? counts[tm.account_id].win += 1 : counts[tm.account_id].lose += 1;
                    //count teammate heroes
                    if (!together[tm_hero]) {
                        together[tm_hero] = {
                            games: 0,
                            win: 0,
                            lose: 0
                        };
                    }
                    together[tm_hero].games += 1;
                    playerMatches[i].player_win ? together[tm_hero].win += 1 : together[tm_hero].lose += 1;
                }
                else {
                    //count enemy heroes
                    if (!against[tm_hero]) {
                        against[tm_hero] = {
                            games: 0,
                            win: 0,
                            lose: 0
                        };
                    }
                    against[tm_hero].games += 1;
                    playerMatches[i].player_win ? against[tm_hero].win += 1 : against[tm_hero].lose += 1;
                }
            }
        }
        player.together = together;
        player.against = against;
        player.teammates = [];
        for (var id in counts) {
            var count = counts[id];
            player.teammates.push(count);
        }
        fillPlayerNames(player.teammates, function(err) {
            cb(err);
        });
    });
}

module.exports = {
    fillPlayerNames: fillPlayerNames,
    mergeMatchData: mergeMatchData,
    generateGraphData: generateGraphData,
    computeStatistics: computeStatistics
};<commit_msg>i noobed<commit_after>var utility = require('./utility');
var db = utility.db;
var async = require('async');

function mergeObjects(merge, val) {
    for (var attr in val) {
        if (val[attr].constructor === Array) {
            merge[attr] = merge[attr].concat(val[attr]);
        }
        else if (typeof val[attr] === "object") {
            mergeObjects(merge[attr], val[attr]);
        }
        else {
            //does property exist?
            if (!merge[attr]) {
                merge[attr] = val[attr];
            }
            else {
                merge[attr] += val[attr];
            }
        }
    }
}

function mergeMatchData(match, constants) {
    var heroes = match.parsed_data.heroes;
    //loop through all units
    //look up corresponding hero_id
    //hero if can find in constants
    //find player slot associated with that unit(hero_to_slot)
    //merge into player's primary unit
    //if not hero attempt to associate with a hero
    for (var key in heroes) {
        var val = heroes[key];
        var primary = key;
        if (constants.hero_names[key]) {
            //is a hero
            //merging multiple heroes together, only occurs in ARDM
            //doesn't work for 1v1, but ARDM is only played with 10 players
            var hero_id = constants.hero_names[key].id;
            var slot = match.parsed_data.hero_to_slot[hero_id];
            if (match.players[slot]) {
                var primary_id = match.players[slot].hero_id;
                primary = constants.heroes[primary_id].name;
                //build hero_ids for each player
                if (!match.players[slot].hero_ids) {
                    match.players[slot].hero_ids = [];
                }
                match.players[slot].hero_ids.push(hero_id);
            }
            else {
                console.log("couldn't find slot for hero id %s", hero_id);
            }
        }
        else {
            //is not a hero
            primary = getAssociatedHero(key, heroes);
        }
        if (key !== primary) {
            //merge the objects into primary, but not with itself
            mergeObjects(heroes[primary], val);
        }
    }
    return match;
}

function getAssociatedHero(unit, heroes) {
    //assume all illusions belong to that hero
    if (unit.slice(0, "illusion_".length) === "illusion_") {
        unit = unit.slice("illusion_".length);
    }
    //attempt to recover hero name from unit
    if (unit.slice(0, "npc_dota_".length) === "npc_dota_") {
        //split by _
        var split = unit.split("_");
        //get the third element
        var identifiers = [split[2], split[2] + "_" + split[3]];
        identifiers.forEach(function(id) {
            //append to npc_dota_hero_, see if matches
            var attempt = "npc_dota_hero_" + id;
            if (heroes[attempt]) {
                unit = attempt;
            }
        });
    }
    return unit;
}

function generateGraphData(match, constants) {
    var oneVone = (match.players.length === 2);
    if (oneVone) {
        //rebuild parsed data players array if 1v1 match
        match.parsed_data.players = [match.parsed_data.players[0], match.parsed_data.players[5]];
    }
    //compute graphs
    var goldDifference = ['Gold'];
    var xpDifference = ['XP'];
    for (var i = 0; i < match.parsed_data.times.length; i++) {
        var goldtotal = 0;
        var xptotal = 0;
        match.parsed_data.players.forEach(function(elem, j) {
            if (match.players[j].player_slot < 64) {
                goldtotal += elem.gold[i];
                xptotal += elem.xp[i];
            }
            else {
                xptotal -= elem.xp[i];
                goldtotal -= elem.gold[i];
            }
        });
        goldDifference.push(goldtotal);
        xpDifference.push(xptotal);
    }
    var time = ["time"].concat(match.parsed_data.times);
    var data = {
        difference: [time, goldDifference, xpDifference],
        gold: [time],
        xp: [time],
        lh: [time]
    };
    match.parsed_data.players.forEach(function(elem, i) {
        var hero = constants.heroes[match.players[i].hero_id].localized_name + (oneVone ? " - " + match.players[i].personaname : "");
        data.gold.push([hero].concat(elem.gold));
        data.xp.push([hero].concat(elem.xp));
        data.lh.push([hero].concat(elem.lh));
    });

    //data for income chart
    var gold_reasons = [];
    var columns = [];
    var categories = [];
    var orderedPlayers = match.players.slice(0);
    orderedPlayers.sort(function(a, b) {
        return b.gold_per_min - a.gold_per_min;
    });
    //console.log(orderedPlayers);
    orderedPlayers.forEach(function(player) {
        var hero = constants.heroes[player.hero_id];
        categories.push(hero.localized_name);
    });
    for (var key in constants.gold_reasons) {
        var reason = constants.gold_reasons[key];
        gold_reasons.push(reason);
        var col = [reason];
        orderedPlayers.forEach(function(player) {
            var hero = constants.heroes[player.hero_id];
            var parsedHero = match.parsed_data.heroes[hero.name];
            col.push(parsedHero.gold_log[key] || 0);
        });
        columns.push(col);
    }

    data.cats = categories;
    data.goldCols = columns;
    data.gold_reasons = gold_reasons;
    match.graphData = data;
    return match;
}

function fillPlayerNames(players, cb) {
    async.mapSeries(players, function(player, cb) {
        db.players.findOne({
            account_id: player.account_id
        }, function(err, dbPlayer) {
            if (dbPlayer) {
                for (var prop in dbPlayer) {
                    player[prop] = dbPlayer[prop];
                }
            }
            cb(err);
        });
    }, function(err) {
        cb(err);
    });
}

function computeStatistics(player, cb) {
    var playerMatches = player.matches;
    db.matches.find({
        'players.account_id': player.account_id
    }, {
        sort: {
            match_id: -1
        },
        fields: {
            players: 1
        }
    }, function(err, matches) {
        if (err) {
            return cb(err);
        }
        var counts = {};
        var against = {};
        var together = {};
        for (var i = 0; i < matches.length; i++) {
            for (var j = 0; j < matches[i].players.length; j++) {
                var tm = matches[i].players[j];
                var tm_hero = tm.hero_id;
                if (utility.isRadiant(tm) === playerMatches[i].playerRadiant) {
                    //count teammate players
                    if (!counts[tm.account_id]) {
                        counts[tm.account_id] = {
                            account_id: tm.account_id,
                            win: 0,
                            lose: 0,
                            games: 0
                        };
                    }
                    counts[tm.account_id].games += 1;
                    playerMatches[i].player_win ? counts[tm.account_id].win += 1 : counts[tm.account_id].lose += 1;
                    //count teammate heroes
                    if (!together[tm_hero]) {
                        together[tm_hero] = {
                            games: 0,
                            win: 0,
                            lose: 0
                        };
                    }
                    together[tm_hero].games += 1;
                    playerMatches[i].player_win ? together[tm_hero].win += 1 : together[tm_hero].lose += 1;
                }
                else {
                    //count enemy heroes
                    if (!against[tm_hero]) {
                        against[tm_hero] = {
                            games: 0,
                            win: 0,
                            lose: 0
                        };
                    }
                    against[tm_hero].games += 1;
                    playerMatches[i].player_win ? against[tm_hero].win += 1 : against[tm_hero].lose += 1;
                }
            }
        }
        player.together = together;
        player.against = against;
        player.teammates = [];
        for (var id in counts) {
            var count = counts[id];
            player.teammates.push(count);
        }
        fillPlayerNames(player.teammates, function(err) {
            cb(err);
        });
    });
}

module.exports = {
    fillPlayerNames: fillPlayerNames,
    mergeMatchData: mergeMatchData,
    generateGraphData: generateGraphData,
    computeStatistics: computeStatistics
};<|endoftext|>


<commit_before>/**
 * Created by d1m on 7/28/2015.
 */

var express = require('express')
var bodyParser = require('body-parser')
var morgan = require('morgan')
var app = express()

app.use(morgan())

var urlencodedParser = bodyParser.urlencoded({ extended: false })
app.get('/gestrec.min.js', urlencodedParser, function (req, res) {
  require('fs').createReadStream('gestrec.min.js').pipe(res)
})

app.post('/data', urlencodedParser, function (req, res) {
  require('fs').writeFileSync('results.json', JSON.stringify(JSON.parse(req.body.train), null, 2))
  res.send(200)
})

app.use(express.static('trainer'));

app.listen(8080);
<commit_msg>remove useless comment block<commit_after>var express = require('express')
var bodyParser = require('body-parser')
var morgan = require('morgan')
var app = express()

app.use(morgan())

var urlencodedParser = bodyParser.urlencoded({ extended: false })
app.get('/gestrec.min.js', urlencodedParser, function (req, res) {
  require('fs').createReadStream('gestrec.min.js').pipe(res)
})

app.post('/data', urlencodedParser, function (req, res) {
  require('fs').writeFileSync('results.json', JSON.stringify(JSON.parse(req.body.train), null, 2))
  res.send(200)
})

app.use(express.static('trainer'));

app.listen(8080);
<|endoftext|>


<commit_before>Facet.program = function(vs_src, fs_src)
{
    var ctx = Facet._globals.ctx;
    function getShader(shader_type, str)
    {
        var shader = ctx.createShader(shader_type);
        ctx.shaderSource(shader, str);
        ctx.compileShader(shader);
        if (!ctx.getShaderParameter(shader, ctx.COMPILE_STATUS)) {
            alert(ctx.getShaderInfoLog(shader));
            return null;
        }
        return shader;
    }

    var vertex_shader = getShader(ctx.VERTEX_SHADER, vs_src),
        fragment_shader = getShader(ctx.FRAGMENT_SHADER, fs_src);

    var shaderProgram = ctx.createProgram();
    ctx.attachShader(shaderProgram, vertex_shader);
    ctx.attachShader(shaderProgram, fragment_shader);
    ctx.linkProgram(shaderProgram);

    if (!ctx.getProgramParameter(shaderProgram, ctx.LINK_STATUS)) {
        alert("Could not initialise shaders");
        return null;
    }

    var active_uniforms = ctx.getProgramParameter(shaderProgram, ctx.ACTIVE_UNIFORMS);
    var array_name_regexp = /.*\[0\]/;
    var info;
    for (var i=0; i<active_uniforms; ++i) {
        info = ctx.getActiveUniform(shaderProgram, i);
        if (array_name_regexp.test(info.name)) {
            var array_name = info.name.substr(0, info.name.length-3);
            shaderProgram[array_name] = ctx.getUniformLocation(shaderProgram, array_name);
        } else {
            shaderProgram[info.name] = ctx.getUniformLocation(shaderProgram, info.name);
        }
    }
    var active_attributes = ctx.getProgramParameter(shaderProgram, ctx.ACTIVE_ATTRIBUTES);
    for (i=0; i<active_attributes; ++i) {
        info = ctx.getActiveAttrib(shaderProgram, i);
        shaderProgram[info.name] = ctx.getAttribLocation(shaderProgram, info.name);
    }
    return shaderProgram;
};
<commit_msg>when compilation fails, dump source and error to console<commit_after>Facet.program = function(vs_src, fs_src)
{
    var ctx = Facet._globals.ctx;
    function getShader(shader_type, str)
    {
        var shader = ctx.createShader(shader_type);
        ctx.shaderSource(shader, str);
        ctx.compileShader(shader);
        if (!ctx.getShaderParameter(shader, ctx.COMPILE_STATUS)) {
            alert(ctx.getShaderInfoLog(shader));
            console.log("Error message: ");
            console.log(ctx.getShaderInfoLog(shader));
            console.log("Failing shader: ");
            console.log(str);
            return null;
        }
        return shader;
    }

    var vertex_shader = getShader(ctx.VERTEX_SHADER, vs_src),
        fragment_shader = getShader(ctx.FRAGMENT_SHADER, fs_src);

    var shaderProgram = ctx.createProgram();
    ctx.attachShader(shaderProgram, vertex_shader);
    ctx.attachShader(shaderProgram, fragment_shader);
    ctx.linkProgram(shaderProgram);

    if (!ctx.getProgramParameter(shaderProgram, ctx.LINK_STATUS)) {
        alert("Could not initialise shaders");
        return null;
    }

    var active_uniforms = ctx.getProgramParameter(shaderProgram, ctx.ACTIVE_UNIFORMS);
    var array_name_regexp = /.*\[0\]/;
    var info;
    for (var i=0; i<active_uniforms; ++i) {
        info = ctx.getActiveUniform(shaderProgram, i);
        if (array_name_regexp.test(info.name)) {
            var array_name = info.name.substr(0, info.name.length-3);
            shaderProgram[array_name] = ctx.getUniformLocation(shaderProgram, array_name);
        } else {
            shaderProgram[info.name] = ctx.getUniformLocation(shaderProgram, info.name);
        }
    }
    var active_attributes = ctx.getProgramParameter(shaderProgram, ctx.ACTIVE_ATTRIBUTES);
    for (i=0; i<active_attributes; ++i) {
        info = ctx.getActiveAttrib(shaderProgram, i);
        shaderProgram[info.name] = ctx.getAttribLocation(shaderProgram, info.name);
    }
    return shaderProgram;
};
<|endoftext|>


<commit_before>'use strict';

const fs = require('fs');
const path = require('path');
const semver = require('semver');
const inquirer = require('inquirer');
const nconf = require('nconf');
const _ = require('lodash');
const shell = require('shelljs');

const lint = require('./lint');
const clean = require('./clean');
const build = require('./build');

let VERSION = null;
let RAW = null;

function raw() {
  if (!RAW) {
    RAW = fs.readFileSync(path.join(process.cwd(), 'package.json'), 'utf8');
  }

  return RAW;
}

function pkg(contents) {
  return JSON.parse(contents || raw());
}

// Preserver new line at the end of a file
function newLine(contents) {
  const lastChar = (contents && contents.slice(-1) === '\n') ? '' : '\n';
  return contents + lastChar;
}

function bump() {

  return new Promise( (resolve, reject) => {

    if (!VERSION) {
      return reject(false);
    }

    let contents = raw();
    let json = pkg(contents);

    json = _.merge({}, json, {version: VERSION});

    contents = JSON.stringify(json, null, 2);
    contents = newLine(contents);

    // update package.json
    fs.writeFileSync(path.join(process.cwd(), 'package.json'), contents, 'utf8');

    resolve();

  });

}

function git() {

  return new Promise( resolve => {

    shell.exec('git add .');
    shell.exec(`git commit -m "v${VERSION}"`);
    shell.exec(`git tag -a v${VERSION} -m "v${VERSION}"`);

    const push = nconf.get('push');

    if (push) {
      shell.exec('git push', 'Push to remote');
      shell.exec('git push --tags', `Push new tag v${VERSION} to remote`);
    }

    resolve();

  });
}

function prompt() {

  const version = pkg().version;
  const parsed = semver.parse(version);

  // regular release
  const simpleVersion = `${parsed.major}.${parsed.minor}.${parsed.patch}`;
  let choices = [
    {name: `patch ( ${version} --> ${semver.inc(simpleVersion, 'patch')}`, value: semver.inc(simpleVersion, 'patch')},
    {name: `minor ( ${version} --> ${semver.inc(simpleVersion, 'minor')}`, value: semver.inc(simpleVersion, 'minor')},
    {name: `major ( ${version} --> ${semver.inc(simpleVersion, 'major')}`, value: semver.inc(simpleVersion, 'major')},
    new inquirer.Separator(),
    {name: 'other', value: 'other'}
  ];

  // pre-release
  if (parsed.prerelease && parsed.prerelease.length) {

    choices = [
      {name: `prerelease ( ${version} => ${semver.inc(version, 'prerelease', parsed[0])})`, value: semver.inc(version, 'prerelease', parsed[0])},
      {name: `release ( ${version} => ${simpleVersion})`, value: simpleVersion},
      new inquirer.Separator(),
      {name: 'other', value: 'other'}
    ];

  }

  const questions = [
    {
      type: 'rawlist',
      name: 'bump',
      message: 'What type of version bump would you like to do?',
      choices
    },
    {
      type: 'input',
      name: 'version',
      message: `version (current version is ${pkg().version})`,
      when(answer) {
        return answer.bump === 'other';
      },
      filter(value) {
        return semver.clean(value);
      },
      validate(value) {

        const valid = semver.valid(value);

        if (valid) {
          return true;
        }

        return 'Enter valid semver version number.  Please see https://docs.npmjs.com/misc/semver for more details.';

      }

    }
  ];

  return new Promise( resolve => {

    inquirer.prompt(questions, function(answers) {

      VERSION = answers.bump !== 'other' ? answers.bump : answers.version;

      return resolve();

    });

  });

}

function release() {

  return prompt()
    .then(lint)
    .then(clean)
    .then(bump)
    .then(build)
    .then(git);

}

module.exports = {
  prompt,
  release
};
<commit_msg>multiple exports was breaking release tool<commit_after>'use strict';

const fs = require('fs');
const path = require('path');
const semver = require('semver');
const inquirer = require('inquirer');
const nconf = require('nconf');
const _ = require('lodash');
const shell = require('shelljs');

const lint = require('./lint');
const clean = require('./clean');
const build = require('./build');

let VERSION = null;
let RAW = null;

function raw() {
  if (!RAW) {
    RAW = fs.readFileSync(path.join(process.cwd(), 'package.json'), 'utf8');
  }

  return RAW;
}

function pkg(contents) {
  return JSON.parse(contents || raw());
}

// Preserver new line at the end of a file
function newLine(contents) {
  const lastChar = (contents && contents.slice(-1) === '\n') ? '' : '\n';
  return contents + lastChar;
}

function bump() {

  return new Promise( (resolve, reject) => {

    if (!VERSION) {
      return reject(false);
    }

    let contents = raw();
    let json = pkg(contents);

    json = _.merge({}, json, {version: VERSION});

    contents = JSON.stringify(json, null, 2);
    contents = newLine(contents);

    // update package.json
    fs.writeFileSync(path.join(process.cwd(), 'package.json'), contents, 'utf8');

    resolve();

  });

}

function git() {

  return new Promise( resolve => {

    shell.exec('git add .');
    shell.exec(`git commit -m "v${VERSION}"`);
    shell.exec(`git tag -a v${VERSION} -m "v${VERSION}"`);

    const push = nconf.get('push');

    if (push) {
      shell.exec('git push', 'Push to remote');
      shell.exec('git push --tags', `Push new tag v${VERSION} to remote`);
    }

    resolve();

  });
}

function prompt() {

  const version = pkg().version;
  const parsed = semver.parse(version);

  // regular release
  const simpleVersion = `${parsed.major}.${parsed.minor}.${parsed.patch}`;
  let choices = [
    {name: `patch ( ${version} --> ${semver.inc(simpleVersion, 'patch')}`, value: semver.inc(simpleVersion, 'patch')},
    {name: `minor ( ${version} --> ${semver.inc(simpleVersion, 'minor')}`, value: semver.inc(simpleVersion, 'minor')},
    {name: `major ( ${version} --> ${semver.inc(simpleVersion, 'major')}`, value: semver.inc(simpleVersion, 'major')},
    new inquirer.Separator(),
    {name: 'other', value: 'other'}
  ];

  // pre-release
  if (parsed.prerelease && parsed.prerelease.length) {

    choices = [
      {name: `prerelease ( ${version} => ${semver.inc(version, 'prerelease', parsed[0])})`, value: semver.inc(version, 'prerelease', parsed[0])},
      {name: `release ( ${version} => ${simpleVersion})`, value: simpleVersion},
      new inquirer.Separator(),
      {name: 'other', value: 'other'}
    ];

  }

  const questions = [
    {
      type: 'rawlist',
      name: 'bump',
      message: 'What type of version bump would you like to do?',
      choices
    },
    {
      type: 'input',
      name: 'version',
      message: `version (current version is ${pkg().version})`,
      when(answer) {
        return answer.bump === 'other';
      },
      filter(value) {
        return semver.clean(value);
      },
      validate(value) {

        const valid = semver.valid(value);

        if (valid) {
          return true;
        }

        return 'Enter valid semver version number.  Please see https://docs.npmjs.com/misc/semver for more details.';

      }

    }
  ];

  return new Promise( resolve => {

    inquirer.prompt(questions, function(answers) {

      VERSION = answers.bump !== 'other' ? answers.bump : answers.version;

      return resolve();

    });

  });

}

function release() {

  return prompt()
    .then(lint)
    .then(clean)
    .then(bump)
    .then(build)
    .then(git);

}

module.exports = release;
<|endoftext|>


<commit_before>// 21 Dez 2012, 4:42
;(function ($, window, document, undefined) {
	'use strict';
	({
		animateScroll : function () {
			$('.nav-link').on('click', function (event) {

				var $this = $(this),
					$htmlBody = $('html, body'),
					linkTarget = $this.attr('href'),
					offSetTop;

				// If not start with #, stop here!
				if (linkTarget[0] !== '#') {
					return false;
				}

				event.preventDefault();

				// Get distance of top
				offSetTop = $(linkTarget).offset().top;

				// Animate the scroll
				$htmlBody.stop().animate({scrollTop : offSetTop}, function () {
					location.hash = linkTarget;
				});
			});
		},

		init : function () {
			var that = this;

			$(function () {
				that.animateScroll();
			});
		}
	}).init();
}(jQuery, window, document));<commit_msg>improving selector performance on click nav-link<commit_after>// 21 Dez 2012, 4:42
;(function ($, window, document, undefined) {
	'use strict';
	({
		animateScroll : function () {
			$("#nav").find('.nav-link').on('click', function (event) {

				var $this = $(this),
					$htmlBody = $('html, body'),
					linkTarget = $this.attr('href'),
					offSetTop;

				// If not start with #, stop here!
				if (linkTarget[0] !== '#') {
					return false;
				}

				event.preventDefault();

				// Get distance of top
				offSetTop = $(linkTarget).offset().top;

				// Animate the scroll
				$htmlBody.stop().animate({scrollTop : offSetTop}, function () {
					location.hash = linkTarget;
				});
			});
		},

		init : function () {
			var that = this;

			$(function () {
				that.animateScroll();
			});
		}
	}).init();
}(jQuery, window, document));<|endoftext|>


<commit_before>'use strict';
//this popup is for holding pages
define(['module', 'common/kernel/kernel', 'site/pages/pages'], function (module, kernel, pages) {
	let thisPopup = module.id.replace(/^[^/]+\/|\/[^/]+/g, ''),
		dom = document.querySelector('#popup>.content>.' + thisPopup),
		frame, pageLoc;
	dom.innerHTML = '';
	frame = dom.firstChild;
	frame.kernel = kernel;

	return {
		open: function (loc, force) {
			if (loc) {
				pageLoc = loc;
				if (frame.src === 'about:blank') {
					kernel.listeners.add(kernel.popupEvents, 'hide', popuphide);
					loc.args.ui = 'clean';
				}
				frame.src = kernel.buildHash(loc);
			} else if (frame.src === 'about:blank') {
				return true;
			}
			kernel.openPopup(thisPopup, !force);
		},
		onloadend: function () {
			kernel.setPopupTitle(pages[pageLoc.id].title);
		}
	};

	function popuphide() {
		kernel.listeners.remove(kernel.popupEvents, 'hide', popuphide);
		frame.src = 'about:blank';
	}
});<commit_msg>no message<commit_after>'use strict';
//this popup is for holding pages
define(['module', 'common/kernel/kernel', 'site/pages/pages'], function (module, kernel, pages) {
	let thisPopup = module.id.replace(/^[^/]+\/|\/[^/]+/g, ''),
		dom = document.querySelector('#popup>.content>.' + thisPopup),
		frame, pageLoc;
	dom.innerHTML = '';
	frame = dom.firstChild;
	frame.kernel = kernel;

	return {
		open: function (loc, force) {
			if (loc) {
				pageLoc = loc;
				if (frame.src === 'about:blank') {
					kernel.listeners.add(kernel.popupEvents, 'hide', popuphide);
					loc.args.ui = 'clean';
				}
				frame.src = kernel.buildHash(loc);
			}
			kernel.openPopup(thisPopup, !force);
		},
		onloadend: function () {
			kernel.setPopupTitle(pages[pageLoc.id].title);
		}
	};

	function popuphide() {
		kernel.listeners.remove(kernel.popupEvents, 'hide', popuphide);
		frame.src = 'about:blank';
	}
});<|endoftext|>


<commit_before>define([
    'jquery',
    'var/blankImg',
    'var/slice',
    'var/css_class',
    'function/trigger',
    'function/attach',
    'function/shortnameTo',
    'function/pasteHtmlAtCaret',
    'function/getOptions',
    'function/saveSelection',
    'function/restoreSelection',
    'function/htmlFromText',
    'function/textFromHtml',
    'function/isObject',
    'function/calcButtonPosition',
    'function/selector',
    'function/div'
],
function($, blankImg, slice, css_class, trigger, attach, shortnameTo, pasteHtmlAtCaret,
         getOptions, saveSelection, restoreSelection, htmlFromText, textFromHtml, isObject,
         calcButtonPosition, selector, div)
{
    return function(self, source, options) {
        options = getOptions(options);
        self.sprite     = options.sprite;
        self.shortnames = options.shortnames;
        self.pickerPosition = options.pickerPosition;

        var sourceValFunc = source.is("TEXTAREA") || source.is("INPUT") ? "val" : "text",
            editor, button, picker, tones, emojis, filters, filtersBtns, emojisList,
            app = div({"class" : css_class + " " + source.attr("class"), role: "application"},
                editor = self.editor = div('editor').attr({
                    contenteditable: true,
                    placeholder: options["placeholder"] || source.data("placeholder") || source.attr("placeholder") || "",
                    tabindex: 0
                }),
                button = self.button = div('button',
                    div('button-open'),
                    div('button-close')
                ).attr('title', options.buttonTitle),
                picker = self.picker = div('picker',
                    div('wrapper',
                        filters = div('filters'),
                        emojisList = div('emojis-list',
                            tones = div('tones'),
                            emojis = div('emojis')
                        )
                    )
                ).addClass(selector('picker-position-' + options.pickerPosition, true))
                 .addClass(selector('filters-position-' + options.filtersPosition, true))
                 .addClass('hidden')
            );

        for (var attr = ["dir", "spellcheck", "autocomplete", "autocorrect", "autocapitalize"], j=0; j<5; j++) {
            editor.attr(attr[j], options[attr[j]]);
        }

        $.each(options.filters, function(filter, params) {
            $("", {
                "class": selector("filter", true) + " " + selector("filter-" + filter, true),
                "data-filter": filter,
                title: params.title
            })
            .wrapInner(shortnameTo(params.icon, self.sprite ? '' : ''))
            .appendTo(filters);
        });

        editor.data('render_emojis', function() {
            editor.data('render_emojis', null);
            $.each(options.filters, function(filter, params) {
                emojisList.append('
' + params.title + '
');
                div('emojis').html(shortnameTo(params.emoji.replace(' ', ','), '<' +
                    (self.sprite ? 'i class="emojione-{uni}"' : 'img class="emojione" src="{img}"') +
                    ' data-name="{name}"/>') . split(','). join('')).appendTo(emojisList);
            });
            options.filters = null;
            attach(self, emojisList.find(".emojibtn"), {click: "emojibtn.click"});
        });

        filtersBtns = filters.find(selector("filter"));

        if (options.container) {
            $(options.container).wrapInner(app);
        } else {
            app.insertAfter(source);
        }

        if (options.hideSource) {
            source.hide();
        }

        self.setText(source[sourceValFunc]());
        calcButtonPosition.apply(self);

        attach(self, window, {resize: "!resize"});
        attach(self, [picker, button], {mousedown: "!mousedown"}, editor);
        attach(self, button, {click: "button.click"});
        attach(self, editor, {paste :"!paste"}, editor);
        attach(self, editor, ["focus", "blur"], function() { return self.stayFocused ? false : editor; });
        attach(self, [editor, picker], ["mousedown", "mouseup", "click", "keyup", "keydown", "keypress"], editor);
        attach(self, picker.find(".emojionearea-filter"), {click: "filter.click"});

        if (isObject(options.events) && !$.isEmptyObject(options.events)) {
            $.each(options.events, function(event, handler) {
                self.on(event.replace(/_/g, '.'), handler);
            });
        }

        self.on("@filter.click", function(filter) {
                if (!filter.is(".active")) {
                    filtersBtns.filter(".active").removeClass("active");
                    filter.addClass("active");
                }
            })

            .on("@button.click", function(button) {
                if (button.is(".active")) {
                    self.hidePicker();
                } else {
                    self.showPicker();
                }
            })

            .on("@!paste", function(editor) {
                self.stayFocused = true;
                // insert invisible character for fix caret position
                pasteHtmlAtCaret('');

                var sel = saveSelection(editor[0]),
                    editorScrollTop = editor.scrollTop(),
                    clipboard = $("
", {contenteditable: true})
                        .css({position: "fixed", left: "-999px", width: "1px", height: "1px", top: "20px", overflow: "hidden"})
                        .appendTo($("BODY"))
                        .focus();

                window.setTimeout(function() {
                    var caretID = "caret-" + (new Date()).getTime();
                    editor.focus();
                    restoreSelection(editor[0], sel);
                    var text = textFromHtml(clipboard.html().replace(/\r\n|\n|\r/g, '
'), self),
                        html = htmlFromText(text, self);
                    pasteHtmlAtCaret(html);
                    clipboard.remove();
                    pasteHtmlAtCaret('');
                    editor.scrollTop(editorScrollTop);
                    var caret = $("#" + caretID),
                        top = caret.offset().top - editor.offset().top,
                        height = editor.height();
                    if (editorScrollTop + top >= height || editorScrollTop > top) {
                        editor.scrollTop(editorScrollTop + top - 2 * height/3);
                    }
                    caret.remove();
                    self.stayFocused = false;
                    calcButtonPosition.apply(self);
                    trigger(self, 'paste', [editor, text, html]);
                }, 200);
            })

            .on("@emojibtn.click", function(emojibtn) {
                saveSelection(editor[0]);
                pasteHtmlAtCaret(shortnameTo(emojibtn.children().data("name"),
                    '' : '" src="{img}">')));
            })

            .on("@!resize @keyup @emojibtn.click", calcButtonPosition)

            .on("@!mousedown", function(editor, event) {
                if (!options.autoHideFilters && !app.is(".focused")) {
                    editor.focus();
                }
                event.preventDefault();
                return false;
            })

            .on("@change", function(editor) {
                var html = editor.html().replace(/<\/?(?:div|span|p)[^>]*>/ig, '');
                // clear input: chrome adds
 when contenteditable is empty
                if (!html.length || /^
]*>$/i.test(html)) {
                    self.setText('', false);
                }
                source[sourceValFunc](self.getText());
            })

            .on("@focus", function() {
                app.addClass("focused");
            })

            .on("@blur", function(editor) {
                app.removeClass("focused");

                if (options.hidePickerOnBlur) {
                    self.hidePicker();
                }

                var content = editor.html();
                if (self.content !== content) {
                    self.content = content;
                    trigger(self, 'change', [editor]);
                    source.blur().trigger("change");
                } else {
                    source.blur();
                }
            });
    };
});<commit_msg>Update<commit_after>define([
    'jquery',
    'var/blankImg',
    'var/slice',
    'var/css_class',
    'function/trigger',
    'function/attach',
    'function/shortnameTo',
    'function/pasteHtmlAtCaret',
    'function/getOptions',
    'function/saveSelection',
    'function/restoreSelection',
    'function/htmlFromText',
    'function/textFromHtml',
    'function/isObject',
    'function/calcButtonPosition',
    'function/selector',
    'function/div'
],
function($, blankImg, slice, css_class, trigger, attach, shortnameTo, pasteHtmlAtCaret,
         getOptions, saveSelection, restoreSelection, htmlFromText, textFromHtml, isObject,
         calcButtonPosition, selector, div)
{
    return function(self, source, options) {
        options = getOptions(options);
        self.sprite     = options.sprite;
        self.shortnames = options.shortnames;
        self.pickerPosition = options.pickerPosition;

        var sourceValFunc = source.is("TEXTAREA") || source.is("INPUT") ? "val" : "text",
            editor, button, picker, tones, emojis, filters, filtersBtns, emojisList, headers,
            app = div({"class" : css_class + " " + source.attr("class"), role: "application"},
                editor = self.editor = div('editor').attr({
                    contenteditable: true,
                    placeholder: options["placeholder"] || source.data("placeholder") || source.attr("placeholder") || "",
                    tabindex: 0
                }),
                button = self.button = div('button',
                    div('button-open'),
                    div('button-close')
                ).attr('title', options.buttonTitle),
                picker = self.picker = div('picker',
                    div('wrapper',
                        filters = div('filters'),
                        emojisList = div('emojis-list',
                            tones = div('tones'),
                            emojis = div('emojis')
                        )
                    )
                ).addClass(selector('picker-position-' + options.pickerPosition, true))
                 .addClass(selector('filters-position-' + options.filtersPosition, true))
                 .addClass('hidden')
            );

        for (var attr = ["dir", "spellcheck", "autocomplete", "autocorrect", "autocapitalize"], j=0; j<5; j++) {
            editor.attr(attr[j], options[attr[j]]);
        }

        $.each(options.filters, function(filter, params) {
            $("", {
                "class": selector("filter", true) + " " + selector("filter-" + filter, true),
                "data-filter": filter,
                title: params.title
            })
            .wrapInner(shortnameTo(params.icon, self.sprite ? '' : ''))
            .appendTo(filters);
        });

        editor.data('render_emojis', function() {
            editor.data('render_emojis', null);
            $.each(options.filters, function(filter, params) {
                emojisList.append('
' + params.title + '
');
                div('emojis').html(shortnameTo(params.emoji.replace(' ', ','), '<' +
                    (self.sprite ? 'i class="emojione-{uni}"' : 'img class="emojione" src="{img}"') +
                    ' data-name="{name}"/>') . split(','). join('')).appendTo(emojisList);
            });
            options.filters = null;
            attach(self, emojisList.find(".emojibtn"), {click: "emojibtn.click"});
            headers = emojisList.find("h1");
        });

        filtersBtns = filters.find(selector("filter"));
        filtersBtns.eq(0).addClass("active");

        var noListenScroll = false;
        emojisList.on('scroll', function () {
            if (!noListenScroll) {
                var item = headers.eq(0), scrollTop = emojisList.offset().top;
                headers.each(function (i, e) {
                    if ($(e).offset().top - scrollTop >= 3) {
                        return false;
                    }
                    item = $(e);
                });
                var filter = filtersBtns.filter('[data-filter="' + item.attr("name") + '"]');
                if (!filter.is(".active")) {
                    filtersBtns.removeClass("active");
                    filter.addClass("active");
                }
            }
        });

        if (options.container) {
            $(options.container).wrapInner(app);
        } else {
            app.insertAfter(source);
        }

        if (options.hideSource) {
            source.hide();
        }

        self.setText(source[sourceValFunc]());
        calcButtonPosition.apply(self);

        attach(self, window, {resize: "!resize"});
        attach(self, [picker, button], {mousedown: "!mousedown"}, editor);
        attach(self, button, {click: "button.click"});
        attach(self, editor, {paste :"!paste"}, editor);
        attach(self, editor, ["focus", "blur"], function() { return self.stayFocused ? false : editor; });
        attach(self, [editor, picker], ["mousedown", "mouseup", "click", "keyup", "keydown", "keypress"], editor);
        attach(self, picker.find(".emojionearea-filter"), {click: "filter.click"});

        if (isObject(options.events) && !$.isEmptyObject(options.events)) {
            $.each(options.events, function(event, handler) {
                self.on(event.replace(/_/g, '.'), handler);
            });
        }

        self.on("@filter.click", function(filter) {
                noListenScroll = true;
                if (!filter.is(".active")) {
                    filtersBtns.filter(".active").removeClass("active");
                    filter.addClass("active");
                }
                var headerOffset = emojisList.find('h1[name="' + filter.data('filter') + '"]').offset().top,
                    scroll = emojisList.scrollTop(),
                    offsetTop = emojisList.offset().top;
                emojisList.stop().animate({
                    scrollTop: headerOffset + scroll - offsetTop - 2
                }, 200, 'swing', function() {
                    noListenScroll = false;
                });
            })

            .on("@button.click", function(button) {
                if (button.is(".active")) {
                    self.hidePicker();
                } else {
                    self.showPicker();
                }
            })

            .on("@!paste", function(editor) {
                self.stayFocused = true;
                // insert invisible character for fix caret position
                pasteHtmlAtCaret('');

                var sel = saveSelection(editor[0]),
                    editorScrollTop = editor.scrollTop(),
                    clipboard = $("
", {contenteditable: true})
                        .css({position: "fixed", left: "-999px", width: "1px", height: "1px", top: "20px", overflow: "hidden"})
                        .appendTo($("BODY"))
                        .focus();

                window.setTimeout(function() {
                    var caretID = "caret-" + (new Date()).getTime();
                    editor.focus();
                    restoreSelection(editor[0], sel);
                    var text = textFromHtml(clipboard.html().replace(/\r\n|\n|\r/g, '
'), self),
                        html = htmlFromText(text, self);
                    pasteHtmlAtCaret(html);
                    clipboard.remove();
                    pasteHtmlAtCaret('');
                    editor.scrollTop(editorScrollTop);
                    var caret = $("#" + caretID),
                        top = caret.offset().top - editor.offset().top,
                        height = editor.height();
                    if (editorScrollTop + top >= height || editorScrollTop > top) {
                        editor.scrollTop(editorScrollTop + top - 2 * height/3);
                    }
                    caret.remove();
                    self.stayFocused = false;
                    calcButtonPosition.apply(self);
                    trigger(self, 'paste', [editor, text, html]);
                }, 200);
            })

            .on("@emojibtn.click", function(emojibtn) {
                saveSelection(editor[0]);
                pasteHtmlAtCaret(shortnameTo(emojibtn.children().data("name"),
                    '' : '" src="{img}">')));
            })

            .on("@!resize @keyup @emojibtn.click", calcButtonPosition)

            .on("@!mousedown", function(editor, event) {
                if (!options.autoHideFilters && !app.is(".focused")) {
                    editor.focus();
                }
                event.preventDefault();
                return false;
            })

            .on("@change", function(editor) {
                var html = editor.html().replace(/<\/?(?:div|span|p)[^>]*>/ig, '');
                // clear input: chrome adds
 when contenteditable is empty
                if (!html.length || /^
]*>$/i.test(html)) {
                    self.setText('', false);
                }
                source[sourceValFunc](self.getText());
            })

            .on("@focus", function() {
                app.addClass("focused");
            })

            .on("@blur", function(editor) {
                app.removeClass("focused");

                if (options.hidePickerOnBlur) {
                    self.hidePicker();
                }

                var content = editor.html();
                if (self.content !== content) {
                    self.content = content;
                    trigger(self, 'change', [editor]);
                    source.blur().trigger("change");
                } else {
                    source.blur();
                }
            });
    };
});<|endoftext|>


<commit_before>/**
 * A basic JS based dice roller
 *
 * GreenImp Web - greenimp.co.uk
 */

;(function(){
  "use strict";

  window.DiceRoller = function(){
    var lib = this;

    this.log  = []; // a history of rolls

    /**
     * Checks if the given val is a valid number
     *
     * @param val
     * @returns {boolean}
     */
    var isNumeric       = function(val){
      return !Array.isArray(val) && ((val- parseFloat(val) + 1) >= 0);
    };

    /**
     * Generates a random number between the
     * min and max, inclusive
     *
     * @param {number} min
     * @param {number} max
     * @returns {*}
     */
    var generateNumber  = function(min, max){
      min = min ? parseInt(min, 10) : 1;
      max = max ? parseInt(max, 10) : min;

      if(max <= min){
        return min;
      }

      return Math.floor(Math.random() * (max - min + 1) + min);
    };

    /**
     * Takes an array of numbers adds them
     * together and returns the total
     *
     * @param {array} numbers
     * @returns {number}
     */
    var totalNumbers    = function(numbers){
      return numbers.reduce(function(prev, current){
        return current + prev;
      }, 0);
    };

    /**
     * Takes a list of dice rolls and returns
     * the total value.
     * If no `rolls` is defined, the log is used
     *
     * @param {Array=} rolls
     * @returns {number}
     */
    var getRollTotals   = function(rolls){
      rolls = (rolls && Array.isArray(rolls)) ? rolls : lib.log;

      // add the totals together
      return rolls.reduce(function(prev, current){
        return (current.total || 0) + prev;
      }, 0);
    };

    /**
     * Returns the String representation of the object
     *
     * @returns {string}
     */
    this.toString = function(){
      var response  = '';

      // loop through each dice log and build the response
      lib.log.forEach(function(elm, index, array){
        // add the rolls to the string
        response += elm.die + ': ' + elm.rolls.join(', ') + ' = ' + elm.total + '; ';
      });

      // output the total
      if(lib.log.length){
        response += 'Total = ' + getRollTotals();
      }else{
        response = 'No dice rolled';
      }

      // return the response
      return response;
    };

    /**
     * Parses the given value for a single die
     * and returns the number of die sides and
     * required quantity
     *
     * @param val
     * @returns {number|object}
     */
    this.parseDie   = function(val){
      var die;

      if(!val){
        return die;
      }else if(isNumeric(val)){
        // value is a number - ensure that it's an integer
        val = parseInt(val, 10);

        if(val > 0){
          die = val;
        }
      }else if(typeof val === 'string'){
        if(val.indexOf('d') >= 0){
          // just a single die
          var parts = val.split(/d/),
              sides = lib.parseDie(parts[(parts.length == 2) ? 1 : 0]),
              qty   = ((parts.length == 2) && isNumeric(parts[0])) ? parseInt(parts[0], 10) : 1;

          // only define the die if the sides are valid
          if(sides){
            if(qty > 1){
              die = {
                sides: sides,
                qty: (parts.length == 2) ? parseInt(parts[0], 10) : 1
              };
            }else{
              die = sides;
            }
          }
        }
      }

      return die;
    };

    /**
     * Parses the given value for specified dice
     * and returns a list of dice found
     *
     * @param {string|number|Array} val
     * @returns {Array}
     */
    this.parseDice   = function(val){
      var dice  = [];

      // ensure that val is valid and an array
      if(!val){
        // val is falsey - return empty result
        return dice;
      }else if(!Array.isArray(val)){
        // val is NOt an array
        if((typeof val === 'string') && (val.indexOf('+') >= 0)){
          // val is a string with concatenated dice values - split by the join
          val = val.split(/\+/);
        }else{
          // convert to an array
          val = [val];
        }
      }

      // loop through the given dice list and parse them
      val.forEach(function(elm, index, array){
        var die = lib.parseDie(elm);

        // only add the die if it is valid
        if(die){
          dice.push(die);
        }
      });

      // return the list of dice
      return dice;
    };

    /**
     * Rolls the given dice sides for the
     * set amount of rolls.
     * Returns a list of results
     *
     * @param {string} dice
     * @returns {Array}
     */
    this.roll = function(dice){
      var pDice = lib.parseDice(dice);

      lib.log  = [];

      pDice.forEach(function(elm, index, array){
        var sides   = elm.sides || elm,
            qty     = elm.qty || 1,
            rolls   = [];

        if(sides){
          for(var i = 0; i < qty; i++){
            rolls.push(generateNumber(1, sides));
          }

          lib.log.push({
            die:    qty + 'd' + sides,
            rolls:  rolls,
            total:  totalNumbers(rolls)
          });
        }
      });

      return lib.log;
    };
  }
}(window));
<commit_msg>Corrects funcion comment variable type capitalisation<commit_after>/**
 * A basic JS based dice roller
 *
 * GreenImp Web - greenimp.co.uk
 */

;(function(){
  "use strict";

  window.DiceRoller = function(){
    var lib = this;

    this.log  = []; // a history of rolls

    /**
     * Checks if the given val is a valid number
     *
     * @param val
     * @returns {boolean}
     */
    var isNumeric       = function(val){
      return !Array.isArray(val) && ((val- parseFloat(val) + 1) >= 0);
    };

    /**
     * Generates a random number between the
     * min and max, inclusive
     *
     * @param {number} min
     * @param {number} max
     * @returns {*}
     */
    var generateNumber  = function(min, max){
      min = min ? parseInt(min, 10) : 1;
      max = max ? parseInt(max, 10) : min;

      if(max <= min){
        return min;
      }

      return Math.floor(Math.random() * (max - min + 1) + min);
    };

    /**
     * Takes an array of numbers adds them
     * together and returns the total
     *
     * @param {Array} numbers
     * @returns {number}
     */
    var totalNumbers    = function(numbers){
      return numbers.reduce(function(prev, current){
        return current + prev;
      }, 0);
    };

    /**
     * Takes a list of dice rolls and returns
     * the total value.
     * If no `rolls` is defined, the log is used
     *
     * @param {Array=} rolls
     * @returns {number}
     */
    var getRollTotals   = function(rolls){
      rolls = (rolls && Array.isArray(rolls)) ? rolls : lib.log;

      // add the totals together
      return rolls.reduce(function(prev, current){
        return (current.total || 0) + prev;
      }, 0);
    };

    /**
     * Returns the String representation of the object
     *
     * @returns {string}
     */
    this.toString = function(){
      var response  = '';

      // loop through each dice log and build the response
      lib.log.forEach(function(elm, index, array){
        // add the rolls to the string
        response += elm.die + ': ' + elm.rolls.join(', ') + ' = ' + elm.total + '; ';
      });

      // output the total
      if(lib.log.length){
        response += 'Total = ' + getRollTotals();
      }else{
        response = 'No dice rolled';
      }

      // return the response
      return response;
    };

    /**
     * Parses the given value for a single die
     * and returns the number of die sides and
     * required quantity
     *
     * @param val
     * @returns {number|object}
     */
    this.parseDie   = function(val){
      var die;

      if(!val){
        return die;
      }else if(isNumeric(val)){
        // value is a number - ensure that it's an integer
        val = parseInt(val, 10);

        if(val > 0){
          die = val;
        }
      }else if(typeof val === 'string'){
        if(val.indexOf('d') >= 0){
          // just a single die
          var parts = val.split(/d/),
              sides = lib.parseDie(parts[(parts.length == 2) ? 1 : 0]),
              qty   = ((parts.length == 2) && isNumeric(parts[0])) ? parseInt(parts[0], 10) : 1;

          // only define the die if the sides are valid
          if(sides){
            if(qty > 1){
              die = {
                sides: sides,
                qty: (parts.length == 2) ? parseInt(parts[0], 10) : 1
              };
            }else{
              die = sides;
            }
          }
        }
      }

      return die;
    };

    /**
     * Parses the given value for specified dice
     * and returns a list of dice found
     *
     * @param {string|number|Array} val
     * @returns {Array}
     */
    this.parseDice   = function(val){
      var dice  = [];

      // ensure that val is valid and an array
      if(!val){
        // val is falsey - return empty result
        return dice;
      }else if(!Array.isArray(val)){
        // val is NOt an array
        if((typeof val === 'string') && (val.indexOf('+') >= 0)){
          // val is a string with concatenated dice values - split by the join
          val = val.split(/\+/);
        }else{
          // convert to an array
          val = [val];
        }
      }

      // loop through the given dice list and parse them
      val.forEach(function(elm, index, array){
        var die = lib.parseDie(elm);

        // only add the die if it is valid
        if(die){
          dice.push(die);
        }
      });

      // return the list of dice
      return dice;
    };

    /**
     * Rolls the given dice sides for the
     * set amount of rolls.
     * Returns a list of results
     *
     * @param {string} dice
     * @returns {Array}
     */
    this.roll = function(dice){
      var pDice = lib.parseDice(dice);

      lib.log  = [];

      pDice.forEach(function(elm, index, array){
        var sides   = elm.sides || elm,
            qty     = elm.qty || 1,
            rolls   = [];

        if(sides){
          for(var i = 0; i < qty; i++){
            rolls.push(generateNumber(1, sides));
          }

          lib.log.push({
            die:    qty + 'd' + sides,
            rolls:  rolls,
            total:  totalNumbers(rolls)
          });
        }
      });

      return lib.log;
    };
  }
}(window));
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import { Grid, Container, Row, Col, Form, FormGroup, FormControl, ControlLabel, Input, Button, ButtonGroup, Glyphicon } from 'react-bootstrap';
import {reduxForm} from 'redux-form';

class PatronForm extends Component {
  static propTypes = {
    fields: PropTypes.object.isRequired,
    initializeForm: PropTypes.func.isRequired,
    handleSubmit: PropTypes.func.isRequired,
    cancelForm: PropTypes.func.isRequired,
    resetForm: PropTypes.func.isRequired,
    submitting: PropTypes.bool.isRequired
  };

  static defaultProps = {
  };

  render() {
    const {
      fields: {patron_name,patron_code,contact_info,total_fines_paid,total_loans,status,patron_barcode,total_fines},
      handleSubmit,
      cancelForm,
      resetForm,
      submitting
    } = this.props;
    return (

        <Form inline>

Add Patron

          <Row>
            <Col componentClass={ControlLabel} sm={2}>
              Name
            </Col>
            <Col sm={10}>
              <FormControl type='text' placeholder="Patron's name" {...patron_name} />
            </Col>
          </Row>
          <Row>
            <Col componentClass={ControlLabel} sm={2}>
              Code
            </Col>
            <Col sm={10}>
              <FormControl type='text' placeholder="Patron's code" {...patron_code} />
            </Col>
          </Row>
          <Row>
            <Col componentClass={ControlLabel} sm={2}>
              ContactInfo
            </Col>
            <Col sm={10}>
              <FormControl type='text' placeholder="Contact Info" {...contact_info} />
            </Col>
          </Row>
          <Row>
            <Col componentClass={ControlLabel} sm={2}>
              Fines paid
            </Col>
            <Col sm={10}>
              <FormControl type='text' placeholder="Total fines paid" {...total_fines_paid} />
            </Col>
          </Row>
          <Row>
            <Col componentClass={ControlLabel} sm={2}>
              Loans
            </Col>
            <Col sm={10}>
              <FormControl type='text' placeholder="Total loans" {...total_loans} />
            </Col>
          </Row>
          <Row>
            <Col componentClass={ControlLabel} sm={2}>
              Status
            </Col>
            <Col sm={10}>
              <FormControl type='text' placeholder="Patron's status" {...status} />
            </Col>
          </Row>
          <Row>
            <Col componentClass={ControlLabel} sm={2}>
              Barcode
            </Col>
            <Col sm={10}>
              <FormControl type='text' placeholder="Patron's barcode" {...patron_barcode} />
            </Col>
          </Row>
          <Row>
            <Col componentClass={ControlLabel} sm={2}>
              Fines
            </Col>
            <Col sm={10}>
              <FormControl type='text' placeholder="Total fines" {...total_fines} />
            </Col>
          </Row>

          <ButtonGroup>
            <Button bsStyle='primary' disabled={submitting} onClick={handleSubmit}>Save Patron</Button>
            <Button disabled={submitting} onClick={resetForm}>Reset</Button>
            <Button disabled={submitting} onClick={cancelForm}>Cancel</Button>
          </ButtonGroup>
        </Form>

    );
  }
}

export default reduxForm(
  {
    form: 'patronForm',
    fields: ['patron_name','patron_code','contact_info','total_fines_paid','total_loans','status','patron_barcode','total_fines']
  }
)(PatronForm);

<commit_msg>Parameterizes title, button label in patrons form<commit_after>import React, { Component, PropTypes } from 'react';
import { Grid, Container, Row, Col, Form, FormGroup, FormControl, ControlLabel, Input, Button, ButtonGroup, Glyphicon } from 'react-bootstrap';
import {reduxForm} from 'redux-form';

class PatronForm extends Component {

  static propTypes = {
    fields: PropTypes.object.isRequired,
    initializeForm: PropTypes.func.isRequired,
    handleSubmit: PropTypes.func.isRequired,
    cancelForm: PropTypes.func.isRequired,
    resetForm: PropTypes.func.isRequired,
    submitting: PropTypes.bool.isRequired
  };

  static actionTypes = {'create' : { title: 'Add Patron', submitLabel: 'Save Patron'},
                        'update' : { title: 'Edit Patron', submitLabel: 'Save Changes'}};

  render() {
    const {
      fields: {patron_name,patron_code,contact_info,total_fines_paid,total_loans,status,patron_barcode,total_fines},
      handleSubmit,
      cancelForm,
      resetForm,
      submitting,
      action
    } = this.props;
    return (

        <Form inline>

{action ? action.title : 'Patron'}

          <Row>
            <Col componentClass={ControlLabel} sm={2}>
              Name
            </Col>
            <Col sm={10}>
              <FormControl type='text' placeholder="Patron's name" {...patron_name} />
            </Col>
          </Row>
          <Row>
            <Col componentClass={ControlLabel} sm={2}>
              Code
            </Col>
            <Col sm={10}>
              <FormControl type='text' placeholder="Patron's code" {...patron_code} />
            </Col>
          </Row>
          <Row>
            <Col componentClass={ControlLabel} sm={2}>
              ContactInfo
            </Col>
            <Col sm={10}>
              <FormControl type='text' placeholder="Contact Info" {...contact_info} />
            </Col>
          </Row>
          <Row>
            <Col componentClass={ControlLabel} sm={2}>
              Fines paid
            </Col>
            <Col sm={10}>
              <FormControl type='text' placeholder="Total fines paid" {...total_fines_paid} />
            </Col>
          </Row>
          <Row>
            <Col componentClass={ControlLabel} sm={2}>
              Loans
            </Col>
            <Col sm={10}>
              <FormControl type='text' placeholder="Total loans" {...total_loans} />
            </Col>
          </Row>
          <Row>
            <Col componentClass={ControlLabel} sm={2}>
              Status
            </Col>
            <Col sm={10}>
              <FormControl type='text' placeholder="Patron's status" {...status} />
            </Col>
          </Row>
          <Row>
            <Col componentClass={ControlLabel} sm={2}>
              Barcode
            </Col>
            <Col sm={10}>
              <FormControl type='text' placeholder="Patron's barcode" {...patron_barcode} />
            </Col>
          </Row>
          <Row>
            <Col componentClass={ControlLabel} sm={2}>
              Fines
            </Col>
            <Col sm={10}>
              <FormControl type='text' placeholder="Total fines" {...total_fines} />
            </Col>
          </Row>

          <ButtonGroup>
            <Button bsStyle='primary' disabled={submitting} onClick={handleSubmit}>{action ? action.submitLabel : 'Save'}</Button>
            <Button disabled={submitting} onClick={resetForm}>Reset</Button>
            <Button disabled={submitting} onClick={cancelForm}>Cancel</Button>
          </ButtonGroup>
        </Form>

    );
  }
}

export default reduxForm(
  {
    form: 'patronForm',
    fields: ['patron_name','patron_code','contact_info','total_fines_paid','total_loans','status','patron_barcode','total_fines']
  }
)(PatronForm);

<|endoftext|>