<commit_before>//node-modules
var request = require('request');
var jsdom = require("jsdom");
var dom = new jsdom.JSDOM(`<!DOCTYPE html>`);
var $ = require("jquery")(dom.window);
var fs = require('fs');
var url = require('url');
var xml = require('xml');
var ArgumentParser = require('argparse').ArgumentParser;
var parser = new ArgumentParser({
    version: '0.0.1',
    addHelp: true,
    description: 'This node-js crawler searches through a steam-tag-name and lists every discount with percentage and price. The export of the result is on your side.'
});
parser.addArgument(
    ['-m', '--minutes'], {
        help: 'Process-Interval in minutes -> min value is 5 [DEFAULT: 60]',
        type: 'int',
        choices: [">= 5"]
    }
);
parser.addArgument(
    ['-i', '--interval'], {
        help: 'determine if the process should be executed in an interval, or just once [DEFAULT: false]',
        choices: [true, false]
    }
);
parser.addArgument(
    ['-l', '--log'], {
        help: 'Log actions into a seperate file for each day [DEFAULT: true]',
        choices: [true, false]
    }
);
parser.addArgument(
    ['-e', '--export'], {
        help: 'Log actions into a seperate file for each day [DEFAULT: found in ./config.json]',
        choices: ["JSON", "HTML", "XML"]
    }
);
var args = parser.parseArgs();

//globals
const GLOBALS = {
        T_INTERVAL: args.minutes !== null ? args.minutes < 5 ? (60000 * 5) : (args.minutes * 60000) : (60000 * 60),
        T_INTERVAL_SET: args.interval !== null ? !(args.minutes == 'true') : false,
        LOG_ACTIONS: args.log !== null ? !(args.log == 'false') : true
    }
    //global variables
const CONFIG = JSON.parse(fs.readFileSync('./data/config.json', 'utf8'));
const SETTINGS = {
    FILE_PATH: CONFIG.saveConfig.filePath,
    LOG_PATH: CONFIG.saveConfig.logPath,
    ID_ARRAY: CONFIG.tag_id_list,
    EXPORT_TYPE: args.export !== null ? args.export : CONFIG.saveConfig.exportType,
    INITIALIZE_OLDITEMS: true,
    DEBUG: true
}
var globalVariables = {
    globalTagList: {},
    callBackCount: 0,
    gamesWithDiscound: {},
    today: null,
    todayDate: null
}

//main function for recursive iteration through results
function findDiscountsWithPerTag(object, pageResults) {
    if (typeof pageResults === 'undefined') { pageResults = 0; }

    var tagId = object.id;
    var specificTagList = object.taglist;
    globalVariables.globalTagList[tagId] = object.name;
    var extraTagList = "";

    //taglists are used to filter-results even further
    if (typeof specificTagList !== 'undefined' && specificTagList.length > 0) {
        $(specificTagList).each(function(i, el) {
            extraTagList += "&tag[" + i + "]=" + el;
        })
    }

    //request-options
    var options = {
        url: 'http://store.steampowered.com/tagdata/querypaginated/de/' + tagId + '/Discounts/render/?query=&start=' + pageResults + '&count=10&cc=DE&l=german&no_violence=0&no_sex=0&v=4' + extraTagList,
        method: 'GET',
        json: true
    }
    request(options, function(error, response, json_body) {
        if (error) { console.log(error); } else {
            body = "
" + json_body["results_html"] + "
";
            $(body).find('a').each(function(index, game) {
                //to cut the '?snr=1_237_1600__106_5' from the url and minimize the data
                var myurl = url.parse($(game).attr("href"), true);
                var v_link = myurl.host + myurl.pathname;
                var v_id = $(game).data("ds-appid");
                var v_name = $(game).find('div.tab_item_content > div.tab_item_name').text();
                var v_price = $(game).find('div.discount_block > div.discount_prices > div.discount_final_price').text();
                var v_discount = $(game).find('div.discount_block > div.discount_pct').text();
                if (!globalVariables.gamesWithDiscound.hasOwnProperty(tagId)) {
                    globalVariables.gamesWithDiscound[tagId] = [];
                }

                globalVariables.gamesWithDiscound[tagId].push({ _id: v_id, _name: v_name, _price: v_price, _discount: v_discount, _link: v_link });
            });

            if (json_body["total_count"] >= pageResults + 10) {
                findDiscountsWithPerTag(object, pageResults + 10);
            } else {
                callBack();
            }

        }
    });

}

//callBack and logging/exporting data
function callBack() {
    globalVariables.callBackCount++;
    if (SETTINGS.ID_ARRAY.length == globalVariables.callBackCount) {
        var saved_data_string = fs.readFileSync(SETTINGS.FILE_PATH, 'utf8');
        var saved_data = JSON.parse(saved_data_string == "" ? "{}" : saved_data_string);
        if (GLOBALS.LOG_ACTIONS) {

            var i = 0;

            for (var key in globalVariables.gamesWithDiscound) {
                if (!globalVariables.gamesWithDiscound.hasOwnProperty(key)) continue;

                var obj = globalVariables.gamesWithDiscound[key];
                var logMessage = "[STATUS] Found " + obj.length + " reduced games for Category-Tag: " + globalVariables.globalTagList[key];
                logAction(logMessage);
                if (saved_data.hasOwnProperty(key)) {
                    var saved_obj = saved_data[key];
                }
                obj.forEach(function(single_obj) {
                    var newEntry = true;
                    if (saved_obj !== undefined) {

                        saved_obj.forEach(function(single_saved_obj) {

                            if (single_saved_obj._id == single_obj._id) {
                                newEntry = false;
                            }

                        });
                    }

                    if (newEntry && SETTINGS.INITIALIZE_OLDITEMS) {
                        var singleLogMessage = "[NEW] " + single_obj._name + " with " + single_obj._discount + " to " + single_obj._price;
                        i++;
                        logAction(singleLogMessage);
                    }
                })
            }

            if (i > 0 && SETTINGS.INITIALIZE_OLDITEMS) {
                logAction("[END] " + i + " new Entrys.");
            } else {
                logAction("[END] Nothing new found.");
            }
        }
        fs.writeFile(SETTINGS.FILE_PATH, JSON.stringify(globalVariables.gamesWithDiscound), 'utf-8', function(err) {
            if (err) console.log(err);
        });

        exportData();
    }
}

//logging-helper
function logAction(content) {
    content = globalVariables.todayDate + " " + content;
    var logFileName = SETTINGS.LOG_PATH + (globalVariables.today.getMonth() + 1) + '_' + globalVariables.today.getDate() + '_' + globalVariables.today.getFullYear() + '.log';
    SETTINGS.DEBUG ? console.log(content) : "";
    fs.appendFile(logFileName, content + "\n", 'utf-8', function(err) {
        if (err) console.log(err);
    });
}

//main-function
function execute() {
    globalVariables.today = new Date();
    globalVariables.todayDate = "[" + (globalVariables.today.getMonth() + 1) + '/' + globalVariables.today.getDate() + '/' + globalVariables.today.getFullYear() + " " + (globalVariables.today.getHours() < 10 ? "0" + globalVariables.today.getHours() : globalVariables.today.getHours()) + ":" + (globalVariables.today.getMinutes() < 10 ? "0" + globalVariables.today.getMinutes() : globalVariables.today.getMinutes()) + "]";
    SETTINGS.DEBUG ? console.log(globalVariables.todayDate + " [START] Executing main-functionality") : "";
    SETTINGS.ID_ARRAY.forEach(function(object) {
        findDiscountsWithPerTag(object, 0);
    });
}

//export the result to a specific export-type
function exportData() {
    var types = SETTINGS.EXPORT_TYPE.split("|");
    types.forEach(function(single_type) {
        switch (single_type) {
            case "JSON":
                //exportData[tagId] = { _id, _name, _price, _discount, _link }
                fs.writeFile('./data/export/export_json.json', JSON.stringify(globalVariables.gamesWithDiscound), 'utf-8', function(err) {
                    if (err) console.log(err);
                });
                break;
            case "XML":
                var gwdXml = {};
                var gwdXmlObject = [];
                for (var key in globalVariables.gamesWithDiscound) {
                    var singleXmlObj = {};
                    var singleObj = globalVariables.gamesWithDiscound[key];
                    var ar = [];
                    singleObj.forEach(function(so, index) {
                        ar.push({ item: [{ _id: so._id }, { _name: so._name }, { _price: so._price }, { _discount: so._discount }, { _link: so._link }] });
                        singleXmlObj["items"] = ar;
                    });
                    gwdXmlObject.push({ tagname: [{ _attr: { attributes: key } }, singleXmlObj] });
                    gwdXml["tags"] = gwdXmlObject;
                }
                //exportData[tagId] = { _id, _name, _price, _discount, _link }
                fs.writeFile('./data/export/export_xml.xml', xml(gwdXml), 'utf-8', function(err) {
                    if (err) console.log(err);
                });
                break;
            case "HTML":
                var htmlContent = '<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

';

                for (var key in globalVariables.gamesWithDiscound) {
                    var singleObj = globalVariables.gamesWithDiscound[key];
                    htmlContent += '
Categorie: ' + globalVariables.globalTagList[key] + ' (' + key + ')
';
                    htmlContent += '

Game	Discount	New Price

';
                    singleObj.forEach(function(so, index) {
                        htmlContent += '
' + so._name + '	 ' + so._discount + '	' + so._price + '
';
                    });
                    htmlContent += '

';

                }
                htmlContent += '
';

                fs.writeFile('./data/export/export_html.html', htmlContent, 'utf-8', function(err) {
                    if (err) console.log(err);
                });
                break;
            default:
                console.log(single_type + " is not a valid Export-Type.");
                break;
        }
    });

    globalVariables.globalTagList = {};
    globalVariables.callBackCount = 0;
    globalVariables.gamesWithDiscound = {};
}

//RUN
if (GLOBALS.T_INTERVAL_SET) {
    execute();
    setInterval(function() { execute(); }, GLOBALS.T_INTERVAL);
} else {
    execute();
}<commit_msg>log-folder is created if not existing in first place<commit_after>//node-modules
var request = require('request');
var jsdom = require("jsdom");
var dom = new jsdom.JSDOM(`<!DOCTYPE html>`);
var $ = require("jquery")(dom.window);
var fs = require('fs');
var url = require('url');
var xml = require('xml');
var ArgumentParser = require('argparse').ArgumentParser;
var parser = new ArgumentParser({
    version: '0.0.1',
    addHelp: true,
    description: 'This node-js crawler searches through a steam-tag-name and lists every discount with percentage and price. The export of the result is on your side.'
});
parser.addArgument(
    ['-m', '--minutes'], {
        help: 'Process-Interval in minutes -> min value is 5 [DEFAULT: 60]',
        type: 'int',
        choices: [">= 5"]
    }
);
parser.addArgument(
    ['-i', '--interval'], {
        help: 'determine if the process should be executed in an interval, or just once [DEFAULT: false]',
        choices: [true, false]
    }
);
parser.addArgument(
    ['-l', '--log'], {
        help: 'Log actions into a seperate file for each day [DEFAULT: true]',
        choices: [true, false]
    }
);
parser.addArgument(
    ['-e', '--export'], {
        help: 'Log actions into a seperate file for each day [DEFAULT: found in ./config.json]',
        choices: ["JSON", "HTML", "XML"]
    }
);
var args = parser.parseArgs();

