<commit_before>var Botkit = require(__dirname + '/CoreBot.js');
var request = require('request');
var express = require('express');
var bodyParser = require('body-parser');

function Facebookbot(configuration) {

    // Create a core botkit bot
    var facebook_botkit = Botkit(configuration || {});

    if (facebook_botkit.config.require_delivery) {

        facebook_botkit.on('message_delivered', function(bot, message) {

            // get list of mids in this message
            for (var m = 0; m < message.delivery.mids.length; m++) {
                var mid = message.delivery.mids[m];

                // loop through all active conversations this bot is having
                // and mark messages in conversations as delivered = true
                bot.findConversation(message, function(convo) {
                    if (convo) {
                        for (var s = 0; s < convo.sent.length; s++) {
                            if (convo.sent[s].sent_timestamp <= message.delivery.watermark ||
                                (convo.sent[s].api_response && convo.sent[s].api_response.mid == mid)) {
                                convo.sent[s].delivered = true;
                            }
                        }
                    }
                });
            }

        });

    }

    // customize the bot definition, which will be used when new connections
    // spawn!
    facebook_botkit.defineBot(function(botkit, config) {

        var bot = {
            type: 'fb',
            botkit: botkit,
            config: config || {},
            utterances: botkit.utterances,
        };

        bot.startConversation = function(message, cb) {
            botkit.startConversation(this, message, cb);
        };

        bot.createConversation = function(message, cb) {
            botkit.createConversation(this, message, cb);
        };

        bot.send = function(message, cb) {

            var facebook_message = {
                recipient: {},
                message: message.sender_action ? undefined : {}
            };

            if (typeof(message.channel) == 'string' && message.channel.match(/\+\d+\(\d\d\d\)\d\d\d\-\d\d\d\d/)) {
                facebook_message.recipient.phone_number = message.channel;
            } else {
                facebook_message.recipient.id = message.channel;
            }

            if (!message.sender_action) {
                if (message.text) {
                    facebook_message.message.text = message.text;
                }

                if (message.attachment) {
                    facebook_message.message.attachment = message.attachment;
                }

                if (message.sticker_id) {
                    facebook_message.message.sticker_id = message.sticker_id;
                }

                if (message.quick_replies) {

                    // sanitize the length of the title to maximum of 20 chars
                    var titleLimit = function(title) {
                        if (title.length > 20) {
                            var newTitle = title.substring(0, 16) + '...';
                            return newTitle;
                        } else {
                            return title;
                        }
                    };

                    facebook_message.message.quick_replies = message.quick_replies.map(function(item) {
                        return {
                            content_type: item.content_type || 'text',
                            title: titleLimit(item.title),
                            payload: item.payload,
                            image_url: item.image_url,
                        };
                    });
                }
            } else {
                facebook_message.sender_action = message.sender_action;
            }

            if (message.sender_action) {
                facebook_message.sender_action = message.sender_action;
            }

            if (message.notification_type) {
                facebook_message.notification_type = message.notification_type;
            }

            //Add Access Token to outgoing request
            facebook_message.access_token = configuration.access_token;

            request({
                method: 'POST',
                json: true,
                headers: {
                    'content-type': 'application/json',
                },
                body: facebook_message,
                uri: 'https://graph.facebook.com/v2.6/me/messages'
            },
                function(err, res, body) {

                    if (err) {
                        botkit.debug('WEBHOOK ERROR', err);
                        return cb && cb(err);
                    }

                    if (body.error) {
                        botkit.debug('API ERROR', body.error);
                        return cb && cb(body.error.message);
                    }

                    botkit.debug('WEBHOOK SUCCESS', body);
                    cb && cb(null, body);
                });
        };

        bot.startTyping = function(src, cb) {
            var msg = {};
            msg.channel = src.channel;
            msg.sender_action = 'typing_on';
            bot.say(msg, cb);
        };

        bot.stopTyping = function(src, cb) {
            var msg = {};
            msg.channel = src.channel;
            msg.sender_action = 'typing_off';
            bot.say(msg, cb);
        };

        bot.replyWithTyping = function(src, resp, cb) {
            var text;

            if (typeof(resp) == 'string') {
                text = resp;
            } else {
                text = resp.text;
            }

            var avgWPM = 85;
            var avgCPM = avgWPM * 7;

            var typingLength = Math.min(Math.floor(text.length / (avgCPM / 60)) * 1000, 5000);

            bot.startTyping(src, function(err) {
                if (err) console.log(err);
                setTimeout(function() {
                    bot.reply(src, resp, cb);
                }, typingLength);
            });

        };

        bot.reply = function(src, resp, cb) {
            var msg = {};

            if (typeof(resp) == 'string') {
                msg.text = resp;
            } else {
                msg = resp;
            }

            msg.channel = src.channel;

            bot.say(msg, cb);
        };

        bot.findConversation = function(message, cb) {
            botkit.debug('CUSTOM FIND CONVO', message.user, message.channel);
            for (var t = 0; t < botkit.tasks.length; t++) {
                for (var c = 0; c < botkit.tasks[t].convos.length; c++) {
                    if (
                        botkit.tasks[t].convos[c].isActive() &&
                        botkit.tasks[t].convos[c].source_message.user == message.user
                    ) {
                        botkit.debug('FOUND EXISTING CONVO!');
                        cb(botkit.tasks[t].convos[c]);
                        return;
                    }
                }
            }

            cb();
        };

        return bot;
    });

    // set up a web route for receiving outgoing webhooks and/or slash commands

    facebook_botkit.createWebhookEndpoints = function(webserver, bot, cb) {

        facebook_botkit.log(
            '** Serving webhook endpoints for Messenger Platform at: ' +
            'http://' + facebook_botkit.config.hostname + ':' + facebook_botkit.config.port + '/facebook/receive');
        webserver.post('/facebook/receive', function(req, res) {

            facebook_botkit.debug('GOT A MESSAGE HOOK');
            var obj = req.body;
            if (obj.entry) {
                for (var e = 0; e < obj.entry.length; e++) {
                    for (var m = 0; m < obj.entry[e].messaging.length; m++) {
                        var facebook_message = obj.entry[e].messaging[m];
                        if (facebook_message.message) {
                            var message = {
                                text: facebook_message.message.text,
                                user: facebook_message.sender.id,
                                channel: facebook_message.sender.id,
                                timestamp: facebook_message.timestamp,
                                seq: facebook_message.message.seq,
                                is_echo: facebook_message.message.is_echo,
                                mid: facebook_message.message.mid,
                                sticker_id: facebook_message.message.sticker_id,
                                attachments: facebook_message.message.attachments,
                                quick_reply: facebook_message.message.quick_reply,
                                type: 'user_message',
                            };

                            facebook_botkit.receiveMessage(bot, message);
                        } else if (facebook_message.postback) {

                            // trigger BOTH a facebook_postback event
                            // and a normal message received event.
                            // this allows developers to receive postbacks as part of a conversation.
                            var message = {
                                text: facebook_message.postback.payload,
                                payload: facebook_message.postback.payload,
                                user: facebook_message.sender.id,
                                channel: facebook_message.sender.id,
                                timestamp: facebook_message.timestamp,
                            };

                            facebook_botkit.trigger('facebook_postback', [bot, message]);

                            if (facebook_botkit.config.receive_via_postback) {
                                var message = {
                                    text: facebook_message.postback.payload,
                                    user: facebook_message.sender.id,
                                    channel: facebook_message.sender.id,
                                    timestamp: facebook_message.timestamp,
                                    type: 'facebook_postback',
                                };

                                facebook_botkit.receiveMessage(bot, message);
                            }

                        } else if (facebook_message.optin) {

                            var message = {
                                optin: facebook_message.optin,
                                user: facebook_message.sender.id,
                                channel: facebook_message.sender.id,
                                timestamp: facebook_message.timestamp,
                            };

                            facebook_botkit.trigger('facebook_optin', [bot, message]);
                        } else if (facebook_message.delivery) {

                            var message = {
                                delivery: facebook_message.delivery,
                                user: facebook_message.sender.id,
                                channel: facebook_message.sender.id,
                            };

                            facebook_botkit.trigger('message_delivered', [bot, message]);
                        } else if (facebook_message.read) {

                            var message = {
                                read: facebook_message.read,
                                user: facebook_message.sender.id,
                                channel: facebook_message.sender.id,
                                timestamp: facebook_message.timestamp,
                            };

                            facebook_botkit.trigger('message_read', [bot, message]);
                        } else if (facebook_message.referral) {
                            var message = {
                                user: facebook_message.sender.id,
                                channel: facebook_message.sender.id,
                                timestamp: facebook_message.timestamp,
                                referral: facebook_message.referral,
                            };

                            facebook_botkit.trigger('facebook_referral', [bot, message]);
                        }  else {
                            facebook_botkit.log('Got an unexpected message from Facebook: ', facebook_message);
                        }
                    }
                }
            }
            res.send('ok');
        });

        webserver.get('/facebook/receive', function(req, res) {
            if (req.query['hub.mode'] == 'subscribe') {
                if (req.query['hub.verify_token'] == configuration.verify_token) {
                    res.send(req.query['hub.challenge']);
                } else {
                    res.send('OK');
                }
            }
        });

        if (cb) {
            cb();
        }

        return facebook_botkit;
    };

    facebook_botkit.setupWebserver = function(port, cb) {

        if (!port) {
            throw new Error('Cannot start webserver without a port');
        }

        var static_dir =  __dirname + '/public';

        if (facebook_botkit.config && facebook_botkit.config.webserver && facebook_botkit.config.webserver.static_dir)
            static_dir = facebook_botkit.config.webserver.static_dir;

        facebook_botkit.config.port = port;

        facebook_botkit.webserver = express();
        facebook_botkit.webserver.use(bodyParser.json());
        facebook_botkit.webserver.use(bodyParser.urlencoded({ extended: true }));
        facebook_botkit.webserver.use(express.static(static_dir));

        var server = facebook_botkit.webserver.listen(
            facebook_botkit.config.port,
            facebook_botkit.config.hostname,
            function() {
                facebook_botkit.log('** Starting webserver on port ' +
                    facebook_botkit.config.port);
                if (cb) { cb(null, facebook_botkit.webserver); }
            });

        request.post('https://graph.facebook.com/me/subscribed_apps?access_token=' + configuration.access_token,
            function(err, res, body) {
                if (err) {
                    facebook_botkit.log('Could not subscribe to page messages');
                } else {
                    facebook_botkit.debug('Successfully subscribed to Facebook events:', body);
                    facebook_botkit.startTicking();
                }
            });

        return facebook_botkit;

    };

    facebook_botkit.api = {
        'thread_settings': {
            greeting: function(greeting) {
                var message = {
                    'setting_type': 'greeting',
                    'greeting': {
                        'text': greeting
                    }
                };
                facebook_botkit.api.thread_settings.postAPI(message);
            },
            delete_greeting: function() {
                var message = {
                    'setting_type': 'greeting',
                };
                facebook_botkit.api.thread_settings.deleteAPI(message);
            },
            get_started: function(payload) {
                var message = {
                    'setting_type': 'call_to_actions',
                    'thread_state': 'new_thread',
                    'call_to_actions':
                        [
                            {
                                'payload': payload
                            }
                        ]
                };
                facebook_botkit.api.thread_settings.postAPI(message);
            },
            delete_get_started: function() {
                var message = {
                    'setting_type': 'call_to_actions',
                    'thread_state': 'new_thread',
                };
                facebook_botkit.api.thread_settings.deleteAPI(message);
            },
            menu: function(payload) {
                var message = {
                    'setting_type': 'call_to_actions',
                    'thread_state': 'existing_thread',
                    'call_to_actions': payload
                };
                facebook_botkit.api.thread_settings.postAPI(message);
            },
            delete_menu: function() {
                var message = {
                    'setting_type': 'call_to_actions',
                    'thread_state': 'existing_thread',
                };
                facebook_botkit.api.thread_settings.deleteAPI(message);
            },
            postAPI: function(message) {
                request.post('https://graph.facebook.com/v2.6/me/thread_settings?access_token=' + configuration.access_token,
                    {form: message},
                    function(err, res, body) {
                        if (err) {
                            facebook_botkit.log('Could not configure thread settings');
                        } else {

                            var results = null;
                            try {
                                results = JSON.parse(body);
                            } catch (err) {
                                facebook_botkit.log('ERROR in thread_settings API call: Could not parse JSON', err, body);
                            }

                            if (results) {
                                if (results.error) {
                                    facebook_botkit.log('ERROR in thread_settings API call: ', results.error.message);
                                } else {
                                    facebook_botkit.debug('Successfully configured thread settings', body);
                                }
                            }

                        }
                    });
            },
            deleteAPI: function(message) {
                request.delete('https://graph.facebook.com/v2.6/me/thread_settings?access_token=' + configuration.access_token,
                    {form: message},
                    function(err, res, body) {
                        if (err) {
                            facebook_botkit.log('Could not configure thread settings');
                        } else {
                            facebook_botkit.debug('Successfully configured thread settings', message);
                        }
                    });
            }
        }
    };

    return facebook_botkit;
};

module.exports = Facebookbot;
<commit_msg>Re #552 - add support for referral param via postbacks (Facebook)<commit_after>var Botkit = require(__dirname + '/CoreBot.js');
var request = require('request');
var express = require('express');
var bodyParser = require('body-parser');

function Facebookbot(configuration) {

    // Create a core botkit bot
    var facebook_botkit = Botkit(configuration || {});

    if (facebook_botkit.config.require_delivery) {

        facebook_botkit.on('message_delivered', function(bot, message) {

            // get list of mids in this message
            for (var m = 0; m < message.delivery.mids.length; m++) {
                var mid = message.delivery.mids[m];

                // loop through all active conversations this bot is having
                // and mark messages in conversations as delivered = true
                bot.findConversation(message, function(convo) {
                    if (convo) {
                        for (var s = 0; s < convo.sent.length; s++) {
                            if (convo.sent[s].sent_timestamp <= message.delivery.watermark ||
                                (convo.sent[s].api_response && convo.sent[s].api_response.mid == mid)) {
                                convo.sent[s].delivered = true;
                            }
                        }
                    }
                });
            }

        });

    }

    // customize the bot definition, which will be used when new connections
    // spawn!
    facebook_botkit.defineBot(function(botkit, config) {

        var bot = {
            type: 'fb',
            botkit: botkit,
            config: config || {},
            utterances: botkit.utterances,
        };

        bot.startConversation = function(message, cb) {
            botkit.startConversation(this, message, cb);
        };

        bot.createConversation = function(message, cb) {
            botkit.createConversation(this, message, cb);
        };

        bot.send = function(message, cb) {

            var facebook_message = {
                recipient: {},
                message: message.sender_action ? undefined : {}
            };

            if (typeof(message.channel) == 'string' && message.channel.match(/\+\d+\(\d\d\d\)\d\d\d\-\d\d\d\d/)) {
                facebook_message.recipient.phone_number = message.channel;
            } else {
                facebook_message.recipient.id = message.channel;
            }

            if (!message.sender_action) {
                if (message.text) {
                    facebook_message.message.text = message.text;
                }

                if (message.attachment) {
                    facebook_message.message.attachment = message.attachment;
                }

                if (message.sticker_id) {
                    facebook_message.message.sticker_id = message.sticker_id;
                }

                if (message.quick_replies) {

                    // sanitize the length of the title to maximum of 20 chars
                    var titleLimit = function(title) {
                        if (title.length > 20) {
                            var newTitle = title.substring(0, 16) + '...';
                            return newTitle;
                        } else {
                            return title;
                        }
                    };

                    facebook_message.message.quick_replies = message.quick_replies.map(function(item) {
                        return {
                            content_type: item.content_type || 'text',
                            title: titleLimit(item.title),
                            payload: item.payload,
                            image_url: item.image_url,
                        };
                    });
                }
            } else {
                facebook_message.sender_action = message.sender_action;
            }

            if (message.sender_action) {
                facebook_message.sender_action = message.sender_action;
            }

            if (message.notification_type) {
                facebook_message.notification_type = message.notification_type;
            }

            //Add Access Token to outgoing request
            facebook_message.access_token = configuration.access_token;

            request({
                method: 'POST',
                json: true,
                headers: {
                    'content-type': 'application/json',
                },
                body: facebook_message,
                uri: 'https://graph.facebook.com/v2.6/me/messages'
            },
                function(err, res, body) {

                    if (err) {
                        botkit.debug('WEBHOOK ERROR', err);
                        return cb && cb(err);
                    }

                    if (body.error) {
                        botkit.debug('API ERROR', body.error);
                        return cb && cb(body.error.message);
                    }

                    botkit.debug('WEBHOOK SUCCESS', body);
                    cb && cb(null, body);
                });
        };

        bot.startTyping = function(src, cb) {
            var msg = {};
            msg.channel = src.channel;
            msg.sender_action = 'typing_on';
            bot.say(msg, cb);
        };

        bot.stopTyping = function(src, cb) {
            var msg = {};
            msg.channel = src.channel;
            msg.sender_action = 'typing_off';
            bot.say(msg, cb);
        };

        bot.replyWithTyping = function(src, resp, cb) {
            var text;

            if (typeof(resp) == 'string') {
                text = resp;
            } else {
                text = resp.text;
            }

            var avgWPM = 85;
            var avgCPM = avgWPM * 7;

            var typingLength = Math.min(Math.floor(text.length / (avgCPM / 60)) * 1000, 5000);

            bot.startTyping(src, function(err) {
                if (err) console.log(err);
                setTimeout(function() {
                    bot.reply(src, resp, cb);
                }, typingLength);
            });

        };

        bot.reply = function(src, resp, cb) {
            var msg = {};

            if (typeof(resp) == 'string') {
                msg.text = resp;
            } else {
                msg = resp;
            }

            msg.channel = src.channel;

            bot.say(msg, cb);
        };

        bot.findConversation = function(message, cb) {
            botkit.debug('CUSTOM FIND CONVO', message.user, message.channel);
            for (var t = 0; t < botkit.tasks.length; t++) {
                for (var c = 0; c < botkit.tasks[t].convos.length; c++) {
                    if (
                        botkit.tasks[t].convos[c].isActive() &&
                        botkit.tasks[t].convos[c].source_message.user == message.user
                    ) {
                        botkit.debug('FOUND EXISTING CONVO!');
                        cb(botkit.tasks[t].convos[c]);
                        return;
                    }
                }
            }

            cb();
        };

        return bot;
    });

    // set up a web route for receiving outgoing webhooks and/or slash commands

    facebook_botkit.createWebhookEndpoints = function(webserver, bot, cb) {

        facebook_botkit.log(
            '** Serving webhook endpoints for Messenger Platform at: ' +
            'http://' + facebook_botkit.config.hostname + ':' + facebook_botkit.config.port + '/facebook/receive');
        webserver.post('/facebook/receive', function(req, res) {

            facebook_botkit.debug('GOT A MESSAGE HOOK');
            var obj = req.body;
            if (obj.entry) {
                for (var e = 0; e < obj.entry.length; e++) {
                    for (var m = 0; m < obj.entry[e].messaging.length; m++) {
                        var facebook_message = obj.entry[e].messaging[m];
                        if (facebook_message.message) {
                            var message = {
                                text: facebook_message.message.text,
                                user: facebook_message.sender.id,
                                channel: facebook_message.sender.id,
                                timestamp: facebook_message.timestamp,
                                seq: facebook_message.message.seq,
                                is_echo: facebook_message.message.is_echo,
                                mid: facebook_message.message.mid,
                                sticker_id: facebook_message.message.sticker_id,
                                attachments: facebook_message.message.attachments,
                                quick_reply: facebook_message.message.quick_reply,
                                type: 'user_message',
                            };

                            facebook_botkit.receiveMessage(bot, message);
                        } else if (facebook_message.postback) {
                            // trigger BOTH a facebook_postback event
                            // and a normal message received event.
                            // this allows developers to receive postbacks as part of a conversation.
                            var message = {
                                text: facebook_message.postback.payload,
                                payload: facebook_message.postback.payload,
                                user: facebook_message.sender.id,
                                channel: facebook_message.sender.id,
                                timestamp: facebook_message.timestamp,
                                referral: facebook_message.postback.referral,
                            };

                            facebook_botkit.trigger('facebook_postback', [bot, message]);

                            if (facebook_botkit.config.receive_via_postback) {
                                var message = {
                                    text: facebook_message.postback.payload,
                                    user: facebook_message.sender.id,
                                    channel: facebook_message.sender.id,
                                    timestamp: facebook_message.timestamp,
                                    referral: facebook_message.postback.referral,
                                    type: 'facebook_postback',
                                };

                                facebook_botkit.receiveMessage(bot, message);
                            }

                        } else if (facebook_message.optin) {

                            var message = {
                                optin: facebook_message.optin,
                                user: facebook_message.sender.id,
                                channel: facebook_message.sender.id,
                                timestamp: facebook_message.timestamp,
                            };

                            facebook_botkit.trigger('facebook_optin', [bot, message]);
                        } else if (facebook_message.delivery) {

                            var message = {
                                delivery: facebook_message.delivery,
                                user: facebook_message.sender.id,
                                channel: facebook_message.sender.id,
                            };

                            facebook_botkit.trigger('message_delivered', [bot, message]);
                        } else if (facebook_message.read) {

                            var message = {
                                read: facebook_message.read,
                                user: facebook_message.sender.id,
                                channel: facebook_message.sender.id,
                                timestamp: facebook_message.timestamp,
                            };

                            facebook_botkit.trigger('message_read', [bot, message]);
                        } else if (facebook_message.referral) {
                            var message = {
                                user: facebook_message.sender.id,
                                channel: facebook_message.sender.id,
                                timestamp: facebook_message.timestamp,
                                referral: facebook_message.referral,
                            };

                            facebook_botkit.trigger('facebook_referral', [bot, message]);
                        }  else {
                            facebook_botkit.log('Got an unexpected message from Facebook: ', facebook_message);
                        }
                    }
                }
            }
            res.send('ok');
        });

        webserver.get('/facebook/receive', function(req, res) {
            if (req.query['hub.mode'] == 'subscribe') {
                if (req.query['hub.verify_token'] == configuration.verify_token) {
                    res.send(req.query['hub.challenge']);
                } else {
                    res.send('OK');
                }
            }
        });

        if (cb) {
            cb();
        }

        return facebook_botkit;
    };

    facebook_botkit.setupWebserver = function(port, cb) {

        if (!port) {
            throw new Error('Cannot start webserver without a port');
        }

        var static_dir =  __dirname + '/public';

        if (facebook_botkit.config && facebook_botkit.config.webserver && facebook_botkit.config.webserver.static_dir)
            static_dir = facebook_botkit.config.webserver.static_dir;

        facebook_botkit.config.port = port;

        facebook_botkit.webserver = express();
        facebook_botkit.webserver.use(bodyParser.json());
        facebook_botkit.webserver.use(bodyParser.urlencoded({ extended: true }));
        facebook_botkit.webserver.use(express.static(static_dir));

        var server = facebook_botkit.webserver.listen(
            facebook_botkit.config.port,
            facebook_botkit.config.hostname,
            function() {
                facebook_botkit.log('** Starting webserver on port ' +
                    facebook_botkit.config.port);
                if (cb) { cb(null, facebook_botkit.webserver); }
            });

        request.post('https://graph.facebook.com/me/subscribed_apps?access_token=' + configuration.access_token,
            function(err, res, body) {
                if (err) {
                    facebook_botkit.log('Could not subscribe to page messages');
                } else {
                    facebook_botkit.debug('Successfully subscribed to Facebook events:', body);
                    facebook_botkit.startTicking();
                }
            });

        return facebook_botkit;

    };

    facebook_botkit.api = {
        'thread_settings': {
            greeting: function(greeting) {
                var message = {
                    'setting_type': 'greeting',
                    'greeting': {
                        'text': greeting
                    }
                };
                facebook_botkit.api.thread_settings.postAPI(message);
            },
            delete_greeting: function() {
                var message = {
                    'setting_type': 'greeting',
                };
                facebook_botkit.api.thread_settings.deleteAPI(message);
            },
            get_started: function(payload) {
                var message = {
                    'setting_type': 'call_to_actions',
                    'thread_state': 'new_thread',
                    'call_to_actions':
                        [
                            {
                                'payload': payload
                            }
                        ]
                };
                facebook_botkit.api.thread_settings.postAPI(message);
            },
            delete_get_started: function() {
                var message = {
                    'setting_type': 'call_to_actions',
                    'thread_state': 'new_thread',
                };
                facebook_botkit.api.thread_settings.deleteAPI(message);
            },
            menu: function(payload) {
                var message = {
                    'setting_type': 'call_to_actions',
                    'thread_state': 'existing_thread',
                    'call_to_actions': payload
                };
                facebook_botkit.api.thread_settings.postAPI(message);
            },
            delete_menu: function() {
                var message = {
                    'setting_type': 'call_to_actions',
                    'thread_state': 'existing_thread',
                };
                facebook_botkit.api.thread_settings.deleteAPI(message);
            },
            postAPI: function(message) {
                request.post('https://graph.facebook.com/v2.6/me/thread_settings?access_token=' + configuration.access_token,
                    {form: message},
                    function(err, res, body) {
                        if (err) {
                            facebook_botkit.log('Could not configure thread settings');
                        } else {

                            var results = null;
                            try {
                                results = JSON.parse(body);
                            } catch (err) {
                                facebook_botkit.log('ERROR in thread_settings API call: Could not parse JSON', err, body);
                            }

                            if (results) {
                                if (results.error) {
                                    facebook_botkit.log('ERROR in thread_settings API call: ', results.error.message);
                                } else {
                                    facebook_botkit.debug('Successfully configured thread settings', body);
                                }
                            }

                        }
                    });
            },
            deleteAPI: function(message) {
                request.delete('https://graph.facebook.com/v2.6/me/thread_settings?access_token=' + configuration.access_token,
                    {form: message},
                    function(err, res, body) {
                        if (err) {
                            facebook_botkit.log('Could not configure thread settings');
                        } else {
                            facebook_botkit.debug('Successfully configured thread settings', message);
                        }
                    });
            }
        }
    };

    return facebook_botkit;
};

module.exports = Facebookbot;
<|endoftext|>


<commit_before>/*
 * Simple middleware that saves res.locals as stringified JSON to
 * `res.locals.INITIAL_STATE`
 *
 * @module midwest/middleware/bootstrap
 */

'use strict'

const _ = require('lodash')

const defaultOmit = ['settings']

module.exports = function ({ pick, omit, property = 'INITIAL_STATE' }) {
  if (!pick) {
    omit = omit ? defaultOmit.concat(omit) : defaultOmit
  }

  return function bootstrap (req, res, next) {
    if (!req.xhr && req.accepts(['json', '*/*']) === '*/*') {
      let obj = Object.assign({}, res.app.locals, res.locals)

      if (pick) {
        obj = _.pick(obj, pick)
      } else {
        obj = _.omit(obj, omit)
      }

      res.locals[property] = JSON.stringify(obj)
    }

    next()
  }
}
<commit_msg>Set empty object as default arg<commit_after>/*
 * Simple middleware that saves res.locals as stringified JSON to
 * `res.locals.INITIAL_STATE`
 *
 * @module midwest/middleware/bootstrap
 */

'use strict'

const _ = require('lodash')

const defaultOmit = ['settings']

module.exports = function ({ pick, omit, property = 'INITIAL_STATE' } = {}) {
  if (!pick) {
    omit = omit ? defaultOmit.concat(omit) : defaultOmit
  }

  return function bootstrap (req, res, next) {
    if (!req.xhr && req.accepts(['json', '*/*']) === '*/*') {
      let obj = Object.assign({}, res.app.locals, res.locals)

      if (pick) {
        obj = _.pick(obj, pick)
      } else {
        obj = _.omit(obj, omit)
      }

      res.locals[property] = JSON.stringify(obj)
    }

    next()
  }
}
<|endoftext|>


<commit_before>import React from 'react'
import { Diory, DioryGrid } from '../lib'

const diory = {
  text: 'Hello, I am a diory. Take me home!',
  image: 'https://gravatar.com/avatar/ff80f8f9bc52f1b79e468a41f2239001',
  styles: {
    diory: { display: 'inline-block', width: '20em', height: '20em', backgroundColor: 'green', margin: '1em' },
    text: { fontSize: '2em', fontFamily: 'sans-serif', color: 'white', textAlign: 'center', textShadow: '1px 1px green' },
    image: { opacity: 0.6, filter: 'blur(5px)' }
  }
}

const dioryGrid = {
  text: 'This is a diory grid:',
  styles: {
    text: { fontSize: '2em', fontFamily: 'sans-serif' }
  },
  diorys: {
    1: diory,
    2: diory,
    3: diory,
    4: diory
  }
}

const DioryExample = ({}) => (

    <Diory { ...diory } />
    <DioryGrid { ...dioryGrid } />

)

export default DioryExample
<commit_msg>add example on flexbox grid<commit_after>import React from 'react'
import { Diory, DioryGrid } from '../lib'

const diory = {
  text: 'Hello, I am a diory. Take me home!',
  image: 'https://gravatar.com/avatar/ff80f8f9bc52f1b79e468a41f2239001',
  styles: {
    diory: { display: 'inline-block', width: '20em', height: '20em', backgroundColor: 'green', margin: '1em' },
    text: { fontSize: '2em', fontFamily: 'sans-serif', color: 'white', textAlign: 'center', textShadow: '1px 1px green' },
    image: { opacity: 0.6, filter: 'blur(5px)' }
  }
}

const dioryGrid = {
  text: 'This is a grid:',
  styles: {
    text: { fontSize: '2em', fontFamily: 'sans-serif' }
  },
  diorys: {
    1: diory,
    2: diory,
    3: diory,
    4: diory
  }
}

const dioryFlexItem = { ...diory }
dioryFlexItem.styles.diory.flex = '1 0 20em'

const dioryFlexGrid = {
  image: 'https://gravatar.com/avatar/ff80f8f9bc52f1b79e468a41f2239001',
  styles: {
    diory: { display: 'flex', flexWrap: 'wrap' }
  },
  diorys: {
    1: diory,
    2: diory,
    3: diory,
    4: diory
  }
}

const DioryExample = ({}) => (

    <Diory { ...diory } />
    <DioryGrid { ...dioryGrid } />
    <Diory text="This is a flex grid:" styles={{ text: { fontSize: '2em', fontFamily: 'sans-serif' }}} />
    <DioryGrid { ...dioryFlexGrid } />

)

export default DioryExample
<|endoftext|>


<commit_before>(function () {
    "use strict";
    angular.module("services")
        .factory("path", path);

    path.$inject = [
        '$location',
        'EventsService',
        '$route',
        'AuthService',
        'userConstants'
    ];

    function path($location, EventsService, $route, AuthService, userConstants) {
        const current = $location.url();
        let next = current === '/unavailable' ? '/' : current;
        const service = {
            current: current,
            goTo: goTo,
            getUrlPath: getUrlPath,
            locationPath: locationPath
        };

        EventsService.subscribe(service, EventsService.AUTH_LOGIN, () => {
            let rootPath = '/';
            if (AuthService.user.role === userConstants.role.EVALUATOR)
                rootPath = '/groups/1';

            return ['/login', ''].includes(current) ? goTo(rootPath) : goTo(next);
        });

        EventsService.subscribe(service, EventsService.AUTH_LOGOUT, () => {
            next = '/';
        });

        function goTo(path) {
            $location.path(path);
            $route.reload();
        }

        function getUrlPath(url) {
            return url.replace(/https?:\/\/[^\/]+\//, "");
        }

        function locationPath() {
            return $location.$$path;
        }

        return service;
    }
})();<commit_msg>Update path service: remove query from location url<commit_after>(function () {
    "use strict";
    angular.module("services")
        .factory("path", path);

    path.$inject = [
        '$location',
        'EventsService',
        '$route',
        'AuthService',
        'userConstants'
    ];

    function path($location, EventsService, $route, AuthService, userConstants) {
        const current = $location.url();
        let next = current === '/unavailable' ? '/' : current.split('?')[0];
        const service = {
            current: current,
            goTo: goTo,
            getUrlPath: getUrlPath,
            locationPath: locationPath
        };

        EventsService.subscribe(service, EventsService.AUTH_LOGIN, () => {
            let rootPath = '/';
            if (AuthService.user.role === userConstants.role.EVALUATOR)
                rootPath = '/groups/1';

            return ['/login', ''].includes(current) ? goTo(rootPath) : goTo(next);
        });

        EventsService.subscribe(service, EventsService.AUTH_LOGOUT, () => {
            next = '/';
        });

        function goTo(path) {
            $location.path(path);
            $route.reload();
        }

        function getUrlPath(url) {
            return url.replace(/https?:\/\/[^\/]+\//, "");
        }

        function locationPath() {
            return $location.$$path;
        }

        return service;
    }
})();<|endoftext|>


<commit_before>module('Blog post test');

test('Date set to current time', function() {
  var post = new BlogPost('Hello', 'Hello world');
  ok(post.date, 'not comparing the date since it seem to get off')
});

test('Unpublished post throws exception', function() {
  var post = new BlogPost('Hello', 'Hello world');
  throws(post.toString, new Error("This blog post is not published"), "Got exception");
});

test('Generates HTML', function() {
  stop();
  var now = new Date();
  var newpost = new BlogPost('Hello', 'Hello world', now);
  newpost.publish(function(post) {
    equal(post.toString(), "
Hello
" +
      "
Published on " + now.toString() + "
" +
      "
Hello world
", 'Generated expected HTML');
    start();
  });

});

test('Fails epicly', function() {
  ok(false, 'Everything is going to be allright');
});
<commit_msg>Use QUnit2-compatible syntax in test<commit_after>var unit = QUnit;

unit.module('Blog post test');

unit.test('Date set to current time', function(assert) {
  var post = new BlogPost('Hello', 'Hello world');
  assert.ok(post.date, 'not comparing the date since it seem to get off')
});

unit.test('Unpublished post throws exception', function(assert) {
  var post = new BlogPost('Hello', 'Hello world');
  assert.throws(post.toString, new Error("This blog post is not published"), "Got exception");
});

unit.test('Generates HTML', function(assert) {
  var done = assert.async();
  var now = new Date();
  var newpost = new BlogPost('Hello', 'Hello world', now);
  newpost.publish(function(post) {
    assert.equal(post.toString(), "
Hello
" +
      "
Published on " + now.toString() + "
" +
      "
Hello world
", 'Generated expected HTML');
    done();
  });
});

unit.test('Fails epicly', function(assert) {
  assert.ok(false, 'Everything is going to be allright');
});
<|endoftext|>


<commit_before>/***
 * ... loader
 * @craiglu
 */

import React from 'react';

export default class DotDotDotLoader extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      dotState: 0,
      dots: '.',
      show: false,
      amount: 3,
      repeat: true,
      interval: 500,
    }
  }
  componentDidMount() {
    if (this.props.repeat !== null) {
      this.setState({
        repeat: this.props.repeat,
      })
    }
    if (this.props.amount !== null) {
      this.setState({
        amount: this.props.amount,
      })
    }
    if (this.state.interval !== null) {
      this.setState({
        interval: this.props.interval,
      })
    }
    this.setState({
      show: this.props.show,
    })
  }
  componentWillReceiveProps(nextProps) {
    if (this.state.show !== nextProps.show) {
      this.setState({
        show: nextProps.show,
      })

      if (nextProps.show) {
        this.dotsLoader();
      } else {
        clearTimeout(this.dotsLoaderTimeout)
        this.setState({
          dotState: 0,
          dots: '.',
        })
      }
    }
  }

  componentWillUnmount() {
    clearTimeout(this.dotsLoaderTimeout)
  }

  /***
  * recursive function with timeout that loads in the next set of dots
  */
  dotsLoader = () => {
    clearTimeout(this.dotsLoaderTimeout)
    var nextAmount = this.state.dotState + 1;

    if (this.state.repeat) {
      nextAmount = (this.state.dotState + 1) % this.state.amount;
    }
    var nextDots;
    if (nextAmount === 0) {
      nextDots = '.'
    } else {
      nextDots = this.state.dots + '.';
    }
    this.setState({
      dotState: nextAmount,
      dots: nextDots,
    })
    this.dotsLoaderTimeout = setTimeout(() => {
      this.dotsLoader()
    }, this.state.interval)
  }

  render() {
    return (

        {this.state.show
          ? this.state.dots
          : null
        }

    )
  }
}<commit_msg>added maintainer email<commit_after>/***
 * ... loader
 * @craiglu -- craig@quantfive.org
 */

import React from 'react';

export default class DotDotDotLoader extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      dotState: 0,
      dots: '.',
      show: false,
      amount: 3,
      repeat: true,
      interval: 500,
    }
  }
  componentDidMount() {
    if (this.props.repeat !== null) {
      this.setState({
        repeat: this.props.repeat,
      })
    }
    if (this.props.amount !== null) {
      this.setState({
        amount: this.props.amount,
      })
    }
    if (this.state.interval !== null) {
      this.setState({
        interval: this.props.interval,
      })
    }
    this.setState({
      show: this.props.show,
    })
  }
  componentWillReceiveProps(nextProps) {
    if (this.state.show !== nextProps.show) {
      this.setState({
        show: nextProps.show,
      })

      if (nextProps.show) {
        this.dotsLoader();
      } else {
        clearTimeout(this.dotsLoaderTimeout)
        this.setState({
          dotState: 0,
          dots: '.',
        })
      }
    }
  }

  componentWillUnmount() {
    clearTimeout(this.dotsLoaderTimeout)
  }

  /***
  * recursive function with timeout that loads in the next set of dots
  */
  dotsLoader = () => {
    clearTimeout(this.dotsLoaderTimeout)
    var nextAmount = this.state.dotState + 1;

    if (this.state.repeat) {
      nextAmount = (this.state.dotState + 1) % this.state.amount;
    }
    var nextDots;
    if (nextAmount === 0) {
      nextDots = '.'
    } else {
      nextDots = this.state.dots + '.';
    }
    this.setState({
      dotState: nextAmount,
      dots: nextDots,
    })
    this.dotsLoaderTimeout = setTimeout(() => {
      this.dotsLoader()
    }, this.state.interval)
  }

  render() {
    return (

        {this.state.show
          ? this.state.dots
          : null
        }

    )
  }
}<|endoftext|>


<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

var EventEmitter = require('events').EventEmitter;
var inherits = require('util').inherits;

var errors = require('./errors');
var OutArgStream = require('./argstream').OutArgStream;

var emptyBuffer = Buffer(0);

var States = Object.create(null);
States.Initial = 0;
States.Streaming = 1;
States.Done = 2;
States.Error = 3;

function TChannelOutgoingResponse(id, options) {
    options = options || {};
    if (!options.sendFrame) {
        throw new Error('missing sendFrame');
    }
    var self = this;
    EventEmitter.call(self);
    self.logger = options.logger;
    self.random = options.random;
    self.timers = options.timers;

    self.state = States.Initial;
    self.id = id || 0;
    self.code = options.code || 0;
    self.tracing = options.tracing || null;
    self.headers = options.headers || {};
    self.checksumType = options.checksumType || 0;
    self.checksum = options.checksum || null;
    self.ok = self.code === 0;
    self.sendFrame = options.sendFrame;
    self.span = options.span || null;
    if (options.streamed) {
        self.streamed = true;
        self._argstream = OutArgStream();
        self.arg1 = self._argstream.arg1;
        self.arg2 = self._argstream.arg2;
        self.arg3 = self._argstream.arg3;
        self._argstream.on('error', function passError(err) {
            self.emit('error', err);
        });
        self._argstream.on('frame', function onFrame(parts, isLast) {
            self.sendParts(parts, isLast);
        });
        self._argstream.on('finish', function onFinish() {
            self.emit('finish');
        });
    } else {
        self.streamed = false;
        self._argstream = null;
        self.arg1 = null;
        self.arg2 = null;
        self.arg3 = null;
    }

    self.on('finish', function onOutgoingResFinish() {
        if (self.span) {
            self.emit('span', self.span);
        }
    });
}

inherits(TChannelOutgoingResponse, EventEmitter);

TChannelOutgoingResponse.prototype.type = 'tchannel.outgoing-response';

TChannelOutgoingResponse.prototype.sendParts = function sendParts(parts, isLast) {
    var self = this;
    switch (self.state) {
        case States.Initial:
            self.sendCallResponseFrame(parts, isLast);
            break;
        case States.Streaming:
            self.sendCallResponseContFrame(parts, isLast);
            break;
        case States.Done:
            throw new Error('got frame in done state'); // TODO: typed error
        case States.Error:
            // TODO: log warn
            break;
    }
};

TChannelOutgoingResponse.prototype.sendCallResponseFrame = function sendCallResponseFrame(args, isLast) {
    var self = this;
    switch (self.state) {
        case States.Initial:
            self.sendFrame.callResponse(args, isLast);
            if (self.span) {
                self.span.annotate('ss');
            }
            if (isLast) self.state = States.Done;
            else self.state = States.Streaming;
            break;
        case States.Streaming:
            throw new Error('first response frame already sent'); // TODO: typed error
        case States.Done:
        case States.Error:
            throw errors.ResponseAlreadyDone({
                attempted: 'send call res frame'
            });
    }
};

TChannelOutgoingResponse.prototype.sendCallResponseContFrame = function sendCallResponseContFrame(args, isLast) {
    var self = this;
    switch (self.state) {
        case States.Initial:
            throw new Error('first response frame not sent'); // TODO: typed error
        case States.Streaming:
            self.sendFrame.callResponseCont(args, isLast);
            if (isLast) self.state = States.Done;
            break;
        case States.Done:
        case States.Error:
            throw errors.ResponseAlreadyDone({
                attempted: 'send call res cont frame'
            });
    }
};

TChannelOutgoingResponse.prototype.sendError = function sendError(codeString, message) {
    var self = this;
    if (self.state === States.Done || self.state === States.Error) {
        throw errors.ResponseAlreadyDone({
            attempted: 'send error frame: ' + codeString + ': ' + message
        });
    } else {
        if (self.span) {
            self.span.annotate('ss');
        }
        self.state = States.Error;
        if (self.streamed) {
            // TODO: we could decide to flush any parts in a (first?) call res frame
            self._argstream.finished = true;
            self.arg1.end();
            self.arg2.end();
            self.arg3.end();
        }
        self.sendFrame.error(codeString, message);
        self.emit('errored', codeString, message);
    }
};

TChannelOutgoingResponse.prototype.setOk = function setOk(ok) {
    var self = this;
    if (self.state !== States.Initial) {
        throw new Error('response already started'); // TODO typed error
    }
    self.ok = ok;
    self.code = ok ? 0 : 1; // TODO: too coupled to v2 specifics?
    if (self.streamed) {
        self.arg1.end();
    }
};

TChannelOutgoingResponse.prototype.sendOk = function sendOk(res1, res2) {
    var self = this;
    self.setOk(true);
    self.send(res1, res2);
};

TChannelOutgoingResponse.prototype.sendNotOk = function sendNotOk(res1, res2) {
    var self = this;
    self.setOk(false);
    self.send(res1, res2);
};

TChannelOutgoingResponse.prototype.send = function send(res1, res2) {
    var self = this;
    if (self.streamed) {
        self.arg2.end(res1);
        self.arg3.end(res2);
    } else {
        self.sendCallResponseFrame([
            self.arg1 || emptyBuffer,
            res1 ? Buffer(res1) : emptyBuffer,
            res2 ? Buffer(res2) : emptyBuffer
        ], true);
        self.emit('finish');
    }
};

TChannelOutgoingResponse.States = States;

module.exports = TChannelOutgoingResponse;
<commit_msg>OutgoingResponse: factor out #onFinish<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

var EventEmitter = require('events').EventEmitter;
var inherits = require('util').inherits;

var errors = require('./errors');
var OutArgStream = require('./argstream').OutArgStream;

var emptyBuffer = Buffer(0);

var States = Object.create(null);
States.Initial = 0;
States.Streaming = 1;
States.Done = 2;
States.Error = 3;

function TChannelOutgoingResponse(id, options) {
    options = options || {};
    if (!options.sendFrame) {
        throw new Error('missing sendFrame');
    }
    var self = this;
    EventEmitter.call(self);
    self.logger = options.logger;
    self.random = options.random;
    self.timers = options.timers;

    self.state = States.Initial;
    self.id = id || 0;
    self.code = options.code || 0;
    self.tracing = options.tracing || null;
    self.headers = options.headers || {};
    self.checksumType = options.checksumType || 0;
    self.checksum = options.checksum || null;
    self.ok = self.code === 0;
    self.sendFrame = options.sendFrame;
    self.span = options.span || null;
    if (options.streamed) {
        self.streamed = true;
        self._argstream = OutArgStream();
        self.arg1 = self._argstream.arg1;
        self.arg2 = self._argstream.arg2;
        self.arg3 = self._argstream.arg3;
        self._argstream.on('error', function passError(err) {
            self.emit('error', err);
        });
        self._argstream.on('frame', function onFrame(parts, isLast) {
            self.sendParts(parts, isLast);
        });
        self._argstream.on('finish', function onFinish() {
            self.emit('finish');
        });
    } else {
        self.streamed = false;
        self._argstream = null;
        self.arg1 = null;
        self.arg2 = null;
        self.arg3 = null;
    }

    self.on('finish', self.onFinish);
}

inherits(TChannelOutgoingResponse, EventEmitter);

TChannelOutgoingResponse.prototype.onFinish = function onFinish() {
    var self = this;
    if (self.span) {
        self.emit('span', self.span);
    }
};

TChannelOutgoingResponse.prototype.type = 'tchannel.outgoing-response';

TChannelOutgoingResponse.prototype.sendParts = function sendParts(parts, isLast) {
    var self = this;
    switch (self.state) {
        case States.Initial:
            self.sendCallResponseFrame(parts, isLast);
            break;
        case States.Streaming:
            self.sendCallResponseContFrame(parts, isLast);
            break;
        case States.Done:
            throw new Error('got frame in done state'); // TODO: typed error
        case States.Error:
            // TODO: log warn
            break;
    }
};

TChannelOutgoingResponse.prototype.sendCallResponseFrame = function sendCallResponseFrame(args, isLast) {
    var self = this;
    switch (self.state) {
        case States.Initial:
            self.sendFrame.callResponse(args, isLast);
            if (self.span) {
                self.span.annotate('ss');
            }
            if (isLast) self.state = States.Done;
            else self.state = States.Streaming;
            break;
        case States.Streaming:
            throw new Error('first response frame already sent'); // TODO: typed error
        case States.Done:
        case States.Error:
            throw errors.ResponseAlreadyDone({
                attempted: 'send call res frame'
            });
    }
};

TChannelOutgoingResponse.prototype.sendCallResponseContFrame = function sendCallResponseContFrame(args, isLast) {
    var self = this;
    switch (self.state) {
        case States.Initial:
            throw new Error('first response frame not sent'); // TODO: typed error
        case States.Streaming:
            self.sendFrame.callResponseCont(args, isLast);
            if (isLast) self.state = States.Done;
            break;
        case States.Done:
        case States.Error:
            throw errors.ResponseAlreadyDone({
                attempted: 'send call res cont frame'
            });
    }
};

TChannelOutgoingResponse.prototype.sendError = function sendError(codeString, message) {
    var self = this;
    if (self.state === States.Done || self.state === States.Error) {
        throw errors.ResponseAlreadyDone({
            attempted: 'send error frame: ' + codeString + ': ' + message
        });
    } else {
        if (self.span) {
            self.span.annotate('ss');
        }
        self.state = States.Error;
        if (self.streamed) {
            // TODO: we could decide to flush any parts in a (first?) call res frame
            self._argstream.finished = true;
            self.arg1.end();
            self.arg2.end();
            self.arg3.end();
        }
        self.sendFrame.error(codeString, message);
        self.emit('errored', codeString, message);
    }
};

TChannelOutgoingResponse.prototype.setOk = function setOk(ok) {
    var self = this;
    if (self.state !== States.Initial) {
        throw new Error('response already started'); // TODO typed error
    }
    self.ok = ok;
    self.code = ok ? 0 : 1; // TODO: too coupled to v2 specifics?
    if (self.streamed) {
        self.arg1.end();
    }
};

TChannelOutgoingResponse.prototype.sendOk = function sendOk(res1, res2) {
    var self = this;
    self.setOk(true);
    self.send(res1, res2);
};

TChannelOutgoingResponse.prototype.sendNotOk = function sendNotOk(res1, res2) {
    var self = this;
    self.setOk(false);
    self.send(res1, res2);
};

TChannelOutgoingResponse.prototype.send = function send(res1, res2) {
    var self = this;
    if (self.streamed) {
        self.arg2.end(res1);
        self.arg3.end(res2);
    } else {
        self.sendCallResponseFrame([
            self.arg1 || emptyBuffer,
            res1 ? Buffer(res1) : emptyBuffer,
            res2 ? Buffer(res2) : emptyBuffer
        ], true);
        self.emit('finish');
    }
};

TChannelOutgoingResponse.States = States;

module.exports = TChannelOutgoingResponse;
<|endoftext|>


<commit_before>function findUrls( text )
{
    var source = (text || '').toString();
    var urlArray = [];
    var url;
    var matchArray;

    // Regular expression to find FTP, HTTP(S) and email URLs.
    var regexToken = /(((ftp|https?):\/\/)[\-\w@:%_\+.~#?,&\/\/=]+)|((mailto:)?[_.\w-]+@([\w][\w\-]+\.)+[a-zA-Z]{2,3})/g;

    // Iterate through any URLs in the text.
    while( (matchArray = regexToken.exec( source )) !== null )
    {
        var token = matchArray[0];
        urlArray.push( token );
    }

    return urlArray;
}

function showdialog(urls, done) {
//    debugger;
    var buttons = [];
    for (var i = 0; i < urls.length; i++) {
        if (urls[i].indexOf('.flv') > 0 || urls[i].indexOf('.mp4') > 0) {
            var url = urls[i];
            buttons.push({
                text: url,
                click: function() {
                    done(url);
                    $(this).dialog("close");
                }
            });
        }
    }

    var layerNode= document.createElement('div');
    layerNode.setAttribute('id','x-kodi-cda-dialog');
    layerNode.setAttribute('title','Links information');
/*
    var pNode= document.createElement('p');
    pNode.innerHTML  = "woow";
    layerNode.appendChild(pNode);
*/
    document.body.appendChild(layerNode);

    jQuery("#x-kodi-cda-dialog").dialog({
        autoOpen: true,
        draggable: true,
        resizable: true,
        height: 'auto',
        width: "800",
        zIndex:3999,
        modal: false,
        closeOnEscape: true,
        buttons: buttons,
        open: function(event, ui) {
            $(event.target).parent().css('position','fixed');
            $(event.target).parent().css('top', '5px');
            $(event.target).parent().css('left', '10px');
        }
    });
}

chrome.extension.onMessage.addListener(
    function(request, sender, sendResponse) {
        console.log("Received message: " + request.action);
        if (request.action == "getEmbeddedVideos" || request.action == "getVideoSrc") {
//            debugger;
            try {
                var url = $('video').attr('src');
                if( url === undefined )
                    throw "url is undefined";
                url = decodeURIComponent(url);
                showdialog([url], function(url) {
                    sendResponse({videoSrc: url});
                });
                return;
            } catch (e) {
                console.log("not html5 player:" + e);
            };
            var stext = $('#player').text();
            var es = stext.search('eval');
            var ei = stext.slice(es).search('return p');
            var ej = stext.slice(es).search(',{}');
            var et = '['+stext.slice(es+ei+10,es+ej+3)+']';
            var eo = eval(et);
            var pp=function(p,a,c,k,e,d){
                e=function(c){
                    return(
                        c35?String.fromCharCode(c+29):c.toString(36))
                };
                if(!''.replace(/^/,String)){
                    while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1
                };
                while(c--){
                    if(k[c]){
                        p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])
                    }
                }
                return p
            }
            var result = pp(eo[0], eo[1], eo[2], eo[3], eo[4], eo[5]);
            var urls = findUrls(result);
            showdialog(urls, function(url) {
                    var videoSrc = decodeURIComponent(url);
                    sendResponse({videoSrc: videoSrc});
            });
        } else {
            console.log('Unknown action: ' + request.action);
        }
    }
);<commit_msg>no ui<commit_after>function findUrls( text )
{
    var source = (text || '').toString();
    var urlArray = [];
    var url;
    var matchArray;

    // Regular expression to find FTP, HTTP(S) and email URLs.
    var regexToken = /(((ftp|https?):\/\/)[\-\w@:%_\+.~#?,&\/\/=]+)|((mailto:)?[_.\w-]+@([\w][\w\-]+\.)+[a-zA-Z]{2,3})/g;

    // Iterate through any URLs in the text.
    while( (matchArray = regexToken.exec( source )) !== null )
    {
        var token = matchArray[0];
        urlArray.push( token );
    }

    return urlArray;
}

function showdialog(urls, done) {
//    debugger;
    for (var i = 0; i < urls.length; i++) {
        if (urls[i].indexOf('.flv') > 0 || urls[i].indexOf('.mp4') > 0) {
            var url = urls[i];
            return done(url);
        }
    }
    var buttons = [];
    for (var i = 0; i < urls.length; i++) {
        if (urls[i].indexOf('.flv') > 0 || urls[i].indexOf('.mp4') > 0) {
            var url = urls[i];
            buttons.push({
                text: url,
                click: function() {
                    done(url);
                    $(this).dialog("close");
                }
            });
        }
    }

    var layerNode= document.createElement('div');
    layerNode.setAttribute('id','x-kodi-cda-dialog');
    layerNode.setAttribute('title','Links information');
/*
    var pNode= document.createElement('p');
    pNode.innerHTML  = "woow";
    layerNode.appendChild(pNode);
*/
    document.body.appendChild(layerNode);

    jQuery("#x-kodi-cda-dialog").dialog({
        autoOpen: true,
        draggable: true,
        resizable: true,
        height: 'auto',
        width: "800",
        zIndex:3999,
        modal: false,
        closeOnEscape: true,
        buttons: buttons,
        open: function(event, ui) {
            $(event.target).parent().css('position','fixed');
            $(event.target).parent().css('top', '5px');
            $(event.target).parent().css('left', '10px');
        }
    });
}

chrome.extension.onMessage.addListener(
    function(request, sender, sendResponse) {
        console.log("Received message: " + request.action);
        if (request.action == "getEmbeddedVideos" || request.action == "getVideoSrc") {
//            debugger;
            try {
                var url = $('video').attr('src');
                if( url === undefined )
                    throw "url is undefined";
                url = decodeURIComponent(url);
                showdialog([url], function(url) {
                    sendResponse({videoSrc: url});
                });
                return;
            } catch (e) {
                console.log("not html5 player:" + e);
            };
            var stext = $('#player').text();
            var es = stext.search('eval');
            var ei = stext.slice(es).search('return p');
            var ej = stext.slice(es).search(',{}');
            var et = '['+stext.slice(es+ei+10,es+ej+3)+']';
            var eo = eval(et);
            var pp=function(p,a,c,k,e,d){
                e=function(c){
                    return(
                        c35?String.fromCharCode(c+29):c.toString(36))
                };
                if(!''.replace(/^/,String)){
                    while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1
                };
                while(c--){
                    if(k[c]){
                        p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])
                    }
                }
                return p
            }
            var result = pp(eo[0], eo[1], eo[2], eo[3], eo[4], eo[5]);
            var urls = findUrls(result);
            showdialog(urls, function(url) {
                    var videoSrc = decodeURIComponent(url);
                    sendResponse({videoSrc: videoSrc});
            });
        } else {
            console.log('Unknown action: ' + request.action);
        }
    }
);<|endoftext|>