<commit_before>var Botkit = require('botkit')
var http = require('http')

// Expect a SLACK_TOKEN environment variable

firebaseStorage = require('botkit-storage-firebase')({firebase_uri: 'https://demobot.firebaseIO.com'})
var controller = Botkit.slackbot({
    storage: firebaseStorage
});

var con = require('beepboop-botkit').start(controller)

controller.hears(['hello', 'hi', 'hola'], ['direct_message'], function (bot, message) {
    bot.reply(message, helpText)
})

var persona = {id:"default", persona_name:'Demo Bot', persona_icon: 'http://lorempixel.com/48/48'};

var morgan = require('morgan')

controller.setupWebserver(process.env.PORT,function(err,webserver) {
    controller.createWebhookEndpoints(webserver);
});

function cleanKey(key) {
    // strings and can't contain ".", "#", "$", "/", "[", or "]"
    return key.toLowerCase().replace(".","").replace("?","").replace("$","").replace("/","").replace("[","").replace("]","").replace("#","").trim()
}

controller.on('slash_command', function (bot, message) {
    console.log('Here is the actual slash command used: ', message.command);
    var team_id  = message.team_id;
    loadPersonality(team_id, function () {

        if(message.command == '/learn'){
            var learn = message.text
            var man_say = learn.substr(0, learn.indexOf("\n")-1);
            var bot_say = learn.substr(learn.indexOf("\n")+1);
            man_say = cleanKey(man_say);
            bot_say = bot_say.trim();
            if(man_say == "" || bot_say == ""){
                bot.replyPrivate(message, 'missing param - you say is ('+man_say+') I say is ('+bot_say+') ');
                return;
            }
            var  attachments = null;
            if(bot_say.indexOf('"attachments')>0){
                p_data = JSON.parse(bot_say);
                attachments = p_data["attachments"];
                bot_say  = "";
            }
            saving  = persona.id+'_voc/_'+man_say;
            console.log('Saving key, value: ', "["+saving+"],["+bot_say+"}", attachments );
            if(attachments != null){
                var learning = {id: saving, botsay: bot_say, attachments: attachments};
                controller.storage.teams.save(learning);
                bot.replyPrivate(message, 'When you say: '+man_say+' \n I will say: '+p_data)
            }else{
                var learning = {id: saving, botsay: bot_say};
                controller.storage.teams.save(learning);
                bot.replyPrivate(message, 'When you say: '+man_say+' \n I will say: '+bot_say)
            }

        }else if(message.command == '/new-persona'){

            var new_persona_id = cleanKey(message.text);
            controller.storage.teams.get(new_persona_id , function(err, val) {
                if(val != null){
                    bot.replyPrivate(message, 'I already have this persona');
                }else{
                    save_id = team_id+"_"+new_persona_id
                    new_persona = {id:save_id, persona_name:'Demo Bot', persona_icon: 'http://lorempixel.com/48/48'};
                    controller.storage.teams.save(new_persona);

                    var current_persona = {id: team_id+"_"+'current_persona', data: new_persona};
                    controller.storage.teams.save(current_persona);

                    load_id = team_id+"_personas"
                    controller.storage.teams.get(load_id , function(err, val) {
                        if(val != null){
                            val.data.push(new_persona_id)
                            controller.storage.teams.save(val);
                        }else{
                            var personas = {id: team_id+"_personas", data: [new_persona_id]};
                            controller.storage.teams.save(personas);
                        }
                    });

                    bot.replyPrivate(message, 'Created new persona - '+new_persona_id);
                }
            });

        }else if (message.command == '/load-persona'){
            var new_persona_id = cleanKey(message.text);
            load_id = team_id+"_"+new_persona_id
            controller.storage.teams.get(load_id , function(err, val) {
                if(val != null){
                    //console.log('loaded value, new_persona_id -', val, new_persona_id);
                    var current_persona = {id: team_id+"_"+'current_persona', data: val};
                    controller.storage.teams.save(current_persona);

                    bot.replyPrivate(message, 'Loaded new persona - '+val.id);
                }else{

                    // persona not found
                    bot.replyPrivate(message, 'I need my meds! could not find - '+new_persona_id);
                }
            });

        }else if (message.command == '/set-persona-name'){
            var new_persona_name = message.text.trim();
            controller.storage.teams.get(team_id+"_"+'current_persona', function(err, val) {
                if(val != null){
                    persona = val.data
                    val.data.persona_name = new_persona_name;
                    controller.storage.teams.save(val);
                    persona_id = val.data.id;
                    controller.storage.teams.get(persona_id, function(err, val1) {
                        if(val1 != null){
                            val1.persona_name = new_persona_name;
                            controller.storage.teams.save(val1);
                            bot.replyPrivate(message, 'From now on I shall be called Sir '+new_persona_name);

                        }
                    });
                }
            });

        }else if (message.command == '/list-personas'){
            controller.storage.teams.get(team_id+"_personas", function(err, val) {
                if(val != null){
                    bot.replyPrivate(message, 'Personas -  '+ val.data);
                }else{
                    bot.replyPrivate(message, 'No Personas');
                }
            });

        }else if (message.command == '/set-persona-icon-url'){
                var new_persona_icon_url = message.text.trim();
                controller.storage.teams.get(team_id+"_"+'current_persona', function(err, val) {
                    if(val != null){
                        persona = val.data
                        val.data.persona_icon = new_persona_icon_url;
                        controller.storage.teams.save(val);
                        persona_id = val.data.id;
                        controller.storage.teams.get(persona_id, function(err, val1) {
                            if(val1 != null){
                                val1.persona_icon = new_persona_icon_url;
                                controller.storage.teams.save(val1);
                                bot.replyPrivate(message, 'From now on I shall use a new icon - '+new_persona_icon_url);

                            }
                        });
                    }
                });

        }else if (message.command == '/demo-setting'){
            var setting = message.text.trim();
            var key = setting.substring(0, setting.indexOf(" ")).trim();
            var value = setting.substring(setting.indexOf(" ")).trim();
            console.log('Saving key, value: ', "["+key+"],["+value+"]" );
            save_id = team_id+"_setting/"+key;
            new_persona = {id:save_id, value:value};
            controller.storage.teams.save(new_persona);
            bot.replyPublic(message, "");

        }else if (message.command == '/persona-set-notification'){

            var setting = message.text.trim();
            var key = setting.substring(0, setting.indexOf(" ")).trim();
            var interval = setting.substring(setting.indexOf(" "),setting.indexOf("\n")).trim();
            var bot_say = learn.substr(setting.indexOf("\n")+1);
            console.log('Saving notification key, interval, bot_say - ', "["+key+"],["+interval+"],["+bot_say+"]" );
            //save_id = team_id+"_notification/"+key;
            //new_persona = {id:save_id, value:value};
            //controller.storage.teams.save(new_persona);

            bot.replyPublic(message, "");

        }else{
            bot.replyPublic(message, "");

        }
    });

});

/*
beepboop.on('botkit.rtm.started', function (bot, resource, meta) {
    var slackUserId = resource.SlackUserID

    if (meta.isNew && slackUserId) {
        bot.api.im.open({ user: slackUserId }, function (err, response) {
            if (err) {
                return console.log(err)
            }
            var dmChannel = response.channel.id
            bot.say({channel: dmChannel, text: 'Thanks for adding me to your team!'})
            bot.say({channel: dmChannel, text: 'You can now /invite me to a channel, so that I can be of use to the team, or DM/@wordsbot me anytime!'})
        })
    }
})
*/

controller.on('bot_channel_join', function (bot, message) {
    bot.reply(message, ":wave: team -  I am your WordsBot - give me a word and I will provide you with Definition and Synonyms. \n I support direct mentions and DMs, I will not read what is in this channel,  you will need to `@wordsbot: word-you-are-looking-for` me.")
})

//controller.hears(['hello', 'hi'], ['direct_mention'], function (bot, message) {
//    bot.reply(message, ':wave:')
//})

controller.hears('meta-help', ['direct_message', 'direct_mention'], function (bot, message) {
    var help = 'I will respond to the following messages: \n' +
        '`DM` me with a word.\n' +
        '`@wordsbot:` with a word.\n' +
        '`/define` with a word (this way only you see the results).\n' +
        '`bot help` to see this again.'
    bot.reply(message, help)
})

controller.hears('.*', ['direct_message', 'direct_mention', 'ambient'], function (bot, message) {
    console.log('msg - ', message);
    var team_id = message.team;
    loadPersonality(team_id, function () {
        man_say = cleanKey(message.text);
        loading  = persona.id+'_voc/_'+man_say;
        console.log('Loading key: ', "["+loading+"]");

        controller.storage.teams.get(loading, function(err, val) {
            console.log("got value" , val)
            if(val == undefined){
                console.log('what should I say when you say "'+man_say+'"');
                if(message.event != "ambient"){
                    //bot.reply(message, compose('what should I say when you say "'+man_say+'"? not sure... \n Please use /learn to teach me new tricks!', [] ));
                }
            }else{
                resp = val["botsay"].toString();
                var attach = val["attachments"];
                if(attach == undefined || attach == null){
                    attach = []
                }
                bot.reply(message, compose(resp, attach) )
            }
        });

    });

})

function compose(text, attachments){
    console.log('compose for persona ', persona);
    var reply_with_attachments = {
        'username': persona.persona_name ,
        'text': text,
        'attachments': attachments,
        'icon_url': persona.persona_icon
    }
    return reply_with_attachments;

}

function loadPersonality(team_id, callback) {
    console.log('loadPersonality ');
    controller.storage.teams.get(team_id+"_"+'current_persona', function(err, val) {
        if(val != null){
            persona = val.data
            console.log('calling callback', val.data);
            callback();
        }else{
            save_id = team_id+"_default"
            new_persona = {id:save_id, persona_name:'Demo Bot', persona_icon: 'http://lorempixel.com/48/48'};
            controller.storage.teams.save(new_persona);
            var current_persona = {id: team_id+"_"+'current_persona', data: new_persona};
            controller.storage.teams.save(current_persona);
            persona = current_persona.data;
            personas = {id: team_id+"_personas", data: ["default"]};
            controller.storage.teams.save(personas);
            callback();
        }
    });
}

function getRandomColor() {
    var letters = '0123456789ABCDEF'.split('');
    var color = '#';
    for (var i = 0; i < 6; i++ ) {
        color += letters[Math.floor(Math.random() * 16)];
    }
    return color;
}

var helpText = ' *What is the Demo Bot* \n'+
':robot_face: The Demo Bot is an easy to script bot - you simply talk to the bot and teach it what to answer when you say something. The Demo bot supports multiple scripts (personalities) alongside the ability to change it’s name and icon for each. \n'+
'\n*How to use the Demo Bot*'+
'> The bot can learn to reply to any text you send, either in DM or in channel in which the bot was invited to.\n'+
'\n*Working with your bot*\n'+
'* Add the bot to your team and invite it to the appropriate channels (https://beepboophq.com/bots/1d563b4601d44aeca2bda92547894460).\n'+
'* Use `/add-persona [persona name]` to start a new script (this will automatically switch to the newly created persona)\n'+
'* Use `/set-persona-name [display name]` to set the name the bot will use to display in this script\n'+
'* Use `/set-persona-icon-url [URL]` to set the icon the bot will use in this script.\n'+
    '* Use `/load-persona [persona name]` to switch between scripts\n'+
    '* Use `/learn [you say] \\n [bot say]` to teach the bot new tricks, see _Training  your bot_ for more details.\n'+
        '* Run the script by just saying your part of the script the let the bot follow\n'+
        '\n*Training  your bot*\n'+
        'Use the `/learn [you say] \n [bot say]` slash command to teach the bot what to say. Note the new-line between what you say and what the bot say (Use `shift`+`enter`)\n'+
        'Here are a few examples:\n'+
            '* Human say “wazzap?” the bot will say ":wave: all good" -\n'+
        '`/learn wazzap?`\n'+
         '`:wave: all good`\n'+
        '* Human say “/report xyz” the bot will say “:dollar: 500K made this week" - \n'+
            '`/learn /report xyz`\n'+
            '`:dollar: 500K made this week`\n'+
        '* Human say “complex” the bot will say _something complex with attachments_ -\n'+
        '`/learn complex`\n'+
            '`{Jason with attachments}`\n'+
        '> Best way to train the demo bot is DMing it. When the bot does not know what to say in DM, it will give you feedback, the bot will say nothing if it does not know what to say in a channel.\n';

<commit_msg>export try<commit_after>var Botkit = require('botkit')
var http = require('http')

// Expect a SLACK_TOKEN environment variable

firebaseStorage = require('botkit-storage-firebase')({firebase_uri: 'https://demobot.firebaseIO.com'})
var controller = Botkit.slackbot({
    storage: firebaseStorage
});

var con = require('beepboop-botkit').start(controller)

controller.hears(['hello', 'hi', 'hola'], ['direct_message'], function (bot, message) {
    bot.reply(message, helpText)
})

var persona = {id:"default", persona_name:'Demo Bot', persona_icon: 'http://lorempixel.com/48/48'};

var morgan = require('morgan')

controller.setupWebserver(process.env.PORT,function(err,webserver) {
    controller.createWebhookEndpoints(webserver);
});

function cleanKey(key) {
    // strings and can't contain ".", "#", "$", "/", "[", or "]"
    return key.toLowerCase().replace(".","").replace("?","").replace("$","").replace("/","").replace("[","").replace("]","").replace("#","").trim()
}

controller.on('slash_command', function (bot, message) {
    console.log('Here is the actual slash command used: ', message.command);
    var team_id  = message.team_id;
    loadPersonality(team_id, function () {

        if(message.command == '/learn'){
            var learn = message.text
            var man_say = learn.substr(0, learn.indexOf("\n")-1);
            var bot_say = learn.substr(learn.indexOf("\n")+1);
            man_say = cleanKey(man_say);
            bot_say = bot_say.trim();
            if(man_say == "" || bot_say == ""){
                bot.replyPrivate(message, 'missing param - you say is ('+man_say+') I say is ('+bot_say+') ');
                return;
            }
            var  attachments = null;
            if(bot_say.indexOf('"attachments')>0){
                p_data = JSON.parse(bot_say);
                attachments = p_data["attachments"];
                bot_say  = "";
            }
            saving  = persona.id+'_voc/_'+man_say;
            console.log('Saving key, value: ', "["+saving+"],["+bot_say+"}", attachments );
            if(attachments != null){
                var learning = {id: saving, botsay: bot_say, attachments: attachments};
                controller.storage.teams.save(learning);
                bot.replyPrivate(message, 'When you say: '+man_say+' \n I will say: '+p_data)
            }else{
                var learning = {id: saving, botsay: bot_say};
                controller.storage.teams.save(learning);
                bot.replyPrivate(message, 'When you say: '+man_say+' \n I will say: '+bot_say)
            }

        }else if(message.command == '/new-persona'){

            var new_persona_id = cleanKey(message.text);
            controller.storage.teams.get(new_persona_id , function(err, val) {
                if(val != null){
                    bot.replyPrivate(message, 'I already have this persona');
                }else{
                    save_id = team_id+"_"+new_persona_id
                    new_persona = {id:save_id, persona_name:'Demo Bot', persona_icon: 'http://lorempixel.com/48/48'};
                    controller.storage.teams.save(new_persona);

                    var current_persona = {id: team_id+"_"+'current_persona', data: new_persona};
                    controller.storage.teams.save(current_persona);

                    load_id = team_id+"_personas"
                    controller.storage.teams.get(load_id , function(err, val) {
                        if(val != null){
                            val.data.push(new_persona_id)
                            controller.storage.teams.save(val);
                        }else{
                            var personas = {id: team_id+"_personas", data: [new_persona_id]};
                            controller.storage.teams.save(personas);
                        }
                    });

                    bot.replyPrivate(message, 'Created new persona - '+new_persona_id);
                }
            });

        }else if (message.command == '/load-persona'){
            var new_persona_id = cleanKey(message.text);
            load_id = team_id+"_"+new_persona_id
            controller.storage.teams.get(load_id , function(err, val) {
                if(val != null){
                    //console.log('loaded value, new_persona_id -', val, new_persona_id);
                    var current_persona = {id: team_id+"_"+'current_persona', data: val};
                    controller.storage.teams.save(current_persona);

                    bot.replyPrivate(message, 'Loaded new persona - '+val.id);
                }else{

                    // persona not found
                    bot.replyPrivate(message, 'I need my meds! could not find - '+new_persona_id);
                }
            });

        }else if (message.command == '/set-persona-name'){
            var new_persona_name = message.text.trim();
            controller.storage.teams.get(team_id+"_"+'current_persona', function(err, val) {
                if(val != null){
                    persona = val.data
                    val.data.persona_name = new_persona_name;
                    controller.storage.teams.save(val);
                    persona_id = val.data.id;
                    controller.storage.teams.get(persona_id, function(err, val1) {
                        if(val1 != null){
                            val1.persona_name = new_persona_name;
                            controller.storage.teams.save(val1);
                            bot.replyPrivate(message, 'From now on I shall be called Sir '+new_persona_name);

                        }
                    });
                }
            });

        }else if (message.command == '/list-personas'){
            controller.storage.teams.get(team_id+"_personas", function(err, val) {
                if(val != null){
                    bot.replyPrivate(message, 'Personas -  '+ val.data);
                }else{
                    bot.replyPrivate(message, 'No Personas');
                }
            });

        }else if (message.command == '/export-persona'){
            bot.api.files.upload({ filename: filename, content: "hello world", filetype: 'text', channels: message.channel }, function(err,res) {
                if (err) {
                    bot.replyPrivate(message, 'can not export!');
                    console.log(err)
                    return;
                }
            });

        }else if (message.command == '/set-persona-icon-url'){
            var new_persona_icon_url = message.text.trim();
            controller.storage.teams.get(team_id+"_"+'current_persona', function(err, val) {
                if(val != null){
                    persona = val.data
                    val.data.persona_icon = new_persona_icon_url;
                    controller.storage.teams.save(val);
                    persona_id = val.data.id;
                    controller.storage.teams.get(persona_id, function(err, val1) {
                        if(val1 != null){
                            val1.persona_icon = new_persona_icon_url;
                            controller.storage.teams.save(val1);
                            bot.replyPrivate(message, 'From now on I shall use a new icon - '+new_persona_icon_url);

                        }
                    });
                }
            });

        }else if (message.command == '/demo-setting'){
            var setting = message.text.trim();
            var key = setting.substring(0, setting.indexOf(" ")).trim();
            var value = setting.substring(setting.indexOf(" ")).trim();
            console.log('Saving key, value: ', "["+key+"],["+value+"]" );
            save_id = team_id+"_setting/"+key;
            new_persona = {id:save_id, value:value};
            controller.storage.teams.save(new_persona);
            bot.replyPublic(message, "");

        }else if (message.command == '/persona-set-notification'){

            var setting = message.text.trim();
            var key = setting.substring(0, setting.indexOf(" ")).trim();
            var interval = setting.substring(setting.indexOf(" "),setting.indexOf("\n")).trim();
            var bot_say = learn.substr(setting.indexOf("\n")+1);
            console.log('Saving notification key, interval, bot_say - ', "["+key+"],["+interval+"],["+bot_say+"]" );
            //save_id = team_id+"_notification/"+key;
            //new_persona = {id:save_id, value:value};
            //controller.storage.teams.save(new_persona);

            bot.replyPublic(message, "");

        }else{
            bot.replyPublic(message, "");

        }
    });

});

/*
beepboop.on('botkit.rtm.started', function (bot, resource, meta) {
    var slackUserId = resource.SlackUserID

    if (meta.isNew && slackUserId) {
        bot.api.im.open({ user: slackUserId }, function (err, response) {
            if (err) {
                return console.log(err)
            }
            var dmChannel = response.channel.id
            bot.say({channel: dmChannel, text: 'Thanks for adding me to your team!'})
            bot.say({channel: dmChannel, text: 'You can now /invite me to a channel, so that I can be of use to the team, or DM/@wordsbot me anytime!'})
        })
    }
})
*/

controller.on('bot_channel_join', function (bot, message) {
    bot.reply(message, ":wave: team -  I am your WordsBot - give me a word and I will provide you with Definition and Synonyms. \n I support direct mentions and DMs, I will not read what is in this channel,  you will need to `@wordsbot: word-you-are-looking-for` me.")
})

//controller.hears(['hello', 'hi'], ['direct_mention'], function (bot, message) {
//    bot.reply(message, ':wave:')
//})

controller.hears('meta-help', ['direct_message', 'direct_mention'], function (bot, message) {
    var help = 'I will respond to the following messages: \n' +
        '`DM` me with a word.\n' +
        '`@wordsbot:` with a word.\n' +
        '`/define` with a word (this way only you see the results).\n' +
        '`bot help` to see this again.'
    bot.reply(message, help)
})

controller.hears('.*', ['direct_message', 'direct_mention', 'ambient'], function (bot, message) {
    console.log('msg - ', message);
    var team_id = message.team;
    loadPersonality(team_id, function () {
        man_say = cleanKey(message.text);
        loading  = persona.id+'_voc/_'+man_say;
        console.log('Loading key: ', "["+loading+"]");

        controller.storage.teams.get(loading, function(err, val) {
            console.log("got value" , val)
            if(val == undefined){
                console.log('what should I say when you say "'+man_say+'"');
                if(message.event != "ambient"){
                    //bot.reply(message, compose('what should I say when you say "'+man_say+'"? not sure... \n Please use /learn to teach me new tricks!', [] ));
                }
            }else{
                resp = val["botsay"].toString();
                var attach = val["attachments"];
                if(attach == undefined || attach == null){
                    attach = []
                }
                bot.reply(message, compose(resp, attach) )
            }
        });

    });

})

function compose(text, attachments){
    console.log('compose for persona ', persona);
    var reply_with_attachments = {
        'username': persona.persona_name ,
        'text': text,
        'attachments': attachments,
        'icon_url': persona.persona_icon
    }
    return reply_with_attachments;

}

function loadPersonality(team_id, callback) {
    console.log('loadPersonality ');
    controller.storage.teams.get(team_id+"_"+'current_persona', function(err, val) {
        if(val != null){
            persona = val.data
            console.log('calling callback', val.data);
            callback();
        }else{
            save_id = team_id+"_default"
            new_persona = {id:save_id, persona_name:'Demo Bot', persona_icon: 'http://lorempixel.com/48/48'};
            controller.storage.teams.save(new_persona);
            var current_persona = {id: team_id+"_"+'current_persona', data: new_persona};
            controller.storage.teams.save(current_persona);
            persona = current_persona.data;
            personas = {id: team_id+"_personas", data: ["default"]};
            controller.storage.teams.save(personas);
            callback();
        }
    });
}

function getRandomColor() {
    var letters = '0123456789ABCDEF'.split('');
    var color = '#';
    for (var i = 0; i < 6; i++ ) {
        color += letters[Math.floor(Math.random() * 16)];
    }
    return color;
}

var helpText = ' *What is the Demo Bot* \n'+
':robot_face: The Demo Bot is an easy to script bot - you simply talk to the bot and teach it what to answer when you say something. The Demo bot supports multiple scripts (personalities) alongside the ability to change it’s name and icon for each. \n'+
'\n*How to use the Demo Bot*'+
'> The bot can learn to reply to any text you send, either in DM or in channel in which the bot was invited to.\n'+
'\n*Working with your bot*\n'+
'* Add the bot to your team and invite it to the appropriate channels (https://beepboophq.com/bots/1d563b4601d44aeca2bda92547894460).\n'+
'* Use `/add-persona [persona name]` to start a new script (this will automatically switch to the newly created persona)\n'+
'* Use `/set-persona-name [display name]` to set the name the bot will use to display in this script\n'+
'* Use `/set-persona-icon-url [URL]` to set the icon the bot will use in this script.\n'+
    '* Use `/list-personas` list known personas.\n'+
    '* Use `/load-persona [persona name]` to switch between scripts\n'+
    '* Use `/learn [you say] \\n [bot say]` to teach the bot new tricks, see _Training  your bot_ for more details.\n'+
        '* Run the script by just saying your part of the script the let the bot follow\n'+
        '\n*Training  your bot*\n'+
        'Use the `/learn [you say] \n [bot say]` slash command to teach the bot what to say. Note the new-line between what you say and what the bot say (Use `shift`+`enter`)\n'+
        'Here are a few examples:\n'+
            '* Human say “wazzap?” the bot will say ":wave: all good" -\n'+
        '`/learn wazzap?`\n'+
         '`:wave: all good`\n'+
        '* Human say “/report xyz” the bot will say “:dollar: 500K made this week" - \n'+
            '`/learn /report xyz`\n'+
            '`:dollar: 500K made this week`\n'+
        '* Human say “complex” the bot will say _something complex with attachments_ -\n'+
        '`/learn complex`\n'+
            '`{Jason with attachments}`\n'+
        '> Best way to train the demo bot is DMing it. When the bot does not know what to say in DM, it will give you feedback, the bot will say nothing if it does not know what to say in a channel.\n';

<|endoftext|>


<commit_before>function startTest() {
  mediaFile = document.querySelector('input').value;
  keySystem = keySystemList.value;
  mediaType = mediaTypeList.value;

  loadEncryptedMediaFromURL(video, useSRC.checked);
  video.play();
}

function loadEncryptedMediaFromURL(video, useSRC) {
  return loadEncryptedMedia(video, mediaFile, keySystem, mediaType, useSRC);
}

function loadEncryptedMedia(video, mediaFiles, keySystem, mediaTypes, useSRC) {
  console.log('Trying to run:');
  console.log('mediaFiles: ' + mediaFiles);
  console.log('mediaTypes: ' + mediaTypes);
  console.log('keySystem: ' + keySystem);
  mediaSource = null;
  video = video;

  // Add a property to video to check key was added.
  video.hasKeyAdded = false;
  mediaFiles = ConvertToArray(mediaFiles);
  mediaTypes = ConvertToArray(mediaTypes);

  if (!(video && mediaFiles && keySystem))
    failTest('Missing parameters in loadEncryptedMedia().');

  var totalAppended = 0;
  function onSourceOpen(e) {
    console.log('onSourceOpen', e);
    // We can load multiple media files using the same media type. However, if
    // more than one media type is used, we expect to have a media type entry
    // for each corresponding media file.
    var srcBuffer = null;
    for (var i = 0; i < mediaFiles.length; i++) {
      if (i == 0 || mediaFiles.length == mediaTypes.length) {
        console.log('Creating a source buffer for type ' + mediaTypes[i]);
        srcBuffer = mediaSource.addSourceBuffer(mediaTypes[i]);
      }
      doAppend(mediaFiles[i], srcBuffer);
    }
  }
  function doAppend(mediaFile, srcBuffer) {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', mediaFile);
    xhr.responseType = 'arraybuffer';
    xhr.addEventListener('load', function(e) {
      console.log('Appending to buffer ' + mediaFile);
      srcBuffer.append(new Uint8Array(e.target.response));
      totalAppended++;
      if (totalAppended == mediaFiles.length)
        mediaSource.endOfStream();
    });
    xhr.send();
  }
  //removeEventListeners(video, mediaSource);

  video.addEventListener('webkitneedkey', onNeedKey);
  video.addEventListener('webkitkeymessage', onKeyMessage);
  video.addEventListener('webkitkeyerror', failTest);
  video.addEventListener('webkitkeyadded', onKeyAdded);

  if (useSRC)
    video.src = mediaFile;
  else {
    mediaSource = new WebKitMediaSource();
    mediaSource.addEventListener('webkitsourceopen', onSourceOpen);
    video.src = window.URL.createObjectURL(mediaSource);
  }
}

function onNeedKey(e) {
  console.log('onNeedKey', e);
  console.log('Generate key request with initData: ' + getHexString(e.initData));
  e.target.webkitGenerateKeyRequest(keySystem, e.initData);
}

function onKeyAdded(e) {
  e.target.hasKeyAdded = true;
}

function onKeyMessage(e) {
  console.log('onKeyMessage', e);
  if (isHeartBeatMessage(e.message)) {
    console.log('onKeyMessage - heart beat', e);
    return;
  }
  if (keySystem == 'com.widevine.alpha' || USE_WV_SERVER) {
    console.log('Requesting key from widevine server.');
    requestKey(e);
  }
  else {
    var initData = e.message;
    if (keySystem.indexOf('clearkey') != -1 && mediaType.indexOf('mp4') != -1)
      initData = initDataFromKeyId(); // Temporary hack for Clear Key in v0.1.
    e.target.webkitAddKey(keySystem, KEY, initData);
  }
}

var KEY = new Uint8Array([0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b,
                          0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c]);
// Key ID used for init data.
var keyID = "0123456789012345";
// Stores a failure message that is read by the browser test when it fails.
var failMessage = '';

function failTest(msg) {
  if (msg instanceof Event)
    failMessage = msg.target + '.' + msg.type;
  else
    failMessage = msg;
  console.log(failMessage);
}

<commit_msg>Delete requiredJavaScript.js<commit_after><|endoftext|>


<commit_before>import * as I from 'immutable';

import * as cosets      from '../fpgroups/cosets';
import * as delaney     from './delaney';
import * as properties  from './properties';
import * as delaney2d   from './delaney2d';
import * as delaney3d   from './delaney3d';
import * as fundamental from './fundamental';
import * as covers      from './covers';
import * as periodic    from '../pgraphs/periodic';

import * as util from '../common/util';

import { matrices } from '../arithmetic/types';
const ops = matrices;

let _timers = null;

export function useTimers(timers) {
  _timers = timers;
}

const _remainingIndices = (ds, i) => ds.indices().filter(j => j != i);

const _edgeTranslations = function _edgeTranslations(cov) {
  _timers && _timers.start('_edgeTranslations');

  _timers && _timers.start('_edgeTranslations: fundamental group');
  const fg  = fundamental.fundamentalGroup(cov);
  const n   = fg.nrGenerators;
  _timers && _timers.stop('_edgeTranslations: fundamental group');

  _timers && _timers.start('_edgeTranslations: relator null space');
  const nul = ops.nullSpace(cosets.relatorMatrix(n, fg.relators).toJS());
  _timers && _timers.stop('_edgeTranslations: relator null space');

  _timers && _timers.start('_edgeTranslations: assign translations to edges');
  const result = fg.edge2word.map(function(a) {
    return a.map(function(b) {
      const v = cosets.relatorAsVector(b, n).toJS();
      return ops.times(v, nul);
    });
  });
  _timers && _timers.stop('_edgeTranslations: assign translations to edges');

  _timers && _timers.stop('_edgeTranslations');

  return result;
};

const _cornerShifts = function _cornerShifts(cov, e2t) {
  const dim = delaney.dim(cov);
  const zero = ops.vector(dim);

  return I.Map().withMutations(function(m) {
    cov.indices().forEach(function(i) {
      const idcs = _remainingIndices(cov, i);

      properties.traversal(cov, idcs, cov.elements()).forEach(function(e) {
        const Dk = e[0];
        const k  = e[1];
        const D  = e[2];

        if (k == properties.traversal.root)
          m.setIn([D, i], zero);
        else
          m.setIn([D, i],
                  ops.minus(m.getIn([Dk, i]), e2t.getIn([Dk, k]) || zero));
      });
    });
  });
};

export const skeleton = cov => {
  useTimers(util.timers());

  _timers && _timers.start('skeleton');

  _timers && _timers.start('skeleton: edge translations');
  const e2t = _edgeTranslations(cov);
  _timers && _timers.stop('skeleton: edge translations');

  _timers && _timers.start('skeleton: corner shifts');
  const c2s = _cornerShifts(cov, e2t);
  _timers && _timers.stop('skeleton: corner shifts');

  _timers && _timers.start('skeleton: chamber2node');
  const chamber2node = {};
  let node = 1;
  for (const orb of properties.orbits(cov, _remainingIndices(cov, 0))) {
    for (const D of orb)
      chamber2node[D] = node;
    node += 1;
  }
  _timers && _timers.stop('skeleton: chamber2node');

  _timers && _timers.start('skeleton: edges');
  const zero = ops.vector(delaney.dim(cov));
  const edges = properties.orbitReps(cov, _remainingIndices(cov, 1))
    .map(function(D) {
      const E = cov.s(0, D);
      const v = chamber2node[D];
      const w = chamber2node[E];
      const t = e2t.getIn([D, 0]) || zero;
      const sD = c2s.getIn([D, 0]);
      const sE = c2s.getIn([E, 0]);
      const s = ops.minus(ops.plus(t, sE), sD);

      return [v, w, s];
    });
  _timers && _timers.stop('skeleton: edges');

  _timers && _timers.start('skeleton: make graph');
  const graph = periodic.make(edges);
  _timers && _timers.stop('skeleton: make graph');

  _timers && _timers.stop('skeleton');

  console.log(`Skeleton details:`);
  console.log(`${JSON.stringify(_timers.current(), null, 2)}`);

  return {
    graph,
    chamber2node: chamber2node,
    edgeTranslations: e2t.toJS(),
    cornerShifts: c2s.toJS()
  };
};

const chamberPositions = (cov, skel, pos) => {
  const dim = delaney.dim(cov);
  let result = {};

  cov.elements().forEach(function(D) {
    const p = pos[skel.chamber2node[D]];
    const t = skel.cornerShifts[D][0];
    result[D] = [ops.plus(p, t)];
  });

  I.Range(1, dim+1).forEach(function(i) {
    const idcs = I.Range(0, i);
    properties.orbits(cov, idcs, cov.elements()).forEach(function(orb) {
      let s = ops.vector(dim);
      orb.forEach(function(E) {
        const p = result[E][0];
        const t = skel.cornerShifts[E][i];
        s = ops.plus(s, ops.minus(p, t));
      });
      s = ops.times(ops.div(1, orb.size), s);
      orb.forEach(function(E) {
        const t = skel.cornerShifts[E][i];
        result[E].push(ops.plus(s, t));
      });
   });
  });

  return result;
};

const chamberBasis = (pos, D) => {
  const t = pos[D];
  return ops.cleanup(t.slice(1).map(v => ops.minus(v, t[0])));
};

export const symmetries = (ds, cov, pos) => {
  const D0 = cov.elements()
    .find(D => ops.ne(ops.determinant(chamberBasis(pos, D)), 0));
  const A = ops.inverse(chamberBasis(pos, D0));

  const phi = properties.morphism(cov, 1, ds, 1);
  const E0 = phi.get(D0);

  return I.List(cov.elements()).toJS()
    .filter(D => phi.get(D) == E0)
    .map(D => ops.times(A, chamberBasis(pos, D)));
};

export const makeCover = ds =>
  delaney.dim(ds) == 3 ?
  delaney3d.pseudoToroidalCover(ds) :
  delaney2d.toroidalCover(ds);

const interpolate = (f, v, w) => ops.plus(w, ops.times(f, ops.minus(v, w)));

const tileSurface3D = (corners, faces) => {
  const pos = corners.map(p => interpolate(0.8, p[0], p[3]));

  return { pos, faces };
};

const tileSurface2D = (corners, faces) => {
  const pos = I.List(corners).flatMap(p => [p[0].concat(0), p[0].concat(0.1)]);

  const f = faces[0].map(i => 2 * i);

  faces = [f, f.map(x => x + 1).reverse()]
    .concat(f.map((x, i) => {
      const y = f[(i + 1) % f.length];
      return [y, x, x + 1, y + 1];
    }));

  return { pos: pos.toJS(), faces };
};

const determinant = M => {
  if (M.length == 2)
    return M[0][0] * M[1][1] - M[0][1] * M[1][0];
  else if (M.length == 3)
    return (+ M[0][0] * M[1][1] * M[2][2]
            + M[0][1] * M[1][2] * M[2][0]
            + M[0][2] * M[1][0] * M[2][1]
            - M[0][2] * M[1][1] * M[2][0]
            - M[0][1] * M[1][0] * M[2][2]
            - M[0][0] * M[1][2] * M[2][1]);
  else
    return ops.determinant(ops.cleanup(M));
};

const adjustedOrientation = (cov, pos) => {
  const bas = D => chamberBasis(pos, D);
  const D0 = cov.elements().find(D => ops.ne(determinant(bas(D)), 0));
  const sgn = ops.sgn(determinant(bas(D0)));

  const ori = properties.partialOrientation(cov).toJS();
  if (sgn * ori[D0] < 0) {
    for (const D of cov.elements())
      ori[D] = -ori[D];
  }

  return ori;
};

const tileSurface = (cov, pos, ori, elms, idcs) => {
  const cOrbs = properties.orbits(cov, idcs.slice(1), elms);
  const cPos = cOrbs.map(orb => pos[orb.first()]);
  const cIdcs = I.Map(cOrbs.flatMap((orb, i) => orb.map(D => [D, i])));

  const faces = properties.orbits(cov, [0, 1], elms)
    .map(orb => ori[orb.first()] > 0 ? orb.reverse() : orb)
    .map(orb => orb.filter((D, i) => i % 2 == 0).map(D => cIdcs.get(D)));

  if (delaney.dim(cov) == 3)
    return tileSurface3D(cPos.toJS(), faces.toJS());
  else
    return tileSurface2D(cPos.toJS(), faces.toJS());
};

const affineSymmetry = (D0, D1, pos) => {
  const bas = D => chamberBasis(pos, D);
  const linear = ops.cleanup(ops.times(ops.inverse(bas(D0)), bas(D1)));
  const shift = ops.minus(pos[D1][0], ops.times(pos[D0][0], linear));

  return linear.map(r => r.concat(0)).concat([shift.concat([1])]);
};

export const tileSurfaces = (ds, cov, skel, vertexPos, basis) => {
  const dim = delaney.dim(cov);
  const chamberPos = chamberPositions(cov, skel, vertexPos);

  const pos = {};
  for (const D of cov.elements())
    pos[D] = chamberPos[D].map(p => ops.toJS(ops.times(p, basis)));

  const phi = properties.morphism(cov, 1, ds, 1);
  const bas = D => chamberBasis(pos, D);
  const ori = adjustedOrientation(cov, pos);
  const idcs = I.Range(0, delaney.dim(cov)).toArray();
  const tileOrbits = properties.orbits(cov, idcs).toArray();

  const templates = [];
  const tileOrbitReps = [];
  const dsChamberToTemplateIndex = {};
  const tiles = [];

  for (const elms of tileOrbits) {
    const D0 = elms.find(D => ops.ne(determinant(bas(D)), 0));
    const E0 = phi.get(D0);

    let templateIndex = dsChamberToTemplateIndex[E0];
    let symmetry = ops.identityMatrix(dim + 1);

    if (templateIndex == null) {
      templateIndex = templates.length;

      for (const E of properties.orbit(ds, idcs, E0))
        dsChamberToTemplateIndex[E] = templateIndex;

      templates.push(tileSurface(cov, pos, ori, elms, idcs));
      tileOrbitReps.push(D0);
    }
    else {
      const D0 = tileOrbitReps[templateIndex];
      const D1 = elms.find(D => phi.get(D) == phi.get(D0));
      symmetry = affineSymmetry(D0, D1, pos);
    }

    const center = pos[elms.first()][dim];
    tiles.push({ templateIndex, symmetry, center });
  }

  return { templates, tiles };
};
<commit_msg>get rid of black tiles<commit_after>import * as I from 'immutable';

import * as cosets      from '../fpgroups/cosets';
import * as delaney     from './delaney';
import * as properties  from './properties';
import * as derived     from './derived';
import * as delaney2d   from './delaney2d';
import * as delaney3d   from './delaney3d';
import * as fundamental from './fundamental';
import * as covers      from './covers';
import * as periodic    from '../pgraphs/periodic';

import * as util from '../common/util';

import { matrices } from '../arithmetic/types';
const ops = matrices;

let _timers = null;

export function useTimers(timers) {
  _timers = timers;
}

const _remainingIndices = (ds, i) => ds.indices().filter(j => j != i);

const _edgeTranslations = function _edgeTranslations(cov) {
  _timers && _timers.start('_edgeTranslations');

  _timers && _timers.start('_edgeTranslations: fundamental group');
  const fg  = fundamental.fundamentalGroup(cov);
  const n   = fg.nrGenerators;
  _timers && _timers.stop('_edgeTranslations: fundamental group');

  _timers && _timers.start('_edgeTranslations: relator null space');
  const nul = ops.nullSpace(cosets.relatorMatrix(n, fg.relators).toJS());
  _timers && _timers.stop('_edgeTranslations: relator null space');

  _timers && _timers.start('_edgeTranslations: assign translations to edges');
  const result = fg.edge2word.map(function(a) {
    return a.map(function(b) {
      const v = cosets.relatorAsVector(b, n).toJS();
      return ops.times(v, nul);
    });
  });
  _timers && _timers.stop('_edgeTranslations: assign translations to edges');

  _timers && _timers.stop('_edgeTranslations');

  return result;
};

const _cornerShifts = function _cornerShifts(cov, e2t) {
  const dim = delaney.dim(cov);
  const zero = ops.vector(dim);

  return I.Map().withMutations(function(m) {
    cov.indices().forEach(function(i) {
      const idcs = _remainingIndices(cov, i);

      properties.traversal(cov, idcs, cov.elements()).forEach(function(e) {
        const Dk = e[0];
        const k  = e[1];
        const D  = e[2];

        if (k == properties.traversal.root)
          m.setIn([D, i], zero);
        else
          m.setIn([D, i],
                  ops.minus(m.getIn([Dk, i]), e2t.getIn([Dk, k]) || zero));
      });
    });
  });
};

export const skeleton = cov => {
  useTimers(util.timers());

  _timers && _timers.start('skeleton');

  _timers && _timers.start('skeleton: edge translations');
  const e2t = _edgeTranslations(cov);
  _timers && _timers.stop('skeleton: edge translations');

  _timers && _timers.start('skeleton: corner shifts');
  const c2s = _cornerShifts(cov, e2t);
  _timers && _timers.stop('skeleton: corner shifts');

  _timers && _timers.start('skeleton: chamber2node');
  const chamber2node = {};
  let node = 1;
  for (const orb of properties.orbits(cov, _remainingIndices(cov, 0))) {
    for (const D of orb)
      chamber2node[D] = node;
    node += 1;
  }
  _timers && _timers.stop('skeleton: chamber2node');

  _timers && _timers.start('skeleton: edges');
  const zero = ops.vector(delaney.dim(cov));
  const edges = properties.orbitReps(cov, _remainingIndices(cov, 1))
    .map(function(D) {
      const E = cov.s(0, D);
      const v = chamber2node[D];
      const w = chamber2node[E];
      const t = e2t.getIn([D, 0]) || zero;
      const sD = c2s.getIn([D, 0]);
      const sE = c2s.getIn([E, 0]);
      const s = ops.minus(ops.plus(t, sE), sD);

      return [v, w, s];
    });
  _timers && _timers.stop('skeleton: edges');

  _timers && _timers.start('skeleton: make graph');
  const graph = periodic.make(edges);
  _timers && _timers.stop('skeleton: make graph');

  _timers && _timers.stop('skeleton');

  console.log(`Skeleton details:`);
  console.log(`${JSON.stringify(_timers.current(), null, 2)}`);

  return {
    graph,
    chamber2node: chamber2node,
    edgeTranslations: e2t.toJS(),
    cornerShifts: c2s.toJS()
  };
};

const chamberPositions = (cov, skel, pos, basis) => {
  const dim = delaney.dim(cov);
  let result = {};

  cov.elements().forEach(function(D) {
    const p = pos[skel.chamber2node[D]];
    const t = skel.cornerShifts[D][0];
    result[D] = [ops.plus(p, t)];
  });

  I.Range(1, dim+1).forEach(function(i) {
    const idcs = I.Range(0, i);
    properties.orbits(cov, idcs, cov.elements()).forEach(function(orb) {
      let s = ops.vector(dim);
      orb.forEach(function(E) {
        const p = result[E][0];
        const t = skel.cornerShifts[E][i];
        s = ops.plus(s, ops.minus(p, t));
      });
      s = ops.times(ops.div(1, orb.size), s);
      orb.forEach(function(E) {
        const t = skel.cornerShifts[E][i];
        result[E].push(ops.plus(s, t));
      });
   });
  });

  for (const D of cov.elements())
    result[D] = result[D].map(p => ops.toJS(ops.times(p, basis)));

  return result;
};

const chamberBasis = (pos, D) => {
  const t = pos[D];
  return ops.cleanup(t.slice(1).map(v => ops.minus(v, t[0])));
};

export const symmetries = (ds, cov, pos) => {
  const D0 = cov.elements()
    .find(D => ops.ne(ops.determinant(chamberBasis(pos, D)), 0));
  const A = ops.inverse(chamberBasis(pos, D0));

  const phi = properties.morphism(cov, 1, ds, 1);
  const E0 = phi.get(D0);

  return I.List(cov.elements()).toJS()
    .filter(D => phi.get(D) == E0)
    .map(D => ops.times(A, chamberBasis(pos, D)));
};

export const makeCover = ds =>
  delaney.dim(ds) == 3 ?
  delaney3d.pseudoToroidalCover(ds) :
  delaney2d.toroidalCover(ds);

const interpolate = (f, v, w) => ops.plus(w, ops.times(f, ops.minus(v, w)));

const tileSurface3D = (corners, faces) => {
  const pos = corners.map(p => interpolate(0.8, p[0], p[3]));

  return { pos, faces };
};

const tileSurface2D = (corners, faces) => {
  const pos = I.List(corners).flatMap(p => [p[0].concat(0), p[0].concat(0.1)]);

  const f = faces[0].map(i => 2 * i);

  faces = [f, f.map(x => x + 1).reverse()]
    .concat(f.map((x, i) => {
      const y = f[(i + 1) % f.length];
      return [y, x, x + 1, y + 1];
    }));

  return { pos: pos.toJS(), faces };
};

const determinant = M => {
  if (M.length == 2)
    return M[0][0] * M[1][1] - M[0][1] * M[1][0];
  else if (M.length == 3)
    return (+ M[0][0] * M[1][1] * M[2][2]
            + M[0][1] * M[1][2] * M[2][0]
            + M[0][2] * M[1][0] * M[2][1]
            - M[0][2] * M[1][1] * M[2][0]
            - M[0][1] * M[1][0] * M[2][2]
            - M[0][0] * M[1][2] * M[2][1]);
  else
    return ops.determinant(ops.cleanup(M));
};

const adjustedOrientation = (cov, pos) => {
  const bas = D => chamberBasis(pos, D);
  const D0 = cov.elements().find(D => ops.ne(determinant(bas(D)), 0));
  const sgn = ops.sgn(determinant(bas(D0)));

  const ori = properties.partialOrientation(cov).toJS();
  if (sgn * ori[D0] < 0) {
    for (const D of cov.elements())
      ori[D] = -ori[D];
  }

  return ori;
};

const tileSurface = (cov, pos, ori, elms, idcs) => {
  const cOrbs = properties.orbits(cov, idcs.slice(1), elms);
  const cPos = cOrbs.map(orb => pos[orb.first()]);
  const cIdcs = I.Map(cOrbs.flatMap((orb, i) => orb.map(D => [D, i])));

  const faces = properties.orbits(cov, [0, 1], elms)
    .map(orb => ori[orb.first()] > 0 ? orb.reverse() : orb)
    .map(orb => orb.filter((D, i) => i % 2 == 0).map(D => cIdcs.get(D)));

  if (delaney.dim(cov) == 3)
    return tileSurface3D(cPos.toJS(), faces.toJS());
  else
    return tileSurface2D(cPos.toJS(), faces.toJS());
};

const affineSymmetry = (D0, D1, pos) => {
  const bas = D => chamberBasis(pos, D);
  const linear = ops.cleanup(ops.times(ops.inverse(bas(D0)), bas(D1)));
  const shift = ops.minus(pos[D1][0], ops.times(pos[D0][0], linear));

  return linear.map(r => r.concat(0)).concat([shift.concat([1])]);
};

export const tileSurfaces = (ds, cov, skel, vertexPos, basis) => {
  const dim = delaney.dim(cov);
  const pos = chamberPositions(cov, skel, vertexPos, basis);
  const dso = derived.orientedCover(ds);
  const phi = properties.morphism(cov, 1, dso, 1);
  const bas = D => chamberBasis(pos, D);
  const ori = adjustedOrientation(cov, pos);
  const idcs = I.Range(0, dim).toArray();
  const tileOrbits = properties.orbits(cov, idcs).toArray();

  const templates = [];
  const tileOrbitReps = [];
  const dsChamberToTemplateIndex = {};
  const tiles = [];

  for (const elms of tileOrbits) {
    const D0 = elms.find(D => ops.ne(determinant(bas(D)), 0));
    const E0 = phi.get(D0);

    let templateIndex = dsChamberToTemplateIndex[E0];
    let symmetry = ops.identityMatrix(dim + 1);

    if (templateIndex == null) {
      templateIndex = templates.length;

      for (const E of properties.orbit(dso, idcs, E0))
        dsChamberToTemplateIndex[E] = templateIndex;

      templates.push(tileSurface(cov, pos, ori, elms, idcs));
      tileOrbitReps.push(D0);
    }
    else {
      const D0 = tileOrbitReps[templateIndex];
      const D1 = elms.find(D => phi.get(D) == phi.get(D0));
      symmetry = affineSymmetry(D0, D1, pos);
    }

    const center = pos[elms.first()][dim];
    tiles.push({ templateIndex, symmetry, center });
  }

  return { templates, tiles };
};
<|endoftext|>


<commit_before>// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.

/**
 * Custom auto-complete adapter to load users from the assignment list_participants webservice.
 *
 * @module     mod_assign/participants_selector
 * @copyright  2015 Damyon Wiese <damyon@moodle.com>
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */
define(['core/ajax', 'jquery', 'core/templates'], function(ajax, $, templates) {

    return /** @alias module:mod_assign/participants_selector */ {

        // Public variables and functions.
        /**
         * Process the results returned from transport (convert to value + label)
         *
         * @method processResults
         * @param {String} selector
         * @param {Array} data
         * @return {Array}
         */
        processResults: function(selector, data) {
            return data;
        },

        /**
         * Fetch results based on the current query. This also renders each result from a template before returning them.
         *
         * @method transport
         * @param {String} selector Selector for the original select element
         * @param {String} query Current search string
         * @param {Function} success Success handler
         * @param {Function} failure Failure handler
         */
        transport: function(selector, query, success, failure) {
            var assignmentid = $(selector).attr('data-assignmentid');
            var groupid = $(selector).attr('data-groupid');
            var filters = $('[data-region="configure-filters"] input[type="checkbox"]');
            var filterstrings = [];

            filters.each(function(index, element) {
                filterstrings[$(element).attr('name')] = $(element).prop('checked');
            });

            ajax.call([{
                methodname: 'mod_assign_list_participants',
                args: {assignid: assignmentid, groupid: groupid, filter: query, limit: 30, includeenrolments: false}
            }])[0].then(function(results) {
                var promises = [];
                var identityfields = $('[data-showuseridentity]').data('showuseridentity').split(',');

                // We got the results, now we loop over them and render each one from a template.
                $.each(results, function(index, user) {
                    var ctx = user,
                        identity = [],
                        show = true;

                    if (filterstrings.filter_submitted && !user.submitted) {
                        show = false;
                    }
                    if (filterstrings.filter_notsubmitted && user.submitted) {
                        show = false;
                    }
                    if (filterstrings.filter_requiregrading && !user.requiregrading) {
                        show = false;
                    }
                    if (filterstrings.filter_grantedextension && !user.grantedextension) {
                        show = false;
                    }
                    if (show) {
                        $.each(identityfields, function(i, k) {
                            if (typeof user[k] !== 'undefined' && user[k] !== '') {
                                ctx.hasidentity = true;
                                identity.push(user[k]);
                            }
                        });
                        ctx.identity = identity.join(', ');
                        promises.push(templates.render('mod_assign/list_participant_user_summary', ctx).then(function(html) {
                            return {value: user.id, label: html};
                        }));
                    }
                });
                // Do the dance for $.when()
                return $.when.apply($, promises);
            }).then(function() {
                var users = [];

                // Determine if we've been passed any arguments..
                if (arguments[0]) {
                    // Undo the $.when() dance from arguments object into an array..
                    users = Array.prototype.slice.call(arguments);
                }

                success(users);
            }).catch(failure);
        }
    };
});
<commit_msg>MDL-57139 assign: ensure promise best practices<commit_after>// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.

/**
 * Custom auto-complete adapter to load users from the assignment list_participants webservice.
 *
 * @module     mod_assign/participants_selector
 * @copyright  2015 Damyon Wiese <damyon@moodle.com>
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */
define(['core/ajax', 'jquery', 'core/templates'], function(ajax, $, templates) {

    return /** @alias module:mod_assign/participants_selector */ {

        // Public variables and functions.
        /**
         * Process the results returned from transport (convert to value + label)
         *
         * @method processResults
         * @param {String} selector
         * @param {Array} data
         * @return {Array}
         */
        processResults: function(selector, data) {
            return data;
        },

        /**
         * Fetch results based on the current query. This also renders each result from a template before returning them.
         *
         * @method transport
         * @param {String} selector Selector for the original select element
         * @param {String} query Current search string
         * @param {Function} success Success handler
         * @param {Function} failure Failure handler
         */
        transport: function(selector, query, success, failure) {
            var assignmentid = $(selector).attr('data-assignmentid');
            var groupid = $(selector).attr('data-groupid');
            var filters = $('[data-region="configure-filters"] input[type="checkbox"]');
            var filterstrings = [];

            filters.each(function(index, element) {
                filterstrings[$(element).attr('name')] = $(element).prop('checked');
            });

            ajax.call([{
                methodname: 'mod_assign_list_participants',
                args: {assignid: assignmentid, groupid: groupid, filter: query, limit: 30, includeenrolments: false}
            }])[0].then(function(results) {
                var promises = [];
                var identityfields = $('[data-showuseridentity]').data('showuseridentity').split(',');

                // We got the results, now we loop over them and render each one from a template.
                $.each(results, function(index, user) {
                    var ctx = user,
                        identity = [],
                        show = true;

                    if (filterstrings.filter_submitted && !user.submitted) {
                        show = false;
                    }
                    if (filterstrings.filter_notsubmitted && user.submitted) {
                        show = false;
                    }
                    if (filterstrings.filter_requiregrading && !user.requiregrading) {
                        show = false;
                    }
                    if (filterstrings.filter_grantedextension && !user.grantedextension) {
                        show = false;
                    }
                    if (show) {
                        $.each(identityfields, function(i, k) {
                            if (typeof user[k] !== 'undefined' && user[k] !== '') {
                                ctx.hasidentity = true;
                                identity.push(user[k]);
                            }
                        });
                        ctx.identity = identity.join(', ');
                        promises.push(templates.render('mod_assign/list_participant_user_summary', ctx).then(function(html) {
                            return {value: user.id, label: html};
                        }));
                    }
                });
                // Do the dance for $.when()
                return $.when.apply($, promises);
            }).then(function() {
                var users = [];

                // Determine if we've been passed any arguments..
                if (arguments[0]) {
                    // Undo the $.when() dance from arguments object into an array..
                    users = Array.prototype.slice.call(arguments);
                }

                success(users);
                return;
            }).catch(failure);
        }
    };
});
<|endoftext|>


<commit_before>import { atom, useAtom } from "jotai"
import { Box, Button, Dialog, Tooltip, Typography } from "@material-ui/core";
import { localBuildTime, localSha } from "../common/appVersion";
//import { useLogin } from "./Login";

const aboutAtom = atom(false)

export const useAbout = () => useAtom(aboutAtom)

export default function About() {
    const [show, setShow] = useAbout()
    //const [, setShowLogin] = useLogin()

    // const hasShown = localStorage.getItem('hasShownAbout')

    // if (!show && hasShown !== 'true') {
    //     console.log('Set timeout')

    //     setTimeout(() => {
    //         localStorage.setItem('hasShownAbout', 'true')
    //         setShow(true)
    //     }, 3000);
    // }

    // const enableCloudSync = () => {
    //     setShowLogin(true);
    // }

    return (
        <Dialog open={show} onClose={() => { setShow(false) }} >
            <Box style={{ width: 300, height: 180, padding: 20 }}>
                <Tooltip title={`version: ${localBuildTime} (${localSha.substring(0, 6)})`}>
                    <Typography variant="h5">About Dependitor</Typography>
                </Tooltip>
                <Typography >
                    A tool for modeling cloud architecture.
                </Typography>

                {/* <Typography style={{ paddingTop: 10 }} >
                    Checkout the  "<Link href="https://c4model.com" target="_blank">C4 Model</Link>"
                    by Simon Brown  to better understand on how to use the tool.
                </Typography>
                <Typography style={{ paddingTop: 10 }} >
                    You can sync diagrams between different devices if you login to <Link onClick={enableCloudSync}>enable cloud sync</Link>
                </Typography> */}
                {/* <Typography style={{ paddingTop: 30 }} variant="body2">
                    Hint: Use context menus to access functionality.
                </Typography> */}

                <Box style={{ position: 'absolute', bottom: 20, left: '40%', }}
                    textAlign='center'> <Button onClick={() => setShow(false)} variant="contained" color="primary">Close</Button>
                </Box>
            </Box>
        </Dialog>
    )
}<commit_msg>Dummy<commit_after>import { atom, useAtom } from "jotai"
import { Box, Button, Dialog, Tooltip, Typography } from "@material-ui/core";
import { localBuildTime, localSha } from "../common/appVersion";
//import { useLogin } from "./Login";

const aboutAtom = atom(false)

export const useAbout = () => useAtom(aboutAtom)

export default function About() {
    const [show, setShow] = useAbout()
    //const [, setShowLogin] = useLogin()

    // const hasShown = localStorage.getItem('hasShownAbout')

    // if (!show && hasShown !== 'true') {
    //     console.log('Set timeout')

    //     setTimeout(() => {
    //         localStorage.setItem('hasShownAbout', 'true')
    //         setShow(true)
    //     }, 3000);
    // }//

    // const enableCloudSync = () => {
    //     setShowLogin(true);
    // }

    return (
        <Dialog open={show} onClose={() => { setShow(false) }} >
            <Box style={{ width: 300, height: 180, padding: 20 }}>
                <Tooltip title={`version: ${localBuildTime} (${localSha.substring(0, 6)})`}>
                    <Typography variant="h5">About Dependitor</Typography>
                </Tooltip>
                <Typography >
                    A tool for modeling cloud architecture.
                </Typography>

                {/* <Typography style={{ paddingTop: 10 }} >
                    Checkout the  "<Link href="https://c4model.com" target="_blank">C4 Model</Link>"
                    by Simon Brown  to better understand on how to use the tool.
                </Typography>
                <Typography style={{ paddingTop: 10 }} >
                    You can sync diagrams between different devices if you login to <Link onClick={enableCloudSync}>enable cloud sync</Link>
                </Typography> */}
                {/* <Typography style={{ paddingTop: 30 }} variant="body2">
                    Hint: Use context menus to access functionality.
                </Typography> */}

                <Box style={{ position: 'absolute', bottom: 20, left: '40%', }}
                    textAlign='center'> <Button onClick={() => setShow(false)} variant="contained" color="primary">Close</Button>
                </Box>
            </Box>
        </Dialog>
    )
}<|endoftext|>


<commit_before>var Appointment = require('../models/appointment');
var Doctor = require('../models/doctor');
var Patient = require('../models/patient');
var User = require('../models/user');

function AppointmentController() {

}

AppointmentController.prototype.insert = function (_doctorId, body, callback) {
    Doctor.find({_id : _doctorId},function (error, doctor) {
        if (error) {
            callback(error)
        } else {
            if (doctor.length === 0) {
                callback({error: 'Médico não existe'})
            }else{
                var appointment = new Appointment();
                appointment.doctorId = _doctorId;
                appointment.patientId = body.patientId;
                appointment.availabilityId = body.availabilityId;
                appointment.date = body.date;
                appointment.save(function(err, result){
                    if(err){
                        callback(err);
                    }else{
                        callback({success: 'true'})
                    }
                })

            }
        }
    })
}

AppointmentController.prototype.getDoctors = function(_doctorId, callback) {
    Doctor.find({_id : _doctorId},function (error, doctors) {
        if (error) {
            callback(error)
        } else {
            if (doctors.length === 0) {
                callback({error: "Médico não existe."});
            } else {
                Appointment.find({ doctorId : _doctorId}).populate('availabilityId').populate('patientId').exec(function (error, availability ) {
                    if (error) {
                        callback(error);
                    } else {
                        var availabilities = [];

                        if (availability.length > 0) {
                            load(0);

                            function load (i) {
                                User.find({ _id: availability[i].patientId }, function (error, user) {
                                    var av = {
                                        "_id": availability[i]._id,
                                        "date": availability[i].date,
                                        "availabilityId": availability[i].availabilityId,
                                        "patientId": availability[i].patientId._id,
                                        "profileImage": availability[i].patientId.profileImage,
                                        "doctorId": availability[i].doctorId,
                                        "user": user[0]
                                    };

                                    availabilities.push(av);
                                    if (i + i < availability.length)
                                        load(i + 1);
                                    else
                                        callback(availabilities);
                                });
                            }
                        }
                    }
                });
            }
        }
    })
};

AppointmentController.prototype.getPatients = function(_patientId, callback) {
    Patient.find({_id : _patientId},function (error, doctors) {
        if (error) {
            callback(error)
        } else {
            if (doctors.length === 0) {
                callback({error: "Paciente não existe."});
            } else {
                Appointment.find({ patientId : _patientId }).populate('availabilityId').populate('doctorId').exec(function (error, availability ) {
                    if (error) {
                        callback(error);
                    } else {
                        var availabilities = [];

                        if (availability.length > 0) {
                            load(0);

                            function load (i) {
                                User.find({ _id: availability[i].doctorId }, function (error, user) {
                                    var av = {
                                        "_id": availability[i]._id,
                                        "date": availability[i].date,
                                        "availabilityId": availability[i].availabilityId,
                                        "patientId": availability[i].patientId._id,
                                        "profileImage": availability[i].doctorId.profileImage,
                                        "doctorId": availability[i].doctorId,
                                        "user": user[0]
                                    };

                                    availabilities.push(av);
                                    if (i + i < availability.length)
                                        load(i + 1);
                                    else
                                        callback(availabilities);
                                });
                            }
                        }
                    }
                });
            }
        }
    })
};

AppointmentController.prototype.remove = function(_id,callback) {
    Appointment.remove({ _id: _id }, function (err) {
        if (err) {
            callback(err)
        } else {
            callback({success: 'true'})
        }
    })
}

module.exports = AppointmentController;

<commit_msg>Appointments<commit_after>    var Appointment = require('../models/appointment');
var Doctor = require('../models/doctor');
var Patient = require('../models/patient');
var User = require('../models/user');

function AppointmentController() {

}

AppointmentController.prototype.insert = function (_doctorId, body, callback) {
    Doctor.find({_id : _doctorId},function (error, doctor) {
        if (error) {
            callback(error)
        } else {
            if (doctor.length === 0) {
                callback({error: 'Médico não existe'})
            }else{
                var appointment = new Appointment();
                appointment.doctorId = _doctorId;
                appointment.patientId = body.patientId;
                appointment.availabilityId = body.availabilityId;
                appointment.date = body.date;
                appointment.save(function(err, result){
                    if(err){
                        callback(err);
                    }else{
                        callback({success: 'true'})
                    }
                })

            }
        }
    })
}

AppointmentController.prototype.getDoctors = function(_doctorId, callback) {
    Doctor.find({_id : _doctorId},function (error, doctors) {
        if (error) {
            callback(error)
        } else {
            if (doctors.length === 0) {
                callback({error: "Médico não existe."});
            } else {
                Appointment.find({ doctorId : _doctorId}).populate('availabilityId').populate('patientId').exec(function (error, availability ) {
                    if (error) {
                        callback(error);
                    } else {
                        var availabilities = [];

                        if (availability.length > 0) {
                            load(0);

                            function load (i) {
                                User.find({ _id: availability[i].patientId }, function (error, user) {
                                    var av = {
                                        "_id": availability[i]._id,
                                        "date": availability[i].date,
                                        "availabilityId": availability[i].availabilityId,
                                        "patientId": availability[i].patientId._id,
                                        "profileImage": availability[i].patientId.profileImage,
                                        "doctorId": availability[i].doctorId,
                                        "user": user[0]
                                    };

                                    availabilities.push(av);
                                    if (i + i < availability.length)
                                        load(i + 1);
                                    else
                                        callback(availabilities);
                                });
                            }
                        } else {
                            callback([]);
                        }
                    }
                });
            }
        }
    })
};

AppointmentController.prototype.getPatients = function(_patientId, callback) {
    Patient.find({_id : _patientId},function (error, doctors) {
        if (error) {
            callback(error)
        } else {
            if (doctors.length === 0) {
                callback({error: "Paciente não existe."});
            } else {
                Appointment.find({ patientId : _patientId }).populate('availabilityId').populate('doctorId').exec(function (error, availability ) {
                    if (error) {
                        callback(error);
                    } else {
                        var availabilities = [];

                        if (availability.length > 0) {
                            load(0);

                            function load (i) {
                                User.find({ _id: availability[i].doctorId }, function (error, user) {
                                    var av = {
                                        "_id": availability[i]._id,
                                        "date": availability[i].date,
                                        "availabilityId": availability[i].availabilityId,
                                        "patientId": availability[i].patientId._id,
                                        "profileImage": availability[i].doctorId.profileImage,
                                        "doctorId": availability[i].doctorId,
                                        "user": user[0]
                                    };

                                    availabilities.push(av);
                                    if (i + i < availability.length)
                                        load(i + 1);
                                    else
                                        callback(availabilities);
                                });
                            }
                        } else {
                            callback([]);
                        }
                    }
                });
            }
        }
    })
};

AppointmentController.prototype.remove = function(_id,callback) {
    Appointment.remove({ _id: _id }, function (err) {
        if (err) {
            callback(err)
        } else {
            callback({success: 'true'})
        }
    })
}

module.exports = AppointmentController;

<|endoftext|>


<commit_before>// TODO / FIXME : this needs unit tests!!!

module.exports = {
    injector: require('./injector'),
    structured: require('./structured'),
    clientBuilder: require('./clientBuilder'),
    logger : require('./logger'),

    injectDataFirst: function initResponses(injectables, responses, wrap, hook) {
        const isWrapped = (typeof wrap === 'function');
        const loggerExists = typeof injectables.logger === 'function';

        let createResponseFunc = function (responseName, responseCode) {
            return (data) => {//it is assumed that responses have 1 external parameter from the user (function)
                let LOG;

                if (loggerExists) {
                    LOG = new injectables.logger(responseName, hook);
                }
                this.injector(Object.assign({data: data}, injectables, {
                    LOG: LOG,
                    console: LOG
                }), responseCode);
            };
        };

        return Object.keys(responses).reduce((acc, responseName) => {
            // Support of Response object as a group of responses (so you can include a library of responses with 1 require file
            if(typeof responses[responseName] === 'object' && responses[responseName] !== null) {
                Object.keys(responses[responseName]).forEach((subResponseName) => {
                    let response = createResponseFunc(subResponseName, responses[responseName][subResponseName]);
                    acc[subResponseName] = isWrapped ? wrap(response) : response;
                });
            }
            else {
                let response = createResponseFunc(responseName, responses[responseName]);

                acc[responseName] = isWrapped ? wrap(response) : response;
            }

            return acc;
        }, {});
    },

    /**
     * Injects a bunch of things one after each other injecting all previous siblings
     * returns last one in
     * @param initialInjectables
     * @param injectees
     * @param wrap
     *
     * @returns {*}
     */
    aggregateInjector: function aggregateInjector(initialInjectables, injectees, wrap, hook) {
        let injectables = initialInjectables;

        let last = {};
        injectees.forEach((injectee) => {
            last = this.injector(injectables, injectee, wrap, hook);
            injectables = Object.assign(injectables, last);
        });

        return last;
    },

    generatorReadyData: function generatorReadyData(inputServices) {
        return Object.keys(inputServices).reduce((services, serviceName) => {
            services[serviceName] = Object.keys(inputServices[serviceName]).reduce((service, funcName) => {
                if (['restClient', 'init', 'interpolate', 'debug', 'initialized', 'fncVarReplacements', 'setLogger', '_log'].indexOf(funcName) === -1) {
                    service[funcName] = inputServices[serviceName][funcName];
                }
                return service;
            }, {});
            return services;
        }, {});
    },

    /**
     * this function overrides real DataServiceClients with mocks if mock context exists,
     * it will only preserve the real service if it has a overrideable false flag
     *
     * @param useableDataServices
     * @param mockContext
     * @returns {*}
     */
    runtimeMockDataServices: function runtimeMockDataServices(useableDataServices, mockContext) {
        if (typeof useableDataServices !== 'object') {
            return {};
        }

        if (typeof mockContext !== 'object') {
            return useableDataServices;
        }

        Object.keys(useableDataServices).forEach((serviceName) => {
            if (typeof useableDataServices[serviceName].overrideable !== 'boolean' || useableDataServices[serviceName].overrideable) {
                useableDataServices[serviceName] = this.structured.toImplentation(mockContext[serviceName]);
                // useableDataServices[serviceName] = injectableDataServices[serviceName];
            }
        });

        return useableDataServices;
    },

    /**
     * Workers are agnostic of lambda endpoints as well as DataServices/Hooks and all other injectables
     * workers are injected with a logger, env, tracer, meter, i18n libraries
     */
    setupWorkers: function setupWorkers(workers, injectables) {
        const DEFAULT_WORKER_INTERVAL = 60 * 1000;//every minute

        let workerInstances = {};
        if (typeof workers === 'object') {
            Object.keys(workers).forEach(worker => {
                if (typeof workers[worker] === 'function') {
                    workerInstances[worker] = setInterval( () => {
                        this.injector(injectables, workers[worker]);
                    }, worker.interval || DEFAULT_WORKER_INTERVAL);
                }
            });
        }
        return workerInstances;
    },

    /**
     * if an injectable by a name is missing prepopulate it with an empty object
     * @param app
     * @param names
     * @param defaults
     * @param warn
     */
    fillEmpty: function fixInjectable(app, names, defaults, warn) {
        names.forEach((name) => {
            if (typeof app[name] !== 'object') {
                app[name] = {};
                if(typeof warn === 'function'){
                    warn(name);
                }
            }
            //TODO : this could also in the future add some default Responses/Hooks/Policies/etc
            app[name] = Object.assign(app[name], defaults);
        });
    },

    /**
     * This function initializes DataService Clients
     * @param nonInjectableServices
     * @param activeEnvironment
     * @returns {*}
     */
    clientBuild: function calculateInjectableDataServices(nonInjectableServices, activeEnvironment, loggerHooks) {
        if(loggerHooks === null || typeof loggerHooks !== 'object') {
            loggerHooks = {};
        }

        const internalLogger = new this.logger('interceptor-utils', { level : activeEnvironment.logLevel || 'crucial' });

        const elementIsObject = dataServiceArrayElement => (dataServiceArrayElement !== null) && (typeof dataServiceArrayElement === 'object') && (Object.keys(dataServiceArrayElement).length === 1);

        const configurableDataServices = Object.keys(activeEnvironment);

        if (typeof nonInjectableServices === 'object') {
                return Object.keys(nonInjectableServices).reduce((acc, v) => {

                    const serviceExistsInEnvironmentConfig = (activeEnvironment[v] !== null && typeof activeEnvironment[v] === 'object');
                    const serviceIsANonNullObject = (nonInjectableServices[v] !== null && typeof nonInjectableServices[v] === 'object');
                    const serviceIsANonNullFunction = (nonInjectableServices[v] !== null && typeof nonInjectableServices[v] === 'function');

                    const serviceIsLikelyAnArupexClient = serviceIsANonNullObject && Array.isArray(nonInjectableServices[v]) && nonInjectableServices[v].some(elementIsObject);

                    internalLogger.debug(`configuring ${v}: serviceExistsInEnvironmentConfig=${serviceExistsInEnvironmentConfig} | serviceIsANonNullObject=${serviceIsANonNullObject} | serviceIsANonNullFunction=${serviceIsANonNullFunction} | serviceIsLikelyAnArupexClient=${serviceIsLikelyAnArupexClient} ...`);

                    if(serviceExistsInEnvironmentConfig &&
                        serviceIsANonNullObject &&
                        serviceIsLikelyAnArupexClient ) {
                        let activeLoggerHook = Object.assign({}, loggerHooks);
                        if(activeEnvironment[v].logLevel){
                            activeLoggerHook.level = activeEnvironment[v].logLevel;
                        }
                        internalLogger.debug(`${v} is being initalized as an arupex client...`);
                        activeEnvironment[v].logger = new this.logger(v, activeLoggerHook).info;//has to be a function for hyper-request to work
                        acc[v] = this.clientBuilder(nonInjectableServices[v]).init(activeEnvironment[v]);
                    }
                    else {
                        if(!serviceExistsInEnvironmentConfig) {
                            internalLogger.warn(`only the following are considered configurable dataservices`, configurableDataServices);
                        }

                        if(!serviceExistsInEnvironmentConfig && serviceIsLikelyAnArupexClient) {
                            internalLogger.critical(`${v} appears to be an arupex client! however it appears to have no environment configuration, so it will be treated as an Array or objects and not initialized...`);
                        }
                        else {

                            if(!serviceExistsInEnvironmentConfig) {
                                internalLogger.warn(`environment did not include config for ${v} skipping as client, may be misconfigured...included as raw object`);
                            }

                            if(!serviceIsANonNullObject && !serviceIsANonNullFunction) {
                                internalLogger.critical(`${v} was non object-function/not null...`);
                            }

                            if(!serviceIsLikelyAnArupexClient) {
                                internalLogger.warn(`${v} does appears to not be an arupex client`);
                            }
                        }

                        acc[v] = nonInjectableServices[v];//not a client
                    }

                    return acc;
                }, {});
        }
        return {};
    }

};<commit_msg>arrow so this stays put<commit_after>// TODO / FIXME : this needs unit tests!!!

module.exports = {
    injector: require('./injector'),
    structured: require('./structured'),
    clientBuilder: require('./clientBuilder'),
    logger : require('./logger'),

    injectDataFirst: function initResponses(injectables, responses, wrap, hook) {
        const isWrapped = (typeof wrap === 'function');
        const loggerExists = typeof injectables.logger === 'function';

        let createResponseFunc = (responseName, responseCode) => {
            return (data) => {//it is assumed that responses have 1 external parameter from the user (function)
                let LOG;

                if (loggerExists) {
                    LOG = new injectables.logger(responseName, hook);
                }
                this.injector(Object.assign({data: data}, injectables, {
                    LOG: LOG,
                    console: LOG
                }), responseCode);
            };
        };

        return Object.keys(responses).reduce((acc, responseName) => {
            // Support of Response object as a group of responses (so you can include a library of responses with 1 require file
            if(typeof responses[responseName] === 'object' && responses[responseName] !== null) {
                Object.keys(responses[responseName]).forEach((subResponseName) => {
                    let response = createResponseFunc(subResponseName, responses[responseName][subResponseName]);
                    acc[subResponseName] = isWrapped ? wrap(response) : response;
                });
            }
            else {
                let response = createResponseFunc(responseName, responses[responseName]);

                acc[responseName] = isWrapped ? wrap(response) : response;
            }

            return acc;
        }, {});
    },

    /**
     * Injects a bunch of things one after each other injecting all previous siblings
     * returns last one in
     * @param initialInjectables
     * @param injectees
     * @param wrap
     *
     * @returns {*}
     */
    aggregateInjector: function aggregateInjector(initialInjectables, injectees, wrap, hook) {
        let injectables = initialInjectables;

        let last = {};
        injectees.forEach((injectee) => {
            last = this.injector(injectables, injectee, wrap, hook);
            injectables = Object.assign(injectables, last);
        });

        return last;
    },

    generatorReadyData: function generatorReadyData(inputServices) {
        return Object.keys(inputServices).reduce((services, serviceName) => {
            services[serviceName] = Object.keys(inputServices[serviceName]).reduce((service, funcName) => {
                if (['restClient', 'init', 'interpolate', 'debug', 'initialized', 'fncVarReplacements', 'setLogger', '_log'].indexOf(funcName) === -1) {
                    service[funcName] = inputServices[serviceName][funcName];
                }
                return service;
            }, {});
            return services;
        }, {});
    },

    /**
     * this function overrides real DataServiceClients with mocks if mock context exists,
     * it will only preserve the real service if it has a overrideable false flag
     *
     * @param useableDataServices
     * @param mockContext
     * @returns {*}
     */
    runtimeMockDataServices: function runtimeMockDataServices(useableDataServices, mockContext) {
        if (typeof useableDataServices !== 'object') {
            return {};
        }

        if (typeof mockContext !== 'object') {
            return useableDataServices;
        }

        Object.keys(useableDataServices).forEach((serviceName) => {
            if (typeof useableDataServices[serviceName].overrideable !== 'boolean' || useableDataServices[serviceName].overrideable) {
                useableDataServices[serviceName] = this.structured.toImplentation(mockContext[serviceName]);
                // useableDataServices[serviceName] = injectableDataServices[serviceName];
            }
        });

        return useableDataServices;
    },

    /**
     * Workers are agnostic of lambda endpoints as well as DataServices/Hooks and all other injectables
     * workers are injected with a logger, env, tracer, meter, i18n libraries
     */
    setupWorkers: function setupWorkers(workers, injectables) {
        const DEFAULT_WORKER_INTERVAL = 60 * 1000;//every minute

        let workerInstances = {};
        if (typeof workers === 'object') {
            Object.keys(workers).forEach(worker => {
                if (typeof workers[worker] === 'function') {
                    workerInstances[worker] = setInterval( () => {
                        this.injector(injectables, workers[worker]);
                    }, worker.interval || DEFAULT_WORKER_INTERVAL);
                }
            });
        }
        return workerInstances;
    },

    /**
     * if an injectable by a name is missing prepopulate it with an empty object
     * @param app
     * @param names
     * @param defaults
     * @param warn
     */
    fillEmpty: function fixInjectable(app, names, defaults, warn) {
        names.forEach((name) => {
            if (typeof app[name] !== 'object') {
                app[name] = {};
                if(typeof warn === 'function'){
                    warn(name);
                }
            }
            //TODO : this could also in the future add some default Responses/Hooks/Policies/etc
            app[name] = Object.assign(app[name], defaults);
        });
    },

    /**
     * This function initializes DataService Clients
     * @param nonInjectableServices
     * @param activeEnvironment
     * @returns {*}
     */
    clientBuild: function calculateInjectableDataServices(nonInjectableServices, activeEnvironment, loggerHooks) {
        if(loggerHooks === null || typeof loggerHooks !== 'object') {
            loggerHooks = {};
        }

        const internalLogger = new this.logger('interceptor-utils', { level : activeEnvironment.logLevel || 'crucial' });

        const elementIsObject = dataServiceArrayElement => (dataServiceArrayElement !== null) && (typeof dataServiceArrayElement === 'object') && (Object.keys(dataServiceArrayElement).length === 1);

        const configurableDataServices = Object.keys(activeEnvironment);

        if (typeof nonInjectableServices === 'object') {
                return Object.keys(nonInjectableServices).reduce((acc, v) => {

                    const serviceExistsInEnvironmentConfig = (activeEnvironment[v] !== null && typeof activeEnvironment[v] === 'object');
                    const serviceIsANonNullObject = (nonInjectableServices[v] !== null && typeof nonInjectableServices[v] === 'object');
                    const serviceIsANonNullFunction = (nonInjectableServices[v] !== null && typeof nonInjectableServices[v] === 'function');

                    const serviceIsLikelyAnArupexClient = serviceIsANonNullObject && Array.isArray(nonInjectableServices[v]) && nonInjectableServices[v].some(elementIsObject);

                    internalLogger.debug(`configuring ${v}: serviceExistsInEnvironmentConfig=${serviceExistsInEnvironmentConfig} | serviceIsANonNullObject=${serviceIsANonNullObject} | serviceIsANonNullFunction=${serviceIsANonNullFunction} | serviceIsLikelyAnArupexClient=${serviceIsLikelyAnArupexClient} ...`);

                    if(serviceExistsInEnvironmentConfig &&
                        serviceIsANonNullObject &&
                        serviceIsLikelyAnArupexClient ) {
                        let activeLoggerHook = Object.assign({}, loggerHooks);
                        if(activeEnvironment[v].logLevel){
                            activeLoggerHook.level = activeEnvironment[v].logLevel;
                        }
                        internalLogger.debug(`${v} is being initalized as an arupex client...`);
                        activeEnvironment[v].logger = new this.logger(v, activeLoggerHook).info;//has to be a function for hyper-request to work
                        acc[v] = this.clientBuilder(nonInjectableServices[v]).init(activeEnvironment[v]);
                    }
                    else {
                        if(!serviceExistsInEnvironmentConfig) {
                            internalLogger.warn(`only the following are considered configurable dataservices`, configurableDataServices);
                        }

                        if(!serviceExistsInEnvironmentConfig && serviceIsLikelyAnArupexClient) {
                            internalLogger.critical(`${v} appears to be an arupex client! however it appears to have no environment configuration, so it will be treated as an Array or objects and not initialized...`);
                        }
                        else {

                            if(!serviceExistsInEnvironmentConfig) {
                                internalLogger.warn(`environment did not include config for ${v} skipping as client, may be misconfigured...included as raw object`);
                            }

                            if(!serviceIsANonNullObject && !serviceIsANonNullFunction) {
                                internalLogger.critical(`${v} was non object-function/not null...`);
                            }

                            if(!serviceIsLikelyAnArupexClient) {
                                internalLogger.warn(`${v} does appears to not be an arupex client`);
                            }
                        }

                        acc[v] = nonInjectableServices[v];//not a client
                    }

                    return acc;
                }, {});
        }
        return {};
    }

};<|endoftext|>


<commit_before>/* global*/
import config from './index.config';

import routerConfig from './index.route';

import runBlock from './index.run';
import HomeController from './home/home.controller';
import PortfolioIndexService from './home/portfolio-index.service';

angular.module('lazarus', ['ngAnimate', 'ngCookies', 'ngTouch', 'ngSanitize', 'ngResource', 'ui.router'])
  .run(['$rootScope', '$location', '$window', function($rootScope, $location, $window){
    $rootScope
      .$on('$stateChangeSuccess',
        function(event){
          if (!$window.ga)
              return;

          $window.ga('send', 'pageview', { page: $location.path() });
      });
  }])
  // General config
  .config(config)

  // Routing
  .config(routerConfig)

  .service('PortfolioIndex', PortfolioIndexService)
  .run(runBlock)
  .controller('HomeController', HomeController);
<commit_msg>Comment out Analytics ui-router code<commit_after>/* global*/
import config from './index.config';

import routerConfig from './index.route';

import runBlock from './index.run';
import HomeController from './home/home.controller';
import PortfolioIndexService from './home/portfolio-index.service';

angular.module('lazarus', ['ngAnimate', 'ngCookies', 'ngTouch', 'ngSanitize', 'ngResource', 'ui.router'])
  // .run(['$rootScope', '$location', '$window', function($rootScope, $location, $window){
  //   $rootScope
  //     .$on('$stateChangeSuccess',
  //       function(event){
  //         if (!$window.ga)
  //             return;
  //
  //         $window.ga('send', 'pageview', { page: $location.path() });
  //     });
  // }])
  // General config
  .config(config)

  // Routing
  .config(routerConfig)

  .service('PortfolioIndex', PortfolioIndexService)
  .run(runBlock)
  .controller('HomeController', HomeController);
<|endoftext|>