//globals
const GLOBALS = {
        T_INTERVAL: args.minutes !== null ? args.minutes < 5 ? (60000 * 5) : (args.minutes * 60000) : (60000 * 60),
        T_INTERVAL_SET: args.interval !== null ? !(args.minutes == 'true') : false,
        LOG_ACTIONS: args.log !== null ? !(args.log == 'false') : true
    }
    //global variables
const CONFIG = JSON.parse(fs.readFileSync('./data/config.json', 'utf8'));
const SETTINGS = {
    FILE_PATH: CONFIG.saveConfig.filePath,
    LOG_PATH: CONFIG.saveConfig.logPath,
    ID_ARRAY: CONFIG.tag_id_list,
    EXPORT_TYPE: args.export !== null ? args.export : CONFIG.saveConfig.exportType,
    INITIALIZE_OLDITEMS: true,
    DEBUG: true
}
var globalVariables = {
    globalTagList: {},
    callBackCount: 0,
    gamesWithDiscound: {},
    today: null,
    todayDate: null
}

//main function for recursive iteration through results
function findDiscountsWithPerTag(object, pageResults) {
    if (typeof pageResults === 'undefined') { pageResults = 0; }

    var tagId = object.id;
    var specificTagList = object.taglist;
    globalVariables.globalTagList[tagId] = object.name;
    var extraTagList = "";

    //taglists are used to filter-results even further
    if (typeof specificTagList !== 'undefined' && specificTagList.length > 0) {
        $(specificTagList).each(function(i, el) {
            extraTagList += "&tag[" + i + "]=" + el;
        })
    }

    //request-options
    var options = {
        url: 'http://store.steampowered.com/tagdata/querypaginated/de/' + tagId + '/Discounts/render/?query=&start=' + pageResults + '&count=10&cc=DE&l=german&no_violence=0&no_sex=0&v=4' + extraTagList,
        method: 'GET',
        json: true
    }
    request(options, function(error, response, json_body) {
        if (error) { console.log(error); } else {
            body = "
" + json_body["results_html"] + "
";
            $(body).find('a').each(function(index, game) {
                //to cut the '?snr=1_237_1600__106_5' from the url and minimize the data
                var myurl = url.parse($(game).attr("href"), true);
                var v_link = myurl.host + myurl.pathname;
                var v_id = $(game).data("ds-appid");
                var v_name = $(game).find('div.tab_item_content > div.tab_item_name').text();
                var v_price = $(game).find('div.discount_block > div.discount_prices > div.discount_final_price').text();
                var v_discount = $(game).find('div.discount_block > div.discount_pct').text();
                if (!globalVariables.gamesWithDiscound.hasOwnProperty(tagId)) {
                    globalVariables.gamesWithDiscound[tagId] = [];
                }

                globalVariables.gamesWithDiscound[tagId].push({ _id: v_id, _name: v_name, _price: v_price, _discount: v_discount, _link: v_link });
            });

            if (json_body["total_count"] >= pageResults + 10) {
                findDiscountsWithPerTag(object, pageResults + 10);
            } else {
                callBack();
            }

        }
    });

}

//callBack and logging/exporting data
function callBack() {
    globalVariables.callBackCount++;
    if (SETTINGS.ID_ARRAY.length == globalVariables.callBackCount) {
        var saved_data_string = fs.readFileSync(SETTINGS.FILE_PATH, 'utf8');
        var saved_data = JSON.parse(saved_data_string == "" ? "{}" : saved_data_string);
        if (GLOBALS.LOG_ACTIONS) {

            var i = 0;

            for (var key in globalVariables.gamesWithDiscound) {
                if (!globalVariables.gamesWithDiscound.hasOwnProperty(key)) continue;

                var obj = globalVariables.gamesWithDiscound[key];
                var logMessage = "[STATUS] Found " + obj.length + " reduced games for Category-Tag: " + globalVariables.globalTagList[key];
                logAction(logMessage);
                if (saved_data.hasOwnProperty(key)) {
                    var saved_obj = saved_data[key];
                }
                obj.forEach(function(single_obj) {
                    var newEntry = true;
                    if (saved_obj !== undefined) {

                        saved_obj.forEach(function(single_saved_obj) {

                            if (single_saved_obj._id == single_obj._id) {
                                newEntry = false;
                            }

                        });
                    }

                    if (newEntry && SETTINGS.INITIALIZE_OLDITEMS) {
                        var singleLogMessage = "[NEW] " + single_obj._name + " with " + single_obj._discount + " to " + single_obj._price;
                        i++;
                        logAction(singleLogMessage);
                    }
                })
            }

            if (i > 0 && SETTINGS.INITIALIZE_OLDITEMS) {
                logAction("[END] " + i + " new Entrys.");
            } else {
                logAction("[END] Nothing new found.");
            }
        }
        fs.writeFile(SETTINGS.FILE_PATH, JSON.stringify(globalVariables.gamesWithDiscound), 'utf-8', function(err) {
            if (err) console.log(err);
        });

        exportData();
    }
}

//logging-helper
function logAction(content) {
    var dir = "./logs";
    if (!fs.existsSync(dir)) {
        fs.mkdirSync(dir);
    }
    content = globalVariables.todayDate + " " + content;
    var logFileName = SETTINGS.LOG_PATH + (globalVariables.today.getMonth() + 1) + '_' + globalVariables.today.getDate() + '_' + globalVariables.today.getFullYear() + '.log';
    SETTINGS.DEBUG ? console.log(content) : "";
    fs.appendFile(logFileName, content + "\n", 'utf-8', function(err) {
        if (err) console.log(err);
    });
}

//main-function
function execute() {
    globalVariables.today = new Date();
    globalVariables.todayDate = "[" + (globalVariables.today.getMonth() + 1) + '/' + globalVariables.today.getDate() + '/' + globalVariables.today.getFullYear() + " " + (globalVariables.today.getHours() < 10 ? "0" + globalVariables.today.getHours() : globalVariables.today.getHours()) + ":" + (globalVariables.today.getMinutes() < 10 ? "0" + globalVariables.today.getMinutes() : globalVariables.today.getMinutes()) + "]";
    SETTINGS.DEBUG ? console.log(globalVariables.todayDate + " [START] Executing main-functionality") : "";
    SETTINGS.ID_ARRAY.forEach(function(object) {
        findDiscountsWithPerTag(object, 0);
    });
}

//export the result to a specific export-type
function exportData() {
    var types = SETTINGS.EXPORT_TYPE.split("|");
    types.forEach(function(single_type) {
        switch (single_type) {
            case "JSON":
                //exportData[tagId] = { _id, _name, _price, _discount, _link }
                fs.writeFile('./data/export/export_json.json', JSON.stringify(globalVariables.gamesWithDiscound), 'utf-8', function(err) {
                    if (err) console.log(err);
                });
                break;
            case "XML":
                var gwdXml = {};
                var gwdXmlObject = [];
                for (var key in globalVariables.gamesWithDiscound) {
                    var singleXmlObj = {};
                    var singleObj = globalVariables.gamesWithDiscound[key];
                    var ar = [];
                    singleObj.forEach(function(so, index) {
                        ar.push({ item: [{ _id: so._id }, { _name: so._name }, { _price: so._price }, { _discount: so._discount }, { _link: so._link }] });
                        singleXmlObj["items"] = ar;
                    });
                    gwdXmlObject.push({ tagname: [{ _attr: { attributes: key } }, singleXmlObj] });
                    gwdXml["tags"] = gwdXmlObject;
                }
                //exportData[tagId] = { _id, _name, _price, _discount, _link }
                fs.writeFile('./data/export/export_xml.xml', xml(gwdXml), 'utf-8', function(err) {
                    if (err) console.log(err);
                });
                break;
            case "HTML":
                var htmlContent = '<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

';

                for (var key in globalVariables.gamesWithDiscound) {
                    var singleObj = globalVariables.gamesWithDiscound[key];
                    htmlContent += '
Categorie: ' + globalVariables.globalTagList[key] + ' (' + key + ')
';
                    htmlContent += '

Game	Discount	New Price

';
                    singleObj.forEach(function(so, index) {
                        htmlContent += '
' + so._name + '	 ' + so._discount + '	' + so._price + '
';
                    });
                    htmlContent += '

';

                }
                htmlContent += '
';

                fs.writeFile('./data/export/export_html.html', htmlContent, 'utf-8', function(err) {
                    if (err) console.log(err);
                });
                break;
            default:
                console.log(single_type + " is not a valid Export-Type.");
                break;
        }
    });

    globalVariables.globalTagList = {};
    globalVariables.callBackCount = 0;
    globalVariables.gamesWithDiscound = {};
}

//RUN
if (GLOBALS.T_INTERVAL_SET) {
    execute();
    setInterval(function() { execute(); }, GLOBALS.T_INTERVAL);
} else {
    execute();
}<|endoftext|>


<commit_before>import Botkit from 'botkit';
import redisStore from './storage/redis';
import Matchers from './matcher-register';
import setupMatchers from './matchers';
import nconf from './config';

if (!nconf.get('SLACK_BOT_TOKEN') || !nconf.get('SLACK_SLASH_TOKEN')) {
  throw new Error('Error: Specify slack tokens in environment');
}

const controller = Botkit.slackbot({
  debug: false,
  storage: redisStore({ url: nconf.get('REDIS_URL') }),
});

export const slushbot = controller.spawn({ token: nconf.get('SLACK_BOT_TOKEN') });

setupMatchers();

slushbot.api.team.info({}, (err, res) => {
  if (err) {
    throw new Error(err);
  }

  controller.saveTeam(res.team, () => controller.log('Stored Team Information'));
});

slushbot.startRTM(err => {
  if (err) {
    throw new Error(err);
  }
});

controller.setupWebserver(nconf.get('PORT') || 3000, (err, expressWebserver) => {
  if (err) {
    throw new Error(err);
  }

  controller.createWebhookEndpoints(expressWebserver);
});

controller.on('slash_command', (bot, message) => {
  if (message.token === nconf.get('SLACK_SLASH_TOKEN')) {
    Object.values(Matchers.slash).forEach(matcher => matcher.match(bot, message));
  }
});

Object.values(Matchers.bot).forEach(matcher => matcher.match(controller));

export default controller;
<commit_msg>redis docker link<commit_after>import Botkit from 'botkit';
import redisStore from './storage/redis';
import Matchers from './matcher-register';
import setupMatchers from './matchers';
import nconf from './config';

console.log('redis://' + nconf.get('REDIS_PORT_6379_TCP_ADDR') + ':6379');

if (!nconf.get('SLACK_BOT_TOKEN') || !nconf.get('SLACK_SLASH_TOKEN')) {
  throw new Error('Error: Specify slack tokens in environment');
}

const controller = Botkit.slackbot({
  debug: false,
  storage: redisStore({ url: 'redis://' + nconf.get('REDIS_PORT_6379_TCP_ADDR') + ':6379' }),
});

export const slushbot = controller.spawn({ token: nconf.get('SLACK_BOT_TOKEN') });

setupMatchers();

slushbot.api.team.info({}, (err, res) => {
  if (err) {
    throw new Error(err);
  }

  controller.saveTeam(res.team, () => controller.log('Stored Team Information'));
});

slushbot.startRTM(err => {
  if (err) {
    throw new Error(err);
  }
});

controller.setupWebserver(nconf.get('PORT') || 3000, (err, expressWebserver) => {
  if (err) {
    throw new Error(err);
  }

  controller.createWebhookEndpoints(expressWebserver);
});

controller.on('slash_command', (bot, message) => {
  if (message.token === nconf.get('SLACK_SLASH_TOKEN')) {
    Object.values(Matchers.slash).forEach(matcher => matcher.match(bot, message));
  }
});

Object.values(Matchers.bot).forEach(matcher => matcher.match(controller));

export default controller;
<|endoftext|>


<commit_before>"use strict";

var minimist = require("minimist");

function AdminCommand(opts) {
    this._desc = opts.desc;
    this._func = opts.func;

    if (opts.opts) {
        this.optspec = {};
        this.optaliases = {};

        Object.keys(opts.opts).forEach((k) => {
            var names = k.split(/\|/);
            var name = names.shift();

            this.optspec[name] = {
                desc: opts.opts[k],
            }

            names.forEach((a) => this.optaliases[a] = name);
        });
    }
}

AdminCommand.prototype.run = function(bridge, args, respond) {
    if (this.optspec) {
        var opts = minimist(args);

        // Canonicalise aliases
        Object.keys(this.optaliases).forEach((a) => {
            if (a in opts) {
                opts[this.optaliases[a]] = opts[a];
                delete opts[a];
            }
        });

        Object.keys(opts).forEach((n) => {
            if (n === "_") return;

            if (!(n in this.optspec)) {
                throw Error("Unrecognised argument: " + n);
            }
        });

        var missing = [];
        Object.keys(this.optspec).sort().forEach((n) => {
            if (!(n in opts)) missing.push(n);
        });

        if (missing.length) {
            throw Error("Missing required arguments: " + missing.join(", "));
        }

        this._func(bridge, opts, opts._, respond);
    }
    else {
        this._func(bridge, args, respond);
    }
};

var adminCommands = {};

adminCommands.help = new AdminCommand({
    desc: "display a list of commands",
    func: function(bridge, args, respond) {
        // TODO(paul): more detailed help on a single command
        Object.keys(adminCommands).sort().forEach(function (k) {
            var cmd = adminCommands[k];
            respond(k + ": " + cmd._desc);
        });
    },
});

adminCommands.list = new AdminCommand({
    desc: "list the linked rooms",
    func: function(bridge, args, respond) {
        bridge._rooms.forEach((room) => {
            respond("-c=" + room.slack_channel_id + " -r=" + room.matrix_room_id);
        });
    },
});

adminCommands.link = new AdminCommand({
    desc: "connect a Matrix and a Slack room together",
    opts: {
        "channel|c": "Slack channel ID",
        "room|r": "Matrix room ID",
        "webhook_url|u": "Slack webhook URL",
        "token|t": "Slack webhook token",
    },
    func: function(bridge, opts, args, respond) {
        bridge.actionLink({
            matrix_room_id: opts.room,
            slack_channel_id: opts.channel,
            slack_token: opts.token,
            slack_webhook_uri: opts.webhook_url,
        }).then(
            ()  => { respond("Linked") },
            (e) => { respond("Cannot link - " + e ) }
        );
    },
});

adminCommands.unlink = new AdminCommand({
    desc: "disconnect a linked Matrix and Slack room",
    opts: {
        "channel|c": "Slack channel ID",
        "room|r": "Matrix room ID",
    },
    func: function(bridge, opts, args, respond) {
        bridge.actionUnlink({
            matrix_room_id: opts.room,
            slack_channel_id: opts.channel,
        }).then(
            ()  => { respond("Unlinked") },
            (e) => { respond("Cannot unlink - " + e) }
        );
    },
});

module.exports = adminCommands;
<commit_msg>Extend 'help' command to print details about arguments<commit_after>"use strict";

var minimist = require("minimist");

function AdminCommand(opts) {
    this._desc = opts.desc;
    this._func = opts.func;

    if (opts.opts) {
        this.optspec = {};
        this.optaliases = {};

        Object.keys(opts.opts).forEach((k) => {
            var names = k.split(/\|/);
            var name = names.shift();

            this.optspec[name] = {
                desc: opts.opts[k],
            }

            names.forEach((a) => this.optaliases[a] = name);
        });
    }
}

AdminCommand.prototype.run = function(bridge, args, respond) {
    if (this.optspec) {
        var opts = minimist(args);

        // Canonicalise aliases
        Object.keys(this.optaliases).forEach((a) => {
            if (a in opts) {
                opts[this.optaliases[a]] = opts[a];
                delete opts[a];
            }
        });

        Object.keys(opts).forEach((n) => {
            if (n === "_") return;

            if (!(n in this.optspec)) {
                throw Error("Unrecognised argument: " + n);
            }
        });

        var missing = [];
        Object.keys(this.optspec).sort().forEach((n) => {
            if (!(n in opts)) missing.push(n);
        });

        if (missing.length) {
            throw Error("Missing required arguments: " + missing.join(", "));
        }

        this._func(bridge, opts, opts._, respond);
    }
    else {
        this._func(bridge, args, respond);
    }
};

var adminCommands = {};

adminCommands.help = new AdminCommand({
    desc: "display a list of commands",
    func: function(bridge, args, respond) {
        if (args.length == 0) {
            Object.keys(adminCommands).sort().forEach(function (k) {
                var cmd = adminCommands[k];
                respond(k + ": " + cmd._desc);
            });
        }
        else {
            var name = args.shift();
            var cmd = adminCommands[name];
            if (!cmd) {
                throw Error("No such command '" + name + "'");
            }

            respond(name + " - " + cmd._desc);
            var optspec = cmd.optspec || {};
            Object.keys(optspec).sort().forEach((n) => {
                respond("  --" + n + ": " + optspec[n].desc);
            });
        }
    },
});

adminCommands.list = new AdminCommand({
    desc: "list the linked rooms",
    func: function(bridge, args, respond) {
        bridge._rooms.forEach((room) => {
            respond("-c=" + room.slack_channel_id + " -r=" + room.matrix_room_id);
        });
    },
});

adminCommands.link = new AdminCommand({
    desc: "connect a Matrix and a Slack room together",
    opts: {
        "channel|c": "Slack channel ID",
        "room|r": "Matrix room ID",
        "webhook_url|u": "Slack webhook URL",
        "token|t": "Slack webhook token",
    },
    func: function(bridge, opts, args, respond) {
        bridge.actionLink({
            matrix_room_id: opts.room,
            slack_channel_id: opts.channel,
            slack_token: opts.token,
            slack_webhook_uri: opts.webhook_url,
        }).then(
            ()  => { respond("Linked") },
            (e) => { respond("Cannot link - " + e ) }
        );
    },
});

adminCommands.unlink = new AdminCommand({
    desc: "disconnect a linked Matrix and Slack room",
    opts: {
        "channel|c": "Slack channel ID",
        "room|r": "Matrix room ID",
    },
    func: function(bridge, opts, args, respond) {
        bridge.actionUnlink({
            matrix_room_id: opts.room,
            slack_channel_id: opts.channel,
        }).then(
            ()  => { respond("Unlinked") },
            (e) => { respond("Cannot unlink - " + e) }
        );
    },
});

module.exports = adminCommands;
<|endoftext|>


<commit_before>"use strict";

var Promise = require('bluebird');

var AdminCommand = require("./AdminCommand");

var adminCommands = {};

function quotemeta(s) { return s.replace(/\W/g, '\\$&'); }

adminCommands.help = AdminCommand.makeHelpCommand(adminCommands);

adminCommands.list = new AdminCommand({
    desc: "list the linked rooms",
    opts: {
        "team|T": "Filter only rooms for this Slack team domain",
    },
    func: function(bridge, opts, args, respond) {
        var name_filter;

        if (opts.team) {
            name_filter = new RegExp("^" + quotemeta(opts.team) + "\.#");
        }

        var found = 0;
        bridge._rooms.forEach((room) => {
            var matrix_room_ids = room.getMatrixRoomIds();

            var slack_channel_id = room.getSlackChannelId();
            var slack_channel_name = room.getSlackChannelName() || "UNKNOWN";

            if (name_filter && !name_filter.exec(slack_channel_name)) {
                return;
            }

            var slack = slack_channel_id ?
                slack_channel_name + "(" + slack_channel_id + ")" :
                slack_channel_name;

            var status = room.getStatus();
            if (status !== "ready") status = status.toUpperCase();

            found++;

            if (!matrix_room_ids.length) {
                respond(status + " " + slack + " unlinked");
            }
            else if (matrix_room_ids.length == 1) {
                respond(status + " " + slack + " -- " + matrix_room_ids[0]);
            }
            else {
                respond(status + " " + slack + " linked:");
                matrix_room_ids.forEach((id) => respond(" +- " + id));
            }
        });

        if (!found) {
            respond("No rooms found");
        }
    },
});

adminCommands.show = new AdminCommand({
    desc: "show a single connected room",
    opts: {
        "channel_id|I": "Slack channel ID",
        "channel|C": "Slack channel name",
        "room|R": "Matrix room ID",
    },
    func: function(bridge, opts, args, respond) {
        console.log("opts are", opts);
        console.log("opts keys are", Object.keys(opts));

        if (Object.keys(opts).length != 1) {
            return Promise.reject("Require exactly one of --room, --channel or --channel_id");
        }

        var room = (opts.channel_id) ? bridge.getRoomBySlackChannelId(opts.channel_id) :
                   (opts.channel) ? bridge.getRoomBySlackChannelName(opts.channel) :
                   bridge.getRoomByMatrixRoomId(opts.room);

        if (!room) {
            respond("No such room");
            return;
        }

        respond((room.isLegacy() ? "Legacy " : "") + "Bridged Room:");
        respond("  Status: " + room.getStatus());
        respond("  Slack Name: " + room.getSlackChannelName() || "PENDING");
        respond("  Webhook URI: " + room.getSlackWebhookUri());

        if (room.isLegacy()) {
            respond("  Slack ID: " + room.getSlackChannelId());
            respond("  Token: " + room.getSlackToken());
        }
        else {
            respond("  Inbound ID: " + room.getInboundId());
            respond("  Inbound URL: " + bridge.getInboundUrlForRoom(room));
            if (room._upgrade_pending) respond("  UPGRADE PENDING");
        }

        var matrix_room_ids = room.getMatrixRoomIds();

        if (!matrix_room_ids.length) {
            respond("  No Matrix room IDs");
        }
        else if(matrix_room_ids.length === 1) {
            respond("  Matrix room ID: " + matrix_room_ids[0]);
        }
        else {
            respond("  Matrix room IDs:");
            matrix_room_ids.forEach((id) => respond("    " + id));
        }
    },
});

adminCommands.link = new AdminCommand({
    desc: "connect a Matrix and a Slack room together",
    opts: {
        "channel_id|I": "Slack channel ID",
        "channel|C": "Slack channel name",
        "!room|R": "Matrix room ID",
        "webhook_url|u": "Slack webhook URL",
    },
    func: function(bridge, opts, args, respond) {
        return bridge.actionLink({
            matrix_room_id: opts.room,
            slack_channel_name: opts.channel,
            slack_channel_id: opts.channel_id,
            slack_webhook_uri: opts.webhook_url,
        }).then(
            (room) => {
                respond("Room is now " + room.getStatus());
                respond("Inbound URL is " + bridge.getInboundUrlForRoom(room));
            },
            (e) => { respond("Cannot link - " + e ) }
        );
    },
});

adminCommands.unlink = new AdminCommand({
    desc: "disconnect a linked Matrix and Slack room",
    opts: {
        "channel_id|I": "Slack channel ID",
        "channel|C": "Slack channel name",
        "!room|R": "Matrix room ID",
    },
    func: function(bridge, opts, args, respond) {
        return bridge.actionUnlink({
            matrix_room_id: opts.room,
            slack_channel_name: opts.channel,
            slack_channel_id: opts.channel_id,
        }).then(
            ()  => { respond("Unlinked") },
            (e) => { respond("Cannot unlink - " + e) }
        );
    },
});

adminCommands.upgrade = new AdminCommand({
    desc: "upgrade a legacy-style room to new webhook-based routing",
    opts: {
        "!room|R": "Matrix room ID",
    },
    func: function(bridge, opts, args, respond) {
        return bridge.actionUpgrade({
            matrix_room_id: opts.room,
        }).then(
            (room) => {
                respond("Room is now " + room.getStatus());
                respond("Inbound URL is " + bridge.getInboundUrlForRoom(room));
            },
            (e) => { respond("Cannot upgrade - " + e ) }
        );
    },
});

module.exports = adminCommands;
<commit_msg>Indicate legacy rooms in 'list' command<commit_after>"use strict";

var Promise = require('bluebird');

var AdminCommand = require("./AdminCommand");

var adminCommands = {};

function quotemeta(s) { return s.replace(/\W/g, '\\$&'); }

adminCommands.help = AdminCommand.makeHelpCommand(adminCommands);

adminCommands.list = new AdminCommand({
    desc: "list the linked rooms",
    opts: {
        "team|T": "Filter only rooms for this Slack team domain",
    },
    func: function(bridge, opts, args, respond) {
        var name_filter;

        if (opts.team) {
            name_filter = new RegExp("^" + quotemeta(opts.team) + "\.#");
        }

        var found = 0;
        bridge._rooms.forEach((room) => {
            var matrix_room_ids = room.getMatrixRoomIds();

            var slack_channel_id = room.getSlackChannelId();
            var slack_channel_name = room.getSlackChannelName() || "UNKNOWN";

            if (name_filter && !name_filter.exec(slack_channel_name)) {
                return;
            }

            var slack = slack_channel_id ?
                slack_channel_name + "(" + slack_channel_id + ")" :
                slack_channel_name;

            var status = room.getStatus();
            if (status !== "ready") status = status.toUpperCase();

            if (room.isLegacy()) {
                status = status + "[legacy]";
            }

            found++;

            if (!matrix_room_ids.length) {
                respond(status + " " + slack + " unlinked");
            }
            else if (matrix_room_ids.length == 1) {
                respond(status + " " + slack + " -- " + matrix_room_ids[0]);
            }
            else {
                respond(status + " " + slack + " linked:");
                matrix_room_ids.forEach((id) => respond(" +- " + id));
            }
        });

        if (!found) {
            respond("No rooms found");
        }
    },
});

adminCommands.show = new AdminCommand({
    desc: "show a single connected room",
    opts: {
        "channel_id|I": "Slack channel ID",
        "channel|C": "Slack channel name",
        "room|R": "Matrix room ID",
    },
    func: function(bridge, opts, args, respond) {
        console.log("opts are", opts);
        console.log("opts keys are", Object.keys(opts));

        if (Object.keys(opts).length != 1) {
            return Promise.reject("Require exactly one of --room, --channel or --channel_id");
        }

        var room = (opts.channel_id) ? bridge.getRoomBySlackChannelId(opts.channel_id) :
                   (opts.channel) ? bridge.getRoomBySlackChannelName(opts.channel) :
                   bridge.getRoomByMatrixRoomId(opts.room);

        if (!room) {
            respond("No such room");
            return;
        }

        respond((room.isLegacy() ? "Legacy " : "") + "Bridged Room:");
        respond("  Status: " + room.getStatus());
        respond("  Slack Name: " + room.getSlackChannelName() || "PENDING");
        respond("  Webhook URI: " + room.getSlackWebhookUri());

        if (room.isLegacy()) {
            respond("  Slack ID: " + room.getSlackChannelId());
            respond("  Token: " + room.getSlackToken());
        }
        else {
            respond("  Inbound ID: " + room.getInboundId());
            respond("  Inbound URL: " + bridge.getInboundUrlForRoom(room));
            if (room._upgrade_pending) respond("  UPGRADE PENDING");
        }

        var matrix_room_ids = room.getMatrixRoomIds();

        if (!matrix_room_ids.length) {
            respond("  No Matrix room IDs");
        }
        else if(matrix_room_ids.length === 1) {
            respond("  Matrix room ID: " + matrix_room_ids[0]);
        }
        else {
            respond("  Matrix room IDs:");
            matrix_room_ids.forEach((id) => respond("    " + id));
        }
    },
});

adminCommands.link = new AdminCommand({
    desc: "connect a Matrix and a Slack room together",
    opts: {
        "channel_id|I": "Slack channel ID",
        "channel|C": "Slack channel name",
        "!room|R": "Matrix room ID",
        "webhook_url|u": "Slack webhook URL",
    },
    func: function(bridge, opts, args, respond) {
        return bridge.actionLink({
            matrix_room_id: opts.room,
            slack_channel_name: opts.channel,
            slack_channel_id: opts.channel_id,
            slack_webhook_uri: opts.webhook_url,
        }).then(
            (room) => {
                respond("Room is now " + room.getStatus());
                respond("Inbound URL is " + bridge.getInboundUrlForRoom(room));
            },
            (e) => { respond("Cannot link - " + e ) }
        );
    },
});

adminCommands.unlink = new AdminCommand({
    desc: "disconnect a linked Matrix and Slack room",
    opts: {
        "channel_id|I": "Slack channel ID",
        "channel|C": "Slack channel name",
        "!room|R": "Matrix room ID",
    },
    func: function(bridge, opts, args, respond) {
        return bridge.actionUnlink({
            matrix_room_id: opts.room,
            slack_channel_name: opts.channel,
            slack_channel_id: opts.channel_id,
        }).then(
            ()  => { respond("Unlinked") },
            (e) => { respond("Cannot unlink - " + e) }
        );
    },
});

adminCommands.upgrade = new AdminCommand({
    desc: "upgrade a legacy-style room to new webhook-based routing",
    opts: {
        "!room|R": "Matrix room ID",
    },
    func: function(bridge, opts, args, respond) {
        return bridge.actionUpgrade({
            matrix_room_id: opts.room,
        }).then(
            (room) => {
                respond("Room is now " + room.getStatus());
                respond("Inbound URL is " + bridge.getInboundUrlForRoom(room));
            },
            (e) => { respond("Cannot upgrade - " + e ) }
        );
    },
});

module.exports = adminCommands;
<|endoftext|>


<commit_before>var
	dgram = require('dgram'),
	EventEmitter = require('events').EventEmitter,
	inherits = require('util').inherits,
	net = require('net'),
	uuid = require('uuid'),

	Base = require('./Base'),
	addrs = require('../Misc/addresses'),
	msgs = require('../Misc/messages'),
	neigh = require('../Misc/neigh');

// ----------------
// Client class
// ----------------
// Main client class
// Inherits from: EventEmitter

// ----------------
// Events

// listening
// close

// ----------------
// Class declaration

function Client(chan) {
	Base.call(this, chan);

	var self = this;

	// Client cache
	this._client_cache = new neigh.NeighborManager();

	// ----------------
	// Server socket

	this._server_sock = new net.Socket();

	// When socket is ready try to find server
	this.on('listening', function(){

		self.findServer;

		var message = new msgs.Message(
			msgs.types.CLIENT_ADVERTISEMENT,
			self.getProfile(),
			"I'm Here ..."
		);

		self.sendUDP(self._channel, message.toString());

	});
};
inherits(Client, Base);

// ----------------
// Public methods

// function findServer
// tries to find a server by sending a SERVER_SOLICITATION
// message. Fires server-found event.
Client.prototype.findServer = function() {
	var message = new msgs.Message(
		msgs.types.SERVER_SOLICITATION,
		this.getProfile(),
		"Server solicitation..."
	);
	this.sendUDP(this._channel, message.toString());
}

// function connect
// stablish a TCP connection to given address and port.
// Used for connecting to a server
Client.prototype.connect = function(address, port) {

	var addr = address + ':' + port;

	this._server_sock.connect(port, address);

	// Data arrives
	this._server_sock.on('data', this._tcpMessageHandler);

	// Connection status
	this._server_sock.on('connect', function() {
		console.log('Connected to server: ' + addr);
	});

	this._server_sock.on('close', function() {
		console.log('Disconnected from server: ' + addr);
	});

	this._server_sock.on('error', function() {
		console.log('Unable to conect to server: ' + addr)
	});
}

// @override
Client.prototype.close = function() {
	Base.prototype.close.call(this);
	if (this._server_sock)
		this._server_sock.end();
}

Client.prototype.beforeClose = function() {}
Client.prototype.afterClose = function() {}

Client.prototype.createGroup = function(group_name) {
	// Gets Multicast address from server
	// Creates group socket
}

// function updateClientCache
// Sends a CLIENT_SOLICITATION message to the
// channel to which this client is connected
Client.prototype.updateClientCache = function() {
	var message = new msgs.Message(
		msgs.types.CLIENT_SOLICITATION,
		this.getProfile()
	);

	this.sendUDP(this._channel, message.toString());
}

// ----------------
// Private methods

// function _tcpMessageHandler
// handles the messages comming from the server
// @param data the data received
// @returns undefined
Client.prototype._tcpMessageHandler = function(data) {

	// JSON parse
	data = JSON.parse(data.toString());

	switch(data.type) {

		case msgs.types.GROUP_CREATE_OK:
			break;
		case msgs.types.GROUP_JOIN_OK:
			break;
		case msgs.types.GROUP_LEAVE_OK:
			break;
	}
}

// function _messageHandler
// @param message buffer of the message
// @remote object that contains the address and port of the sender
// @returns undefined
Client.prototype._messageHandler = function(message, remote) {

	var data = JSON.parse(message.toString());

	// Checks that this message isn't comming from us
	if (data.sender.uuid == this._uuid) return;

	switch(data.type) {

		// ----------------
		// Server messages
		case msgs.types.SERVER_ADVERTISEMENT:
			this.connect(remote.address, remote.port);
			break;

		// ----------------
		// General messages handling

		case msgs.types.CLIENT_ONLINE:
		case msgs.types.CLIENT_REPORT:
		case msgs.types.CLIENT_ADVERTISEMENT:

			this._client_cache.addNeighbor(new neigh.Neighbor(data.sender.uuid, data.sender));

			// Save client in cache

			break;
		case msgs.types.CLIENT_CHANGE:
			// Update client data
			break;
		case msgs.types.CLIENT_SOLICITATION:
			// Tell client we are online
			var message = new msgs.Message(
				msgs.types.CLIENT_REPORT,
				this.getProfile()
			);
			this.sendUDP(sender.channel, message.toString());
			break;
		case msgs.types.CLIENT_OFFLINE:
			// Delete client from list of neighbors
			break;

		// ----------------
		// All / Group messages handling

		case msgs.types.GROUP_SOLICITATION:
			// Tell client of all groups we have
			break;
		case msgs.types.GROUP_ADVERTISEMENT:
			// Save group in neighbor-groups list
			break;

		// ----------------
		// Single / Group messages handling

		case msgs.types.GROUP_CREATE:
			// Group was created, save it in neighbor-group list
			break;
		case msgs.types.GROUP_DELETE:
			// Group deleted, remove it from neighbor-group list
			break;
		case msgs.types.GROUP_JOIN:
			// Client is trying to join a group (maybe of ours)
			break;
		case msgs.types.GROUP_LEAVE:
			// Somebody is leaving a group
			break;
		case msgs.types.GROUP_MESSAGE:
			// Messages to a group
			break;
		case msgs.types.GROUP_JOIN_OK:
			// We were able to join a group
			break;
		case msgs.types.GROUP_JOIN_ERR:
			// We weren't able to join a group
			break;
		case msgs.types.SINGLE_MESSAGE:

			this.emit('single-message', data.sender, data.extras);
			// We received an unicast message
			break;
	} // switch

} // messageHandler

// ----------------
// Exports
// ----------------

module.exports = Client;<commit_msg>Fixed sender info<commit_after>var
	dgram = require('dgram'),
	EventEmitter = require('events').EventEmitter,
	inherits = require('util').inherits,
	net = require('net'),
	uuid = require('uuid'),

	Base = require('./Base'),
	addrs = require('../Misc/addresses'),
	msgs = require('../Misc/messages'),
	neigh = require('../Misc/neigh');

// ----------------
// Client class
// ----------------
// Main client class
// Inherits from: EventEmitter

// ----------------
// Events

// listening
// close

// ----------------
// Class declaration

function Client(chan) {
	Base.call(this, chan);

	var self = this;

	// Client cache
	this._client_cache = new neigh.NeighborManager();

	// ----------------
	// Server socket

	this._server_sock = new net.Socket();

	// When socket is ready try to find server
	this.on('listening', function(){

		self.findServer;

		var message = new msgs.Message(
			msgs.types.CLIENT_ADVERTISEMENT,
			self.getProfile(),
			"I'm Here ..."
		);

		self.sendUDP(self._channel, message.toString());

	});
};
inherits(Client, Base);

// ----------------
// Public methods

// function findServer
// tries to find a server by sending a SERVER_SOLICITATION
// message. Fires server-found event.
Client.prototype.findServer = function() {
	var message = new msgs.Message(
		msgs.types.SERVER_SOLICITATION,
		this.getProfile(),
		"Server solicitation..."
	);
	this.sendUDP(this._channel, message.toString());
}

// function connect
// stablish a TCP connection to given address and port.
// Used for connecting to a server
Client.prototype.connect = function(address, port) {

	var addr = address + ':' + port;

	this._server_sock.connect(port, address);

	// Data arrives
	this._server_sock.on('data', this._tcpMessageHandler);

	// Connection status
	this._server_sock.on('connect', function() {
		console.log('Connected to server: ' + addr);
	});

	this._server_sock.on('close', function() {
		console.log('Disconnected from server: ' + addr);
	});

	this._server_sock.on('error', function() {
		console.log('Unable to conect to server: ' + addr)
	});
}

// @override
Client.prototype.close = function() {
	Base.prototype.close.call(this);
	if (this._server_sock)
		this._server_sock.end();
}

Client.prototype.beforeClose = function() {}
Client.prototype.afterClose = function() {}

Client.prototype.createGroup = function(group_name) {
	// Gets Multicast address from server
	// Creates group socket
}

// function updateClientCache
// Sends a CLIENT_SOLICITATION message to the
// channel to which this client is connected
Client.prototype.updateClientCache = function() {
	var message = new msgs.Message(
		msgs.types.CLIENT_SOLICITATION,
		this.getProfile()
	);

	this.sendUDP(this._channel, message.toString());
}

// ----------------
// Private methods

// function _tcpMessageHandler
// handles the messages comming from the server
// @param data the data received
// @returns undefined
Client.prototype._tcpMessageHandler = function(data) {

	// JSON parse
	data = JSON.parse(data.toString());

	switch(data.type) {

		case msgs.types.GROUP_CREATE_OK:
			break;
		case msgs.types.GROUP_JOIN_OK:
			break;
		case msgs.types.GROUP_LEAVE_OK:
			break;
	}
}

// function _messageHandler
// @param message buffer of the message
// @remote object that contains the address and port of the sender
// @returns undefined
Client.prototype._messageHandler = function(message, remote) {

	var data = JSON.parse(message.toString());

	// Checks that this message isn't comming from us
	if (data.sender.uuid == this._uuid) return;

	data.sender.channel = new addrs.Channel(remote.address, remote.port);
	console.log(data.type);

	switch(data.type) {

		// ----------------
		// Server messages
		case msgs.types.SERVER_ADVERTISEMENT:
			this.connect(remote.address, remote.port);
			break;

		// ----------------
		// General messages handling

		case msgs.types.CLIENT_ONLINE:
		case msgs.types.CLIENT_REPORT:
		case msgs.types.CLIENT_ADVERTISEMENT:

			this._client_cache.addNeighbor(new neigh.Neighbor(data.sender.uuid, data.sender));

			// Save client in cache

			break;
		case msgs.types.CLIENT_CHANGE:
			// Update client data
			break;
		case msgs.types.CLIENT_SOLICITATION:
			// Tell client we are online
			var message = new msgs.Message(
				msgs.types.CLIENT_REPORT,
				this.getProfile()
			);
			this.sendUDP(data.sender.channel, message.toString());
			break;
		case msgs.types.CLIENT_OFFLINE:
			// Delete client from list of neighbors
			break;

		// ----------------
		// All / Group messages handling

		case msgs.types.GROUP_SOLICITATION:
			// Tell client of all groups we have
			break;
		case msgs.types.GROUP_ADVERTISEMENT:
			// Save group in neighbor-groups list
			break;

		// ----------------
		// Single / Group messages handling

		case msgs.types.GROUP_CREATE:
			// Group was created, save it in neighbor-group list
			break;
		case msgs.types.GROUP_DELETE:
			// Group deleted, remove it from neighbor-group list
			break;
		case msgs.types.GROUP_JOIN:
			// Client is trying to join a group (maybe of ours)
			break;
		case msgs.types.GROUP_LEAVE:
			// Somebody is leaving a group
			break;
		case msgs.types.GROUP_MESSAGE:
			// Messages to a group
			break;
		case msgs.types.GROUP_JOIN_OK:
			// We were able to join a group
			break;
		case msgs.types.GROUP_JOIN_ERR:
			// We weren't able to join a group
			break;
		case msgs.types.SINGLE_MESSAGE:

			this.emit('single-message', data.sender, data.extras);
			// We received an unicast message
			break;
	} // switch

} // messageHandler

// ----------------
// Exports
// ----------------

module.exports = Client;<|endoftext|>


<commit_before>var issues_raw;
var cooldown_period;
var allowed_statuses_map;

function onLoadOpening() {
  var markIndex = window.location.href.lastIndexOf("#");

  if(markIndex != -1)
  {
    var prevGrid = window.location.href.substr(markIndex + 1, 2);
    openBoard(prevGrid);
  }
  else
  {
    openBoard("dg");
  }
};

function isIndexInArray(array, index) {
  return array.length > index && array[index] != null;
}

function isStatusAllowed(id, src_status, dst_status) {
  return isIndexInArray(allowed_statuses_map, id)
  && isIndexInArray(allowed_statuses_map[id], src_status)
  && allowed_statuses_map[id][src_status].indexOf(dst_status) != -1;
};

function getCooldownPeriod() {
  var cooldownPeriodDays = document.getElementById("cooldown_period_days").getAttribute("value");
  var cooldownPeriodHours = document.getElementById("cooldown_period_hours").getAttribute("value");
  return cooldownPeriodHours * 3600 + cooldownPeriodDays * 86400;
};

function pageOnLoad() {
  onLoadOpening();

  issues_raw = getIssuesRaw();

  cooldown_period = getCooldownPeriod();

  allowed_statuses_map = getStatusesAllowanceMap();

  init();
  statusInit();
};

document.addEventListener("DOMContentLoaded", pageOnLoad);
<commit_msg>semicolon missing<commit_after>var issues_raw;
var cooldown_period;
var allowed_statuses_map;

function onLoadOpening() {
  var markIndex = window.location.href.lastIndexOf("#");

  if(markIndex != -1)
  {
    var prevGrid = window.location.href.substr(markIndex + 1, 2);
    openBoard(prevGrid);
  }
  else
  {
    openBoard("dg");
  }
};

function isIndexInArray(array, index) {
  return array.length > index && array[index] != null;
};

function isStatusAllowed(id, src_status, dst_status) {
  return isIndexInArray(allowed_statuses_map, id)
  && isIndexInArray(allowed_statuses_map[id], src_status)
  && allowed_statuses_map[id][src_status].indexOf(dst_status) != -1;
};

function getCooldownPeriod() {
  var cooldownPeriodDays = document.getElementById("cooldown_period_days").getAttribute("value");
  var cooldownPeriodHours = document.getElementById("cooldown_period_hours").getAttribute("value");
  return cooldownPeriodHours * 3600 + cooldownPeriodDays * 86400;
};

function pageOnLoad() {
  onLoadOpening();

  issues_raw = getIssuesRaw();

  cooldown_period = getCooldownPeriod();

  allowed_statuses_map = getStatusesAllowanceMap();

  init();
  statusInit();
};

document.addEventListener("DOMContentLoaded", pageOnLoad);
<|endoftext|>


<commit_before>
var Loader = function ( signals ) {

  scope = this;

  var sceneExporter = new THREE.ObjectExporter();

  document.addEventListener( 'dragover', function ( event ) {

    event.preventDefault();
    event.dataTransfer.dropEffect = 'copy';

  }, false );

  document.addEventListener( 'drop', function ( event ) {

    event.preventDefault();

    var file = event.dataTransfer.files[ 0 ];

    var chunks = file.name.split( '.' );
    var extension = chunks.pop().toLowerCase();
    var filename = chunks.join( '.' );

    scope.parseFile( file, filename, extension );

  }, false );

  var timeout;

  signals.sceneChanged.add( function ( scene ) {

    clearTimeout( timeout );

    timeout = setTimeout( function () {

      scope.saveLocalStorage( scene );

    }, 3000 );

  } );

  this.loadLocalStorage = function() {

    if ( localStorage.threejsEditor !== undefined ) {

      var loader = new THREE.ObjectLoader();
      var scene = loader.parse( JSON.parse( localStorage.threejsEditor ) );

      signals.sceneAdded.dispatch( scene );

    }

  };

  this.saveLocalStorage = function ( scene ) {

    localStorage.threejsEditor = JSON.stringify( sceneExporter.parse( scene ) );

  }

  this.handleJSON = function ( data ) {

    if ( data.metadata === undefined ) { // 2.0

      data.metadata = { type: 'geometry' };

    }

    if ( data.metadata.type === undefined ) { // 3.0

      data.metadata.type = 'geometry';

    }

    if ( data.metadata.version === undefined ) {

      data.metadata.version = data.metadata.formatVersion;

    }

    if ( data.metadata.type === 'geometry' ) {

      var loader = new THREE.JSONLoader();
      var result = loader.parse( data );

      var geometry = result.geometry;
      var material = result.materials !== undefined
            ? new THREE.MeshFaceMaterial( result.materials )
            : new THREE.MeshPhongMaterial();

      geometry.sourceType = "ascii";
      geometry.sourceFile = file.name;

      var mesh = new THREE.Mesh( geometry, material );
      mesh.name = filename;

      signals.objectAdded.dispatch( mesh );
      signals.objectSelected.dispatch( mesh );

    } else if ( data.metadata.type === 'object' ) {

      var loader = new THREE.ObjectLoader();
      var result = loader.parse( data );

      if ( result instanceof THREE.Scene ) {

        signals.sceneAdded.dispatch( result );

      } else {

        signals.objectAdded.dispatch( result );

      }

    } else if ( data.metadata.type === 'scene' ) {

      // DEPRECATED

      var loader = new THREE.SceneLoader();
      loader.parse( data, function ( result ) {

        var scene = result.scene;

        while ( scene.children.length > 0 ) {

          signals.objectAdded.dispatch( scene.children[ 0 ] );

        }

      }, '' );

    }

  };

  this.parseFile = function ( file, filename, extension ) {

    switch ( extension ) {

      case 'ctm':

        var reader = new FileReader();
        reader.addEventListener( 'load', function ( event ) {

          var contents = event.target.result;

          var stream = new CTM.Stream( contents );
          stream.offset = 0;

          var loader = new THREE.CTMLoader();
          loader.createModelClassic( new CTM.File( stream ), function( geometry ) {

            geometry.sourceType = "ctm";
            geometry.sourceFile = file.name;

            var material = new THREE.MeshPhongMaterial();

            var mesh = new THREE.Mesh( geometry, material );
            mesh.name = filename;

            signals.objectAdded.dispatch( mesh );
            signals.objectSelected.dispatch( mesh );

          } );

        }, false );
        reader.readAsBinaryString( file );

        break;

      case 'dae':

        var reader = new FileReader();
        reader.addEventListener( 'load', function ( event ) {

          var contents = event.target.result;

          var parser = new DOMParser();
          var xml = parser.parseFromString( contents, 'text/xml' );

          var loader = new THREE.ColladaLoader();
          loader.parse( xml, function ( collada ) {

            collada.scene.name = filename;

            signals.objectAdded.dispatch( collada.scene );
            signals.objectSelected.dispatch( collada.scene );

          } );

        }, false );
        reader.readAsText( file );

        break;

      case 'js':
      case 'json':

        var reader = new FileReader();
        reader.addEventListener( 'load', function ( event ) {

          var contents = event.target.result;

          // 2.0

          if ( contents.indexOf( 'postMessage' ) !== -1 ) {

            var blob = new Blob( [ contents ], { type: 'text/javascript' } );
            var url = URL.createObjectURL( blob );

            var worker = new Worker( url );

            worker.onmessage = function ( event ) {

              event.data.metadata = { version: 2 };
              scope.handleJSON( event.data );

            };

            worker.postMessage( Date.now() );

            return;

          }

          // >= 3.0

          var data;

          try {

            data = JSON.parse( contents );

          } catch ( error ) {

            alert( error );
            return;

          }

          scope.handleJSON( data );

        }, false );
        reader.readAsText( file );

        break;

      case 'obj':

        var reader = new FileReader();
        reader.addEventListener( 'load', function ( event ) {

          var contents = event.target.result;

          var object = new THREE.OBJLoader().parse( contents );
          object.name = filename;

          signals.objectAdded.dispatch( object );
          signals.objectSelected.dispatch( object );

        }, false );
        reader.readAsText( file );

        break;

      case 'ply':

        var reader = new FileReader();
        reader.addEventListener( 'load', function ( event ) {

          var contents = event.target.result;

          console.log( contents );

          var geometry = new THREE.PLYLoader().parse( contents );
          geometry.sourceType = "ply";
          geometry.sourceFile = file.name;

          var material = new THREE.MeshPhongMaterial();

          var mesh = new THREE.Mesh( geometry, material );
          mesh.name = filename;

          signals.objectAdded.dispatch( mesh );
          signals.objectSelected.dispatch( mesh );

        }, false );
        reader.readAsText( file );

        break;

      case 'stl':

        var reader = new FileReader();
        reader.addEventListener( 'load', function ( event ) {

          var contents = event.target.result;

          var geometry = new THREE.STLLoader().parse( contents );
          geometry.sourceType = "stl";
          geometry.sourceFile = file.name;

          var material = new THREE.MeshPhongMaterial();

          var mesh = new THREE.Mesh( geometry, material );
          mesh.name = filename;

          signals.objectAdded.dispatch( mesh );
          signals.objectSelected.dispatch( mesh );

        }, false );
        reader.readAsBinaryString(file);

        break;

      /*
      case 'utf8':

        var reader = new FileReader();
        reader.addEventListener( 'load', function ( event ) {

          var contents = event.target.result;

          var geometry = new THREE.UTF8Loader().parse( contents );
          var material = new THREE.MeshLambertMaterial();

          var mesh = new THREE.Mesh( geometry, material );

          signals.objectAdded.dispatch( mesh );
          signals.objectSelected.dispatch( mesh );

        }, false );
        reader.readAsBinaryString( file );

        break;
      */

      case 'vtk':

        var reader = new FileReader();
        reader.addEventListener( 'load', function ( event ) {

          var contents = event.target.result;

          var geometry = new THREE.VTKLoader().parse( contents );
          geometry.sourceType = "vtk";
          geometry.sourceFile = file.name;

          var material = new THREE.MeshPhongMaterial();

          var mesh = new THREE.Mesh( geometry, material );
          mesh.name = filename;

          signals.objectAdded.dispatch( mesh );
          signals.objectSelected.dispatch( mesh );

        }, false );
        reader.readAsText( file );

        break;

    }

  }

}<commit_msg>this allows ie10 to load STL files<commit_after>
var Loader = function ( signals ) {

  scope = this;

  var sceneExporter = new THREE.ObjectExporter();

  document.addEventListener( 'dragover', function ( event ) {

    event.preventDefault();
    event.dataTransfer.dropEffect = 'copy';

  }, false );

  document.addEventListener( 'drop', function ( event ) {

    event.preventDefault();

    var file = event.dataTransfer.files[ 0 ];

    var chunks = file.name.split( '.' );
    var extension = chunks.pop().toLowerCase();
    var filename = chunks.join( '.' );

    scope.parseFile( file, filename, extension );

  }, false );

  var timeout;

  signals.sceneChanged.add( function ( scene ) {

    clearTimeout( timeout );

    timeout = setTimeout( function () {

      scope.saveLocalStorage( scene );

    }, 3000 );

  } );

  this.loadLocalStorage = function() {

    if ( localStorage.threejsEditor !== undefined ) {

      var loader = new THREE.ObjectLoader();
      var scene = loader.parse( JSON.parse( localStorage.threejsEditor ) );

      signals.sceneAdded.dispatch( scene );

    }

  };

  this.saveLocalStorage = function ( scene ) {

    localStorage.threejsEditor = JSON.stringify( sceneExporter.parse( scene ) );

  }

  this.handleJSON = function ( data ) {

    if ( data.metadata === undefined ) { // 2.0

      data.metadata = { type: 'geometry' };

    }

    if ( data.metadata.type === undefined ) { // 3.0

      data.metadata.type = 'geometry';

    }

    if ( data.metadata.version === undefined ) {

      data.metadata.version = data.metadata.formatVersion;

    }

    if ( data.metadata.type === 'geometry' ) {

      var loader = new THREE.JSONLoader();
      var result = loader.parse( data );

      var geometry = result.geometry;
      var material = result.materials !== undefined
            ? new THREE.MeshFaceMaterial( result.materials )
            : new THREE.MeshPhongMaterial();

      geometry.sourceType = "ascii";
      geometry.sourceFile = file.name;

      var mesh = new THREE.Mesh( geometry, material );
      mesh.name = filename;

      signals.objectAdded.dispatch( mesh );
      signals.objectSelected.dispatch( mesh );

    } else if ( data.metadata.type === 'object' ) {

      var loader = new THREE.ObjectLoader();
      var result = loader.parse( data );

      if ( result instanceof THREE.Scene ) {

        signals.sceneAdded.dispatch( result );

      } else {

        signals.objectAdded.dispatch( result );

      }

    } else if ( data.metadata.type === 'scene' ) {

      // DEPRECATED

      var loader = new THREE.SceneLoader();
      loader.parse( data, function ( result ) {

        var scene = result.scene;

        while ( scene.children.length > 0 ) {

          signals.objectAdded.dispatch( scene.children[ 0 ] );

        }

      }, '' );

    }

  };

  this.parseFile = function ( file, filename, extension ) {

    switch ( extension ) {

      case 'ctm':

        var reader = new FileReader();
        reader.addEventListener( 'load', function ( event ) {

          var contents = event.target.result;

          var stream = new CTM.Stream( contents );
          stream.offset = 0;

          var loader = new THREE.CTMLoader();
          loader.createModelClassic( new CTM.File( stream ), function( geometry ) {

            geometry.sourceType = "ctm";
            geometry.sourceFile = file.name;

            var material = new THREE.MeshPhongMaterial();

            var mesh = new THREE.Mesh( geometry, material );
            mesh.name = filename;

            signals.objectAdded.dispatch( mesh );
            signals.objectSelected.dispatch( mesh );

          } );

        }, false );
        reader.readAsBinaryString( file );

        break;

      case 'dae':

        var reader = new FileReader();
        reader.addEventListener( 'load', function ( event ) {

          var contents = event.target.result;

          var parser = new DOMParser();
          var xml = parser.parseFromString( contents, 'text/xml' );

          var loader = new THREE.ColladaLoader();
          loader.parse( xml, function ( collada ) {

            collada.scene.name = filename;

            signals.objectAdded.dispatch( collada.scene );
            signals.objectSelected.dispatch( collada.scene );

          } );

        }, false );
        reader.readAsText( file );

        break;

      case 'js':
      case 'json':

        var reader = new FileReader();
        reader.addEventListener( 'load', function ( event ) {

          var contents = event.target.result;

          // 2.0

          if ( contents.indexOf( 'postMessage' ) !== -1 ) {

            var blob = new Blob( [ contents ], { type: 'text/javascript' } );
            var url = URL.createObjectURL( blob );

            var worker = new Worker( url );

            worker.onmessage = function ( event ) {

              event.data.metadata = { version: 2 };
              scope.handleJSON( event.data );

            };

            worker.postMessage( Date.now() );

            return;

          }

          // >= 3.0

          var data;

          try {

            data = JSON.parse( contents );

          } catch ( error ) {

            alert( error );
            return;

          }

          scope.handleJSON( data );

        }, false );
        reader.readAsText( file );

        break;

      case 'obj':

        var reader = new FileReader();
        reader.addEventListener( 'load', function ( event ) {

          var contents = event.target.result;

          var object = new THREE.OBJLoader().parse( contents );
          object.name = filename;

          signals.objectAdded.dispatch( object );
          signals.objectSelected.dispatch( object );

        }, false );
        reader.readAsText( file );

        break;

      case 'ply':

        var reader = new FileReader();
        reader.addEventListener( 'load', function ( event ) {

          var contents = event.target.result;

          console.log( contents );

          var geometry = new THREE.PLYLoader().parse( contents );
          geometry.sourceType = "ply";
          geometry.sourceFile = file.name;

          var material = new THREE.MeshPhongMaterial();

          var mesh = new THREE.Mesh( geometry, material );
          mesh.name = filename;

          signals.objectAdded.dispatch( mesh );
          signals.objectSelected.dispatch( mesh );

        }, false );
        reader.readAsText( file );

        break;

      case 'stl':

        var reader = new FileReader();
        reader.addEventListener( 'load', function ( event ) {

          var contents = event.target.result;

          var geometry = new THREE.STLLoader().parse( contents );
          geometry.sourceType = "stl";
          geometry.sourceFile = file.name;

          var material = new THREE.MeshPhongMaterial();

          var mesh = new THREE.Mesh( geometry, material );
          mesh.name = filename;

          signals.objectAdded.dispatch( mesh );
          signals.objectSelected.dispatch( mesh );

        }, false );

        if (reader.readAsBinaryString) {

            reader.readAsBinaryStrings(file);

        } else {

            reader.readAsArrayBuffer(file);

        }

        break;

      /*
      case 'utf8':

        var reader = new FileReader();
        reader.addEventListener( 'load', function ( event ) {

          var contents = event.target.result;

          var geometry = new THREE.UTF8Loader().parse( contents );
          var material = new THREE.MeshLambertMaterial();

          var mesh = new THREE.Mesh( geometry, material );

          signals.objectAdded.dispatch( mesh );
          signals.objectSelected.dispatch( mesh );

        }, false );
        reader.readAsBinaryString( file );

        break;
      */

      case 'vtk':

        var reader = new FileReader();
        reader.addEventListener( 'load', function ( event ) {

          var contents = event.target.result;

          var geometry = new THREE.VTKLoader().parse( contents );
          geometry.sourceType = "vtk";
          geometry.sourceFile = file.name;

          var material = new THREE.MeshPhongMaterial();

          var mesh = new THREE.Mesh( geometry, material );
          mesh.name = filename;

          signals.objectAdded.dispatch( mesh );
          signals.objectSelected.dispatch( mesh );

        }, false );
        reader.readAsText( file );

        break;

    }

  }

}<|endoftext|>


<commit_before>'use strict';

angular.module('classBrowserUHApp.offeredClass', ['ngRoute'])

.config(['$routeProvider', function($routeProvider) {
    $routeProvider.when('/offeredClass', {
        templateUrl: 'views/offeredClass/offeredClass.html',
        controller: 'OfferedClassCtrl'
    });
}])
.controller('OfferedClassCtrl', ['$scope', '$http', '$q', '$rootScope', '$parse', '$window', function ($scope, $http, $q, $rootScope, $parse, $window) {
    var setScopeVariableFromJSON = function(filePath, scopeVariable) {
        $rootScope.httpService.getData(filePath).then(function(result) {
            $parse(scopeVariable).assign($scope, result);
        });
    };

    var initializeAllJSONAndScopeNames = function(name) {
        $rootScope.httpService.getData('resources/allScopeVariables.json').then(function(result) {
            $scope.allJSONAndScopeNames = result[name];
            $scope.allJSONAndScopeNames.forEach(function(e) {
                setScopeVariableFromJSON(e.path, e.scopeName);
            });
        });
    };

    initializeAllJSONAndScopeNames("offeredClass");

    $scope.validValues = ['A','1','2', '3', '4', '5', '6', '7', '8', '9', '0'];

    $scope.deleteModel = function() {
        [].slice.call(arguments).forEach(function(arg) {
            delete $scope[arg];
        });
    };

    $scope.clearForms = function() {
        var clearFormDialogConfirmation = $window.confirm('Are you sure you want to clear the entire form?');

        if (clearFormDialogConfirmation) {
            clearAllModels();
            $scope.deleteModel('warningMessage', 'hasNoResults', 'isError');
        }
    };

    $scope.findClasses = function(isValidForm) {
        if(isValidForm) {
            $scope.isDataLoading = true;
            $scope.hasNoResults = false;
            $scope.isError = false;
            $scope.parametersMessage = generateMessageForAllModels();

            var setRowCollectionFromData = function(data) {
                $scope.rowCollection = [];
                $scope.numberOfRows = 0;
                data.forEach(function(aRow) {
                    $scope.numberOfRows += aRow.numberOfRows;
                    $scope.rowCollection = $scope.rowCollection.concat(aRow.result);
                });
            };

            var onError = function(err) {
                console.log('Unable to get the data given error: ' + err);
                $scope.isError = true;
            };

            var finallyDo = function() {
                $scope.isDataLoading = false;

                if($scope.numberOfRows == 0 && !$scope.isError) {
                    $scope.hasNoResults = true;
                    $scope.warningMessage = "There are no classes found with the categories you have selected. Please try again.";
                }
                else if(!$scope.isError) {
                    $scope.showResults = true;
                }
            };

            getAllData()
                .then(setRowCollectionFromData)
                .catch(onError)
                .finally(finallyDo);
        }
        else {
            alert("Please select a class term.");
        }
    };

    var getAllData = function() {
        var apiURLs = getAllAPIUrls();
        var promises = [];

        _.each(apiURLs, function(apiURL) {
            promises.push($rootScope.httpService.getData(apiURL));
        });

        return $q.all(promises);
    };

    var generateBaseURL = function() {
        var baseURLWithoutTerm = $scope.apiUrl + "/classes/term=";
        baseURLWithoutTerm += $scope.$eval('termModel')['term'];
        baseURLWithoutTerm += "?";
        return baseURLWithoutTerm;
    };

    var generateAllParameters = function() {
        var allParameters = [];
        $scope.allJSONAndScopeNames.forEach(function(aScopeVariable) {
            if(aScopeVariable.modelName != 'termModel') {
                var modelValue = $scope.$eval(aScopeVariable.modelName);
                if (modelValue != undefined) {
                    if (isNotArray(modelValue)) {
                        modelValue = [modelValue];
                    }

                    var currentParameters = [];
                    modelValue.forEach(function (aModel) {
                        if (aModel["isOrNot"] != undefined) {
                            currentParameters.push(aModel[aScopeVariable.apiParameterValueFromModel].split(" ").join("-") +
                                "=" + (aModel["isOrNot"] == "Is"));
                        }
                        else {
                            currentParameters.push(aScopeVariable.apiParameterInEndpoint + "=" + aModel[aScopeVariable.apiParameterValueFromModel]);
                        }
                    });
                    allParameters.push(currentParameters);
                }
            }
        });
        return allParameters;
    };

    var getAllAPIUrls = function() {
        var baseURL = generateBaseURL();
        var allParameters = generateAllParameters();
        var allAPIUrls = allParameters
            .reduce($rootScope.cartesianProductService.productAdd, [""]);

        return $rootScope.apiURLService.appendParametersAndReturnAPIUrls(allAPIUrls, baseURL);
    };

    var generateMessageForAllModels = function() {
        var message = "";

        $scope.allJSONAndScopeNames.forEach(function(aScopeVariable) {
            if($scope.$eval(aScopeVariable.modelName) != undefined) {
                var modelValue = $scope.$eval(aScopeVariable.modelName);
                var allDisplayParameters = aScopeVariable.displayParameters.split(", ");
                var allMessagesForModel = getAllMessagesForModelAndParameters(modelValue, allDisplayParameters);

                message += "" + aScopeVariable.uiParameter + ": ";
                message += allMessagesForModel.join(", ");
                message += "
";
            }
        });

        return message;
    };

    var isNotArray = function(models) {
        return $rootScope.types.get(models) !== $rootScope.types.array;
    };

    var getAllMessagesForModelAndParameters = function(models, parameters) {
        if(isNotArray(models)) {
            models = [models];
        }

        var allMessages = [];
        models.forEach(function(model) {
            var aMessageForModel = "";
            parameters.forEach(function(parameter) {
                aMessageForModel = aMessageForModel + model[parameter] + " ";
            });
            allMessages.push(aMessageForModel.trim());
        });
        return allMessages;
    };

    $scope.goBack = function() {
        console.log('Going back to offered class search page.');
        $scope.showResults = false;
    };

    $scope.printDates = function(startDate, endDate) {
        return startDate.replace("-", "/") + " to " + endDate.replace("-", "/");
    };

    $scope.selectTestModels = function() {
        clearAllModels();
        $scope.termModel = {"term": 2000, "year": 2016, "semester": "Fall"};
        $scope.formatModel = [{"format": "Hybrid", "isOrNot": "Is"}, {"format": "Face to Face", "isOrNot": "Not"}];
        $scope.statusModel = {"status": "Closed"};
        $scope.sessionModel = [{"session": 4, "sessionTitle": "Session 4"}, {
            "session": 2,
            "sessionTitle": "Session 2"
        }];
        $scope.subjectModel = [{"subject": "AFSC", "subjectFullName": "Air Force Science"}, {
            "subject": "ARAB",
            "subjectFullName": "Arabic"
        }];
        $scope.buildingModel = [{"buildingID": 517, "building": "A", "buildingName": "Cullen Performance Hall"}];
        $scope.locationModel = [{"location": "UH-Sugar Land"}, {"location": "UH-San Antonio-Conrad Hilton"}, {"location": "UH"}];
        $scope.componentModel = [{"component": "LEC", "componentName": "Lecture"}];
        $scope.creditHourModel = [{"credit-hours": 4}];
        $scope.weekendUModel = {"weekendU": "No"};
        $scope.coreCategoriesModel = [{"categoryNumber": 2, "categoryName": "Mathematics"}];
        $scope.isCoreModel = {"is-core": "No"};
        $scope.syllabusModel = {"syllabus": "No"};
        $scope.classDaysModel = [{"day": "Monday", "isOrNot": "Is"}, {
            "day": "Sunday",
            "isOrNot": "Is"
        }, {"day": "Tuesday", "isOrNot": "Not"}];
        $scope.courseNumberModel = {"courseNumber": 2410};
    };

    $scope.selectTestModelsTwo = function() {
        clearAllModels();
        $scope.termModel = {"term": 2000, "year": 2016, "semester": "Fall"};
        $scope.weekendUModel = {"weekendU": "Yes"};

    };

    $scope.selectTestModelsThree = function() {
        clearAllModels();
        $scope.termModel = {"term": 2000, "year": 2016, "semester": "Fall"};
        $scope.isCoreModel = {"is-core": "Yes"};
        $scope.formatModel = [{"format": "Online", "isOrNot": "Is"}];
    };

    $scope.selectTestModelsOneClassResult = function() {
        clearAllModels();
        $scope.termModel = {"term": 2000, "year": 2016, "semester": "Fall"};
        $scope.formatModel = [{"format": "Online", "isOrNot": "Is"}];
        $scope.sessionModel = [{"session": 6, "sessionTitle": "Session 6"}];
        $scope.subjectModel = [{"subject": "SOC", "subjectFullName": "Sociology"}];

    };

    var clearAllModels = function() {
        $scope.allJSONAndScopeNames.forEach(function(e) {
            $scope.deleteModel(e.modelName);
        });
    };

    $scope.getSyllabus = function(syllabus) {
        if(syllabus == 'Unavailable') {
            return "Syllabus Not Available.";
        }
        else {
            return "<button type='button' class='btn btn-primary'>Syllabus</button>";
        }
    };

    $scope.openSyllabusInNewWindow = function(syllabusLink) {
        if(syllabusLink != 'Unavailable') {
            $window.open(syllabusLink, '_blank');
        }
    };

    $scope.getClassDays = function(classDaysForAClass) {
        var allClassDays = $scope.classDays.dayAbbreviations;

        return allClassDays
                .filter(function(aClassDay) {
                    return classDaysForAClass[aClassDay.classDay];
                })
                .map(function(aClassDay) {
                    return aClassDay.classDayAbbreviation;
                })
                .join("") || "No Class Days";
    };

    $scope.printCoreCategories = function(coreCategories) {
        return coreCategories
                .filter(function(aCoreCategory) {
                    return aCoreCategory.length != 0;
                })
                .map(function(aCoreCategory) {
                    return $scope.coreCategories.availableOptions[aCoreCategory - 1].categoryName;
                })
                .join(", ") || "Not a core class.";
    };

    $scope.displayDetailedOfferedClass = function(aClass) {
        $scope.displayDetailed = true;
        $scope.detailedClass = aClass;
        $scope.detailedOfferedClassMessage = aClass.classTitle;
    };

    $scope.exitDisplayDetailedOfferedClass = function() {
        $scope.displayDetailed = false;
        $scope.detailedClass = undefined;
    };

    $scope.printSeatInformation = function(status, seatInformation) {
        return status + " (" + seatInformation.seatsTaken + "/" +
            seatInformation.seatsTotal + ")";
    }

}]);
<commit_msg>Changed available syllabus link to anchor tag. Removed openSyllabusInNewWindow, since the logic can be inlined with the anchor tag.<commit_after>'use strict';

angular.module('classBrowserUHApp.offeredClass', ['ngRoute'])

.config(['$routeProvider', function($routeProvider) {
    $routeProvider.when('/offeredClass', {
        templateUrl: 'views/offeredClass/offeredClass.html',
        controller: 'OfferedClassCtrl'
    });
}])
.controller('OfferedClassCtrl', ['$scope', '$http', '$q', '$rootScope', '$parse', '$window', function ($scope, $http, $q, $rootScope, $parse, $window) {
    var setScopeVariableFromJSON = function(filePath, scopeVariable) {
        $rootScope.httpService.getData(filePath).then(function(result) {
            $parse(scopeVariable).assign($scope, result);
        });
    };

    var initializeAllJSONAndScopeNames = function(name) {
        $rootScope.httpService.getData('resources/allScopeVariables.json').then(function(result) {
            $scope.allJSONAndScopeNames = result[name];
            $scope.allJSONAndScopeNames.forEach(function(e) {
                setScopeVariableFromJSON(e.path, e.scopeName);
            });
        });
    };

    initializeAllJSONAndScopeNames("offeredClass");

    $scope.validValues = ['A','1','2', '3', '4', '5', '6', '7', '8', '9', '0'];

    $scope.deleteModel = function() {
        [].slice.call(arguments).forEach(function(arg) {
            delete $scope[arg];
        });
    };

    $scope.clearForms = function() {
        var clearFormDialogConfirmation = $window.confirm('Are you sure you want to clear the entire form?');

        if (clearFormDialogConfirmation) {
            clearAllModels();
            $scope.deleteModel('warningMessage', 'hasNoResults', 'isError');
        }
    };

    $scope.findClasses = function(isValidForm) {
        if(isValidForm) {
            $scope.isDataLoading = true;
            $scope.hasNoResults = false;
            $scope.isError = false;
            $scope.parametersMessage = generateMessageForAllModels();

            var setRowCollectionFromData = function(data) {
                $scope.rowCollection = [];
                $scope.numberOfRows = 0;
                data.forEach(function(aRow) {
                    $scope.numberOfRows += aRow.numberOfRows;
                    $scope.rowCollection = $scope.rowCollection.concat(aRow.result);
                });
            };

            var onError = function(err) {
                console.log('Unable to get the data given error: ' + err);
                $scope.isError = true;
            };

            var finallyDo = function() {
                $scope.isDataLoading = false;

                if($scope.numberOfRows == 0 && !$scope.isError) {
                    $scope.hasNoResults = true;
                    $scope.warningMessage = "There are no classes found with the categories you have selected. Please try again.";
                }
                else if(!$scope.isError) {
                    $scope.showResults = true;
                }
            };

            getAllData()
                .then(setRowCollectionFromData)
                .catch(onError)
                .finally(finallyDo);
        }
        else {
            alert("Please select a class term.");
        }
    };

    var getAllData = function() {
        var apiURLs = getAllAPIUrls();
        var promises = [];

        _.each(apiURLs, function(apiURL) {
            promises.push($rootScope.httpService.getData(apiURL));
        });

        return $q.all(promises);
    };

    var generateBaseURL = function() {
        var baseURLWithoutTerm = $scope.apiUrl + "/classes/term=";
        baseURLWithoutTerm += $scope.$eval('termModel')['term'];
        baseURLWithoutTerm += "?";
        return baseURLWithoutTerm;
    };

    var generateAllParameters = function() {
        var allParameters = [];
        $scope.allJSONAndScopeNames.forEach(function(aScopeVariable) {
            if(aScopeVariable.modelName != 'termModel') {
                var modelValue = $scope.$eval(aScopeVariable.modelName);
                if (modelValue != undefined) {
                    if (isNotArray(modelValue)) {
                        modelValue = [modelValue];
                    }

                    var currentParameters = [];
                    modelValue.forEach(function (aModel) {
                        if (aModel["isOrNot"] != undefined) {
                            currentParameters.push(aModel[aScopeVariable.apiParameterValueFromModel].split(" ").join("-") +
                                "=" + (aModel["isOrNot"] == "Is"));
                        }
                        else {
                            currentParameters.push(aScopeVariable.apiParameterInEndpoint + "=" + aModel[aScopeVariable.apiParameterValueFromModel]);
                        }
                    });
                    allParameters.push(currentParameters);
                }
            }
        });
        return allParameters;
    };

    var getAllAPIUrls = function() {
        var baseURL = generateBaseURL();
        var allParameters = generateAllParameters();
        var allAPIUrls = allParameters
            .reduce($rootScope.cartesianProductService.productAdd, [""]);

        return $rootScope.apiURLService.appendParametersAndReturnAPIUrls(allAPIUrls, baseURL);
    };

    var generateMessageForAllModels = function() {
        var message = "";

        $scope.allJSONAndScopeNames.forEach(function(aScopeVariable) {
            if($scope.$eval(aScopeVariable.modelName) != undefined) {
                var modelValue = $scope.$eval(aScopeVariable.modelName);
                var allDisplayParameters = aScopeVariable.displayParameters.split(", ");
                var allMessagesForModel = getAllMessagesForModelAndParameters(modelValue, allDisplayParameters);

                message += "" + aScopeVariable.uiParameter + ": ";
                message += allMessagesForModel.join(", ");
                message += "
";
            }
        });

        return message;
    };

    var isNotArray = function(models) {
        return $rootScope.types.get(models) !== $rootScope.types.array;
    };

    var getAllMessagesForModelAndParameters = function(models, parameters) {
        if(isNotArray(models)) {
            models = [models];
        }

        var allMessages = [];
        models.forEach(function(model) {
            var aMessageForModel = "";
            parameters.forEach(function(parameter) {
                aMessageForModel = aMessageForModel + model[parameter] + " ";
            });
            allMessages.push(aMessageForModel.trim());
        });
        return allMessages;
    };

    $scope.goBack = function() {
        console.log('Going back to offered class search page.');
        $scope.showResults = false;
    };

    $scope.printDates = function(startDate, endDate) {
        return startDate.replace("-", "/") + " to " + endDate.replace("-", "/");
    };

    $scope.selectTestModels = function() {
        clearAllModels();
        $scope.termModel = {"term": 2000, "year": 2016, "semester": "Fall"};
        $scope.formatModel = [{"format": "Hybrid", "isOrNot": "Is"}, {"format": "Face to Face", "isOrNot": "Not"}];
        $scope.statusModel = {"status": "Closed"};
        $scope.sessionModel = [{"session": 4, "sessionTitle": "Session 4"}, {
            "session": 2,
            "sessionTitle": "Session 2"
        }];
        $scope.subjectModel = [{"subject": "AFSC", "subjectFullName": "Air Force Science"}, {
            "subject": "ARAB",
            "subjectFullName": "Arabic"
        }];
        $scope.buildingModel = [{"buildingID": 517, "building": "A", "buildingName": "Cullen Performance Hall"}];
        $scope.locationModel = [{"location": "UH-Sugar Land"}, {"location": "UH-San Antonio-Conrad Hilton"}, {"location": "UH"}];
        $scope.componentModel = [{"component": "LEC", "componentName": "Lecture"}];
        $scope.creditHourModel = [{"credit-hours": 4}];
        $scope.weekendUModel = {"weekendU": "No"};
        $scope.coreCategoriesModel = [{"categoryNumber": 2, "categoryName": "Mathematics"}];
        $scope.isCoreModel = {"is-core": "No"};
        $scope.syllabusModel = {"syllabus": "No"};
        $scope.classDaysModel = [{"day": "Monday", "isOrNot": "Is"}, {
            "day": "Sunday",
            "isOrNot": "Is"
        }, {"day": "Tuesday", "isOrNot": "Not"}];
        $scope.courseNumberModel = {"courseNumber": 2410};
    };

    $scope.selectTestModelsTwo = function() {
        clearAllModels();
        $scope.termModel = {"term": 2000, "year": 2016, "semester": "Fall"};
        $scope.weekendUModel = {"weekendU": "Yes"};

    };

    $scope.selectTestModelsThree = function() {
        clearAllModels();
        $scope.termModel = {"term": 2000, "year": 2016, "semester": "Fall"};
        $scope.isCoreModel = {"is-core": "Yes"};
        $scope.formatModel = [{"format": "Online", "isOrNot": "Is"}];
    };

    $scope.selectTestModelsOneClassResult = function() {
        clearAllModels();
        $scope.termModel = {"term": 2000, "year": 2016, "semester": "Fall"};
        $scope.formatModel = [{"format": "Online", "isOrNot": "Is"}];
        $scope.sessionModel = [{"session": 6, "sessionTitle": "Session 6"}];
        $scope.subjectModel = [{"subject": "SOC", "subjectFullName": "Sociology"}];

    };

    var clearAllModels = function() {
        $scope.allJSONAndScopeNames.forEach(function(e) {
            $scope.deleteModel(e.modelName);
        });
    };

    $scope.getSyllabus = function(syllabus) {
        if(syllabus == 'Unavailable') {
            return "Syllabus Not Available.";
        }
        else {
            return "Syllabus";
        }
    };

    $scope.getClassDays = function(classDaysForAClass) {
        var allClassDays = $scope.classDays.dayAbbreviations;

        return allClassDays
                .filter(function(aClassDay) {
                    return classDaysForAClass[aClassDay.classDay];
                })
                .map(function(aClassDay) {
                    return aClassDay.classDayAbbreviation;
                })
                .join("") || "No Class Days";
    };

    $scope.printCoreCategories = function(coreCategories) {
        return coreCategories
                .filter(function(aCoreCategory) {
                    return aCoreCategory.length != 0;
                })
                .map(function(aCoreCategory) {
                    return $scope.coreCategories.availableOptions[aCoreCategory - 1].categoryName;
                })
                .join(", ") || "Not a core class.";
    };

    $scope.displayDetailedOfferedClass = function(aClass) {
        $scope.displayDetailed = true;
        $scope.detailedClass = aClass;
        $scope.detailedOfferedClassMessage = aClass.classTitle;
    };

    $scope.exitDisplayDetailedOfferedClass = function() {
        $scope.displayDetailed = false;
        $scope.detailedClass = undefined;
    };

    $scope.printSeatInformation = function(status, seatInformation) {
        return status + " (" + seatInformation.seatsTaken + "/" +
            seatInformation.seatsTotal + ")";
    }

}]);
<|endoftext|>