<commit_before>'use strict';

const apiai = require('apiai');
const express = require('express');
const bodyParser = require('body-parser');
const uuid = require('node-uuid');
const request = require('request');
const JSONbig = require('json-bigint');
const async = require('async');

const REST_PORT = (process.env.PORT || 5000);
const APIAI_ACCESS_TOKEN = process.env.APIAI_ACCESS_TOKEN;
const APIAI_LANG = process.env.APIAI_LANG || 'en';
const FB_VERIFY_TOKEN = process.env.FB_VERIFY_TOKEN;
const FB_PAGE_ACCESS_TOKEN = process.env.FB_PAGE_ACCESS_TOKEN;
const FB_TEXT_LIMIT = 640;
var barbrad = 'true';

class FacebookBot {
    constructor() {
        this.apiAiService = apiai(APIAI_ACCESS_TOKEN, {language: APIAI_LANG, requestSource: "fb"});
        this.sessionIds = new Map();
        this.messagesDelay = 200;
    }

    doDataResponse(sender, facebookResponseData) {
        if (!Array.isArray(facebookResponseData)) {
            console.log('Response as formatted message');
            this.sendFBMessage(sender, facebookResponseData)
                .catch(err => console.error(err));
        } else {
            async.eachSeries(facebookResponseData, (facebookMessage, callback) => {
                if (facebookMessage.sender_action) {
                    console.log('Response as sender action');
                    this.sendFBSenderAction(sender, facebookMessage.sender_action)
                        .then(() => callback())
                        .catch(err => callback(err));
                }
                else {
                    console.log('Response as formatted message');
                    this.sendFBMessage(sender, facebookMessage)
                        .then(() => callback())
                        .catch(err => callback(err));
                }
            }, (err) => {
                if (err) {
                    console.error(err);
                } else {
                    console.log('Data response completed');
                }
            });
        }
    }

    doRichContentResponse(sender, messages) {
        let facebookMessages = []; // array with result messages

        for (let messageIndex = 0; messageIndex < messages.length; messageIndex++) {
            let message = messages[messageIndex];

            switch (message.type) {
                //message.type 0 means text message
                case 0:
                    // speech: ["hi"]
                    // we have to get value from fulfillment.speech, because of here is raw speech
                    if (message.speech) {

                        let splittedText = this.splitResponse(message.speech);

                        splittedText.forEach(s => {
                            facebookMessages.push({text: s});
                        });
                    }

                    break;
                //message.type 1 means card message
                case 1: {
                    let carousel = [message];

                    for (messageIndex++; messageIndex < messages.length; messageIndex++) {
                        if (messages[messageIndex].type == 1) {
                            carousel.push(messages[messageIndex]);
                        } else {
                            messageIndex--;
                            break;
                        }
                    }

                    let facebookMessage = {};
                    carousel.forEach((c) => {
                        // buttons: [ {text: "hi", postback: "postback"} ], imageUrl: "", title: "", subtitle: ""

                        let card = {};

                        card.title = c.title;
                        card.image_url = c.imageUrl;
                        if (this.isDefined(c.subtitle)) {
                            card.subtitle = c.subtitle;
                        }
                        //If button is involved in.
                        if (c.buttons.length > 0) {
                            let buttons = [];
                            for (let buttonIndex = 0; buttonIndex < c.buttons.length; buttonIndex++) {
                                let button = c.buttons[buttonIndex];

                                if (button.text) {
                                    let postback = button.postback;
                                    if (!postback) {
                                        postback = button.text;
                                    }

                                    let buttonDescription = {
                                        title: button.text
                                    };

                                    if (postback.startsWith("http")) {
                                        buttonDescription.type = "web_url";
                                        buttonDescription.url = postback;
                                    } else {
                                        buttonDescription.type = "postback";
                                        buttonDescription.payload = postback;
                                    }

                                    buttons.push(buttonDescription);
                                }
                            }

                            if (buttons.length > 0) {
                                card.buttons = buttons;
                            }
                        }

                        if (!facebookMessage.attachment) {
                            facebookMessage.attachment = {type: "template"};
                        }

                        if (!facebookMessage.attachment.payload) {
                            facebookMessage.attachment.payload = {template_type: "generic", elements: []};
                        }

                        facebookMessage.attachment.payload.elements.push(card);
                    });

                    facebookMessages.push(facebookMessage);
                }

                    break;
                //message.type 2 means quick replies message
                case 2: {
                    if (message.replies && message.replies.length > 0) {
                        let facebookMessage = {};

                        facebookMessage.text = message.title ? message.title : 'Choose an item';
                        facebookMessage.quick_replies = [];

                        message.replies.forEach((r) => {
                            facebookMessage.quick_replies.push({
                                content_type: "text",
                                title: r,
                                payload: r
                            });
                        });

                        facebookMessages.push(facebookMessage);
                    }
                }

                    break;
                //message.type 3 means image message
                case 3:

                    if (message.imageUrl) {
                        let facebookMessage = {};

                        // "imageUrl": "http://example.com/image.jpg"
                        facebookMessage.attachment = {type: "image"};
                        facebookMessage.attachment.payload = {url: message.imageUrl};

                        facebookMessages.push(facebookMessage);
                    }

                    break;
                //message.type 4 means custom payload message
                case 4:
                    if (message.payload && message.payload.facebook) {
                        facebookMessages.push(message.payload.facebook);
                    }
                    break;

                default:
                    break;
            }
        }

        return new Promise((resolve, reject) => {
            async.eachSeries(facebookMessages, (msg, callback) => {
                    this.sendFBSenderAction(sender, "typing_on")
                        .then(() => this.sleep(this.messagesDelay))
                        .then(() => this.sendFBMessage(sender, msg))
                        .then(() => callback())
                        .catch(callback);
                },
                (err) => {
                    if (err) {
                        console.error(err);
                        reject(err);
                    } else {
                        console.log('Messages sent');
                        resolve();
                    }
                });
        });

    }

    doTextResponse(sender, responseText) {
        console.log('Response as text message');
        // facebook API limit for text length is 640,
        // so we must split message if needed
        let splittedText = this.splitResponse(responseText);

        async.eachSeries(splittedText, (textPart, callback) => {
            this.sendFBMessage(sender, {text: textPart})
                .then(() => callback())
                .catch(err => callback(err));
        });
    }
 //which webhook event
    getEventText(event) {
        if (event.message) {
            if (event.message.quick_reply && event.message.quick_reply.payload) {
                return event.message.quick_reply.payload;
            }

            if (event.message.text) {
                return event.message.text;
            }
        }

        if (event.postback) {
                if (event.postback.payload && event.postback.referral.ref) {
                    //console.log(event.postback.referral.ref);
                    //return event.postback.referral.ref;

                    //console.log(event.postback.payload);
                    console.log('testing');
                    //return event.postback.payload;
                    return 'testing';
                } else {
                    //console.log(event.postback.payload);
                    //console.log(event.postback.referral.ref);
                    console.log('testing2');
                    //return event.postback.payload;
                    return 'testing2';

                }
            }
        return null;

    }

    processEvent(event) {
        const sender = event.sender.id.toString();
        const text = this.getEventText(event);

        if (text) {

            // Handle a text message from the sender
            if (!this.sessionIds.has(sender)) {
                this.sessionIds.set(sender, uuid.v4());
            }

            console.log("Text", text);
            //send user's text to api.ai service
            let apiaiRequest = this.apiAiService.textRequest(text,
                {
                    sessionId: this.sessionIds.get(sender),
                    originalRequest: {
                        data: event,
                        source: "facebook"
                    }
                });

            //get response from api.ai
            apiaiRequest.on('response', (response) => {
                if (this.isDefined(response.result) && this.isDefined(response.result.fulfillment)) {
                    let responseText = response.result.fulfillment.speech;
                    let responseData = response.result.fulfillment.data;
                    let responseMessages = response.result.fulfillment.messages;

                    let action = response.result.action;

                    if (this.isDefined(responseData) && this.isDefined(responseData.facebook)) {
                        let facebookResponseData = responseData.facebook;
                        this.doDataResponse(sender, facebookResponseData);
                    } else if (this.isDefined(responseMessages) && responseMessages.length > 0) {
                        this.doRichContentResponse(sender, responseMessages);
                    }
                    else if (this.isDefined(responseText)) {
                        this.doTextResponse(sender, responseText);
                    }

                }
            });

            apiaiRequest.on('error', (error) => console.error(error));
            apiaiRequest.end();
        }
    }

    splitResponse(str) {
        if (str.length <= FB_TEXT_LIMIT) {
            return [str];
        }

        return this.chunkString(str, FB_TEXT_LIMIT);
    }

    chunkString(s, len) {
        let curr = len, prev = 0;

        let output = [];

        while (s[curr]) {
            if (s[curr++] == ' ') {
                output.push(s.substring(prev, curr));
                prev = curr;
                curr += len;
            }
            else {
                let currReverse = curr;
                do {
                    if (s.substring(currReverse - 1, currReverse) == ' ') {
                        output.push(s.substring(prev, currReverse));
                        prev = currReverse;
                        curr = currReverse + len;
                        break;
                    }
                    currReverse--;
                } while (currReverse > prev)
            }
        }
        output.push(s.substr(prev));
        return output;
    }

    sendFBMessage(sender, messageData) {
        return new Promise((resolve, reject) => {
            request({
                url: 'https://graph.facebook.com/v2.6/me/messages',
                qs: {access_token: FB_PAGE_ACCESS_TOKEN},
                method: 'POST',
                json: {
                    recipient: {id: sender},
                    message: messageData
                }
            }, (error, response) => {
                if (error) {
                    console.log('Error sending message: ', error);
                    reject(error);
                } else if (response.body.error) {
                    console.log('Error: ', response.body.error);
                    reject(new Error(response.body.error));
                }

                resolve();
            });
        });
    }

    sendFBSenderAction(sender, action) {
        return new Promise((resolve, reject) => {
            request({
                url: 'https://graph.facebook.com/v2.6/me/messages',
                qs: {access_token: FB_PAGE_ACCESS_TOKEN},
                method: 'POST',
                json: {
                    recipient: {id: sender},
                    sender_action: action
                }
            }, (error, response) => {
                if (error) {
                    console.error('Error sending action: ', error);
                    reject(error);
                } else if (response.body.error) {
                    console.error('Error: ', response.body.error);
                    reject(new Error(response.body.error));
                }

                resolve();
            });
        });
    }

    doSubscribeRequest() {
        request({
                method: 'POST',
                uri: "https://graph.facebook.com/v2.6/me/subscribed_apps?access_token=" + FB_PAGE_ACCESS_TOKEN
            },
            (error, response, body) => {
                if (error) {
                    console.error('Error while subscription: ', error);
                } else {
                    console.log('Subscription result: ', response.body);
                }
            });
    }

    isDefined(obj) {
        if (typeof obj == 'undefined') {
            return false;
        }

        if (!obj) {
            return false;
        }

        return obj != null;
    }

    sleep(delay) {
        return new Promise((resolve, reject) => {
            setTimeout(() => resolve(), delay);
        });
    }

}

let facebookBot = new FacebookBot();

const app = express();

app.use(bodyParser.text({type: 'application/json'}));

app.get('/webhook/', (req, res) => {
    if (req.query['hub.verify_token'] == FB_VERIFY_TOKEN) {
        res.send(req.query['hub.challenge']);

        setTimeout(() => {
            facebookBot.doSubscribeRequest();
        }, 3000);
    } else {
        res.send('Error, wrong validation token');
    }
});

app.post('/webhook/', (req, res) => {
    try {
        const data = JSONbig.parse(req.body);

        if (data.entry) {
            let entries = data.entry;
            entries.forEach((entry) => {
                let messaging_events = entry.messaging;
                if (messaging_events) {
                    messaging_events.forEach((event) => {
                    if (event.message && !event.message.is_echo ||
                            event.postback && event.postback.payload) {
                            facebookBot.processEvent(event);
                        }
                    });
                }
            });
        }

        return res.status(200).json({
            status: "ok"
        });
    } catch (err) {
        return res.status(400).json({
            status: "error",
            error: err
        });
    }

});

app.listen(REST_PORT, () => {
    console.log('Rest service ready on port ' + REST_PORT);
});

facebookBot.doSubscribeRequest();
<commit_msg>Update app.js<commit_after>'use strict';

const apiai = require('apiai');
const express = require('express');
const bodyParser = require('body-parser');
const uuid = require('node-uuid');
const request = require('request');
const JSONbig = require('json-bigint');
const async = require('async');

const REST_PORT = (process.env.PORT || 5000);
const APIAI_ACCESS_TOKEN = process.env.APIAI_ACCESS_TOKEN;
const APIAI_LANG = process.env.APIAI_LANG || 'en';
const FB_VERIFY_TOKEN = process.env.FB_VERIFY_TOKEN;
const FB_PAGE_ACCESS_TOKEN = process.env.FB_PAGE_ACCESS_TOKEN;
const FB_TEXT_LIMIT = 640;
var barbrad = 'true';

class FacebookBot {
    constructor() {
        this.apiAiService = apiai(APIAI_ACCESS_TOKEN, {language: APIAI_LANG, requestSource: "fb"});
        this.sessionIds = new Map();
        this.messagesDelay = 200;
    }

    doDataResponse(sender, facebookResponseData) {
        if (!Array.isArray(facebookResponseData)) {
            console.log('Response as formatted message');
            this.sendFBMessage(sender, facebookResponseData)
                .catch(err => console.error(err));
        } else {
            async.eachSeries(facebookResponseData, (facebookMessage, callback) => {
                if (facebookMessage.sender_action) {
                    console.log('Response as sender action');
                    this.sendFBSenderAction(sender, facebookMessage.sender_action)
                        .then(() => callback())
                        .catch(err => callback(err));
                }
                else {
                    console.log('Response as formatted message');
                    this.sendFBMessage(sender, facebookMessage)
                        .then(() => callback())
                        .catch(err => callback(err));
                }
            }, (err) => {
                if (err) {
                    console.error(err);
                } else {
                    console.log('Data response completed');
                }
            });
        }
    }

    doRichContentResponse(sender, messages) {
        let facebookMessages = []; // array with result messages

        for (let messageIndex = 0; messageIndex < messages.length; messageIndex++) {
            let message = messages[messageIndex];

            switch (message.type) {
                //message.type 0 means text message
                case 0:
                    // speech: ["hi"]
                    // we have to get value from fulfillment.speech, because of here is raw speech
                    if (message.speech) {

                        let splittedText = this.splitResponse(message.speech);

                        splittedText.forEach(s => {
                            facebookMessages.push({text: s});
                        });
                    }

                    break;
                //message.type 1 means card message
                case 1: {
                    let carousel = [message];

                    for (messageIndex++; messageIndex < messages.length; messageIndex++) {
                        if (messages[messageIndex].type == 1) {
                            carousel.push(messages[messageIndex]);
                        } else {
                            messageIndex--;
                            break;
                        }
                    }

                    let facebookMessage = {};
                    carousel.forEach((c) => {
                        // buttons: [ {text: "hi", postback: "postback"} ], imageUrl: "", title: "", subtitle: ""

                        let card = {};

                        card.title = c.title;
                        card.image_url = c.imageUrl;
                        if (this.isDefined(c.subtitle)) {
                            card.subtitle = c.subtitle;
                        }
                        //If button is involved in.
                        if (c.buttons.length > 0) {
                            let buttons = [];
                            for (let buttonIndex = 0; buttonIndex < c.buttons.length; buttonIndex++) {
                                let button = c.buttons[buttonIndex];

                                if (button.text) {
                                    let postback = button.postback;
                                    if (!postback) {
                                        postback = button.text;
                                    }

                                    let buttonDescription = {
                                        title: button.text
                                    };

                                    if (postback.startsWith("http")) {
                                        buttonDescription.type = "web_url";
                                        buttonDescription.url = postback;
                                    } else {
                                        buttonDescription.type = "postback";
                                        buttonDescription.payload = postback;
                                    }

                                    buttons.push(buttonDescription);
                                }
                            }

                            if (buttons.length > 0) {
                                card.buttons = buttons;
                            }
                        }

                        if (!facebookMessage.attachment) {
                            facebookMessage.attachment = {type: "template"};
                        }

                        if (!facebookMessage.attachment.payload) {
                            facebookMessage.attachment.payload = {template_type: "generic", elements: []};
                        }

                        facebookMessage.attachment.payload.elements.push(card);
                    });

                    facebookMessages.push(facebookMessage);
                }

                    break;
                //message.type 2 means quick replies message
                case 2: {
                    if (message.replies && message.replies.length > 0) {
                        let facebookMessage = {};

                        facebookMessage.text = message.title ? message.title : 'Choose an item';
                        facebookMessage.quick_replies = [];

                        message.replies.forEach((r) => {
                            facebookMessage.quick_replies.push({
                                content_type: "text",
                                title: r,
                                payload: r
                            });
                        });

                        facebookMessages.push(facebookMessage);
                    }
                }

                    break;
                //message.type 3 means image message
                case 3:

                    if (message.imageUrl) {
                        let facebookMessage = {};

                        // "imageUrl": "http://example.com/image.jpg"
                        facebookMessage.attachment = {type: "image"};
                        facebookMessage.attachment.payload = {url: message.imageUrl};

                        facebookMessages.push(facebookMessage);
                    }

                    break;
                //message.type 4 means custom payload message
                case 4:
                    if (message.payload && message.payload.facebook) {
                        facebookMessages.push(message.payload.facebook);
                    }
                    break;

                default:
                    break;
            }
        }

        return new Promise((resolve, reject) => {
            async.eachSeries(facebookMessages, (msg, callback) => {
                    this.sendFBSenderAction(sender, "typing_on")
                        .then(() => this.sleep(this.messagesDelay))
                        .then(() => this.sendFBMessage(sender, msg))
                        .then(() => callback())
                        .catch(callback);
                },
                (err) => {
                    if (err) {
                        console.error(err);
                        reject(err);
                    } else {
                        console.log('Messages sent');
                        resolve();
                    }
                });
        });

    }

    doTextResponse(sender, responseText) {
        console.log('Response as text message');
        // facebook API limit for text length is 640,
        // so we must split message if needed
        let splittedText = this.splitResponse(responseText);

        async.eachSeries(splittedText, (textPart, callback) => {
            this.sendFBMessage(sender, {text: textPart})
                .then(() => callback())
                .catch(err => callback(err));
        });
    }
 //which webhook event
    getEventText(event) {
        if (event.message) {
            if (event.message.quick_reply && event.message.quick_reply.payload) {
                return event.message.quick_reply.payload;
            }

            if (event.message.text) {
                return event.message.text;
            }
        }

        if (event.postback) {
                if (event.postback.payload) {
                    //console.log(event.postback.referral.ref);
                    //return event.postback.referral.ref;

                    //console.log(event.postback.payload);
                    console.log('testing');
                    //return event.postback.payload;
                    return 'testing';
                } else if (event.postback.referral.ref) {
                    //console.log(event.postback.payload);
                    //console.log(event.postback.referral.ref);
                    console.log('testing2');
                    //return event.postback.payload;
                    return 'testing2';

                }

              else {
                   return null;
              }

            }
        return null;

    }

    processEvent(event) {
        const sender = event.sender.id.toString();
        const text = this.getEventText(event);

        if (text) {

            // Handle a text message from the sender
            if (!this.sessionIds.has(sender)) {
                this.sessionIds.set(sender, uuid.v4());
            }

            console.log("Text", text);
            //send user's text to api.ai service
            let apiaiRequest = this.apiAiService.textRequest(text,
                {
                    sessionId: this.sessionIds.get(sender),
                    originalRequest: {
                        data: event,
                        source: "facebook"
                    }
                });

            //get response from api.ai
            apiaiRequest.on('response', (response) => {
                if (this.isDefined(response.result) && this.isDefined(response.result.fulfillment)) {
                    let responseText = response.result.fulfillment.speech;
                    let responseData = response.result.fulfillment.data;
                    let responseMessages = response.result.fulfillment.messages;

                    let action = response.result.action;

                    if (this.isDefined(responseData) && this.isDefined(responseData.facebook)) {
                        let facebookResponseData = responseData.facebook;
                        this.doDataResponse(sender, facebookResponseData);
                    } else if (this.isDefined(responseMessages) && responseMessages.length > 0) {
                        this.doRichContentResponse(sender, responseMessages);
                    }
                    else if (this.isDefined(responseText)) {
                        this.doTextResponse(sender, responseText);
                    }

                }
            });

            apiaiRequest.on('error', (error) => console.error(error));
            apiaiRequest.end();
        }
    }

    splitResponse(str) {
        if (str.length <= FB_TEXT_LIMIT) {
            return [str];
        }

        return this.chunkString(str, FB_TEXT_LIMIT);
    }

    chunkString(s, len) {
        let curr = len, prev = 0;

        let output = [];

        while (s[curr]) {
            if (s[curr++] == ' ') {
                output.push(s.substring(prev, curr));
                prev = curr;
                curr += len;
            }
            else {
                let currReverse = curr;
                do {
                    if (s.substring(currReverse - 1, currReverse) == ' ') {
                        output.push(s.substring(prev, currReverse));
                        prev = currReverse;
                        curr = currReverse + len;
                        break;
                    }
                    currReverse--;
                } while (currReverse > prev)
            }
        }
        output.push(s.substr(prev));
        return output;
    }

    sendFBMessage(sender, messageData) {
        return new Promise((resolve, reject) => {
            request({
                url: 'https://graph.facebook.com/v2.6/me/messages',
                qs: {access_token: FB_PAGE_ACCESS_TOKEN},
                method: 'POST',
                json: {
                    recipient: {id: sender},
                    message: messageData
                }
            }, (error, response) => {
                if (error) {
                    console.log('Error sending message: ', error);
                    reject(error);
                } else if (response.body.error) {
                    console.log('Error: ', response.body.error);
                    reject(new Error(response.body.error));
                }

                resolve();
            });
        });
    }

    sendFBSenderAction(sender, action) {
        return new Promise((resolve, reject) => {
            request({
                url: 'https://graph.facebook.com/v2.6/me/messages',
                qs: {access_token: FB_PAGE_ACCESS_TOKEN},
                method: 'POST',
                json: {
                    recipient: {id: sender},
                    sender_action: action
                }
            }, (error, response) => {
                if (error) {
                    console.error('Error sending action: ', error);
                    reject(error);
                } else if (response.body.error) {
                    console.error('Error: ', response.body.error);
                    reject(new Error(response.body.error));
                }

                resolve();
            });
        });
    }

    doSubscribeRequest() {
        request({
                method: 'POST',
                uri: "https://graph.facebook.com/v2.6/me/subscribed_apps?access_token=" + FB_PAGE_ACCESS_TOKEN
            },
            (error, response, body) => {
                if (error) {
                    console.error('Error while subscription: ', error);
                } else {
                    console.log('Subscription result: ', response.body);
                }
            });
    }

    isDefined(obj) {
        if (typeof obj == 'undefined') {
            return false;
        }

        if (!obj) {
            return false;
        }

        return obj != null;
    }

    sleep(delay) {
        return new Promise((resolve, reject) => {
            setTimeout(() => resolve(), delay);
        });
    }

}

let facebookBot = new FacebookBot();

const app = express();

app.use(bodyParser.text({type: 'application/json'}));

app.get('/webhook/', (req, res) => {
    if (req.query['hub.verify_token'] == FB_VERIFY_TOKEN) {
        res.send(req.query['hub.challenge']);

        setTimeout(() => {
            facebookBot.doSubscribeRequest();
        }, 3000);
    } else {
        res.send('Error, wrong validation token');
    }
});

app.post('/webhook/', (req, res) => {
    try {
        const data = JSONbig.parse(req.body);

        if (data.entry) {
            let entries = data.entry;
            entries.forEach((entry) => {
                let messaging_events = entry.messaging;
                if (messaging_events) {
                    messaging_events.forEach((event) => {
                    if (event.message && !event.message.is_echo ||
                            event.postback && event.postback.payload) {
                            facebookBot.processEvent(event);
                        }
                    });
                }
            });
        }

        return res.status(200).json({
            status: "ok"
        });
    } catch (err) {
        return res.status(400).json({
            status: "error",
            error: err
        });
    }

});

app.listen(REST_PORT, () => {
    console.log('Rest service ready on port ' + REST_PORT);
});

facebookBot.doSubscribeRequest();
<|endoftext|>


<commit_before>/**
 * ##dispatcher##
 * Behavior modifier for event dispatching.
 * @param {Object} target - the object to apply the methods to.
 * @param {Object} scope - the object that the methods will be applied from
 * @param {object} map - custom names of what methods to map from scope. such as _$emit_ and _$broadcast_.
 */

define('dispatcher', ['apply', 'isFunction'], function (apply, isFunction) {

    function Event(type) {
        this.type = type;
        this.defaultPrevented = false;
        this.propagationStopped = false;
        this.immediatePropagationStopped = false;
    }
    Event.prototype.preventDefault = function() {
        this.defaultPrevented = true;
    };
    Event.prototype.stopPropagation = function() {
        this.propagationStopped = true;
    };
    Event.prototype.stopImmediatePropagation = function() {
        this.immediatePropagationStopped = true;
    };
    Event.prototype.toString = function() {
        return this.type;
    };

    function validateEvent(e) {
        if (!e) {
            throw Error('event cannot be undefined');
        }
    }

    var dispatcher = function (target, scope, map) {
        // if you try to make the same item a dispatcher, it will just do nothing.
        if (target && target.on && target.on.dispatcher) {
            return target;// it is already a dispatcher.
        }
        target = target || {};
        var listeners = {};

        /**
         * ###off###
         * removeEventListener from this object instance. given the event listened for and the callback reference.
         * @param event
         * @param callback
         */
        function off(event, callback) {
            validateEvent(event);
            var index, list;
            list = listeners[event];
            if (list) {
                if (callback) {
                    index = list.indexOf(callback);
                    if (index !== -1) {
                        list.splice(index, 1);
                    }
                } else {
                    list.length = 0;
                }
            }
        }

        /**
         * ###on###
         * addEventListener to this object instance.
         * @param {String} event
         * @param {Function} callback
         * @returns {Function} - removeListener or unwatch function.
         */
        function on(event, callback) {
            if(isFunction(callback)) {
                validateEvent(event);
                listeners[event] = listeners[event] || [];
                listeners[event].push(callback);
                return function () {
                    off(event, callback);
                };
            }
        }

        /**
         * ###once###
         * addEventListener that gets remove with the first call.
         * @param event
         * @param callback
         * @returns {Function} - removeListener or unwatch function.
         */
        function once(event, callback) {
            if(isFunction(callback)) {
                validateEvent(event);
                function fn() {
                    off(event, fn);
                    apply(callback, scope || target, arguments);
                }

                return on(event, fn);
            }
        }

        /**
         * ###getListeners###
         * get the listeners from the dispatcher.
         * @param {String} event
         * @param {Boolean} strict
         * @returns {*}
         */
        function getListeners(event, strict) {
            validateEvent(event);
            var list, a = '*';
            if (event || strict) {
                list = [];
                if (listeners[a]) {
                    list = listeners[a].concat(list);
                }
                if (listeners[event]) {
                    list = listeners[event].concat(list);
                }
                return list;
            }
            return listeners;
        }

        function removeAllListeners() {
            listeners = {};
        }

        /**
         * ###fire###
         * fire the callback with arguments.
         * @param {Function} callback
         * @param {Array} args
         * @returns {*}
         */
        function fire(callback, args) {
            return callback && apply(callback, target, args);
        }

        /**
         * ###dispatch###
         * fire the event and any arguments that are passed.
         * @param {String} event
         */
        function dispatch(event) {
            validateEvent(event);
            var list = getListeners(event, true), len = list.length, i, event = typeof event === 'object' ? event : new Event(event);
            if (len) {
                arguments[0] = event;
                for (i = 0; i < len; i += 1) {
                    if (!event.immediatePropagationStopped) {
                        fire(list[i], arguments);
                    }
                }
            }
            return event;
        }

        if (scope && map) {
            target.on = scope[map.on] && scope[map.on].bind(scope);
            target.off = scope[map.off] && scope[map.off].bind(scope);
            target.once = scope[map.once] && scope[map.once].bind(scope);
            target.dispatch = target.fire = scope[map.dispatch].bind(scope);
        } else {
            target.on = on;
            target.off = off;
            target.once = once;
            target.dispatch = target.fire = dispatch;
        }
        target.getListeners = getListeners;
        target.removeAllListeners = removeAllListeners;

        return target;
    };

    return dispatcher;

});
<commit_msg>dispatcher on method has dispatcher flag to set as recognizable<commit_after>/**
 * ##dispatcher##
 * Behavior modifier for event dispatching.
 * @param {Object} target - the object to apply the methods to.
 * @param {Object} scope - the object that the methods will be applied from
 * @param {object} map - custom names of what methods to map from scope. such as _$emit_ and _$broadcast_.
 */

define('dispatcher', ['apply', 'isFunction'], function (apply, isFunction) {

    function Event(type) {
        this.type = type;
        this.defaultPrevented = false;
        this.propagationStopped = false;
        this.immediatePropagationStopped = false;
    }
    Event.prototype.preventDefault = function() {
        this.defaultPrevented = true;
    };
    Event.prototype.stopPropagation = function() {
        this.propagationStopped = true;
    };
    Event.prototype.stopImmediatePropagation = function() {
        this.immediatePropagationStopped = true;
    };
    Event.prototype.toString = function() {
        return this.type;
    };

    function validateEvent(e) {
        if (!e) {
            throw Error('event cannot be undefined');
        }
    }

    var dispatcher = function (target, scope, map) {
        // if you try to make the same item a dispatcher, it will just do nothing.
        if (target && target.on && target.on.dispatcher) {
            return target;// it is already a dispatcher.
        }
        target = target || {};
        var listeners = {};

        /**
         * ###off###
         * removeEventListener from this object instance. given the event listened for and the callback reference.
         * @param event
         * @param callback
         */
        function off(event, callback) {
            validateEvent(event);
            var index, list;
            list = listeners[event];
            if (list) {
                if (callback) {
                    index = list.indexOf(callback);
                    if (index !== -1) {
                        list.splice(index, 1);
                    }
                } else {
                    list.length = 0;
                }
            }
        }

        /**
         * ###on###
         * addEventListener to this object instance.
         * @param {String} event
         * @param {Function} callback
         * @returns {Function} - removeListener or unwatch function.
         */
        function on(event, callback) {
            if(isFunction(callback)) {
                validateEvent(event);
                listeners[event] = listeners[event] || [];
                listeners[event].push(callback);
                return function () {
                    off(event, callback);
                };
            }
        }
        on.dispatcher = true;

        /**
         * ###once###
         * addEventListener that gets remove with the first call.
         * @param event
         * @param callback
         * @returns {Function} - removeListener or unwatch function.
         */
        function once(event, callback) {
            if(isFunction(callback)) {
                validateEvent(event);
                function fn() {
                    off(event, fn);
                    apply(callback, scope || target, arguments);
                }

                return on(event, fn);
            }
        }

        /**
         * ###getListeners###
         * get the listeners from the dispatcher.
         * @param {String} event
         * @param {Boolean} strict
         * @returns {*}
         */
        function getListeners(event, strict) {
            validateEvent(event);
            var list, a = '*';
            if (event || strict) {
                list = [];
                if (listeners[a]) {
                    list = listeners[a].concat(list);
                }
                if (listeners[event]) {
                    list = listeners[event].concat(list);
                }
                return list;
            }
            return listeners;
        }

        function removeAllListeners() {
            listeners = {};
        }

        /**
         * ###fire###
         * fire the callback with arguments.
         * @param {Function} callback
         * @param {Array} args
         * @returns {*}
         */
        function fire(callback, args) {
            return callback && apply(callback, target, args);
        }

        /**
         * ###dispatch###
         * fire the event and any arguments that are passed.
         * @param {String} event
         */
        function dispatch(event) {
            validateEvent(event);
            var list = getListeners(event, true), len = list.length, i, event = typeof event === 'object' ? event : new Event(event);
            if (len) {
                arguments[0] = event;
                for (i = 0; i < len; i += 1) {
                    if (!event.immediatePropagationStopped) {
                        fire(list[i], arguments);
                    }
                }
            }
            return event;
        }

        if (scope && map) {
            target.on = scope[map.on] && scope[map.on].bind(scope);
            target.off = scope[map.off] && scope[map.off].bind(scope);
            target.once = scope[map.once] && scope[map.once].bind(scope);
            target.dispatch = target.fire = scope[map.dispatch].bind(scope);
        } else {
            target.on = on;
            target.off = off;
            target.once = once;
            target.dispatch = target.fire = dispatch;
        }
        target.getListeners = getListeners;
        target.removeAllListeners = removeAllListeners;

        return target;
    };

    return dispatcher;

});
<|endoftext|>


<commit_before>'use strict';

const apiai = require('apiai');
const express = require('express');
const bodyParser = require('body-parser');
const uuid = require('node-uuid');
const request = require('request');
const JSONbig = require('json-bigint');
const async = require('async');

const REST_PORT = (process.env.PORT || 5000);
const APIAI_ACCESS_TOKEN = process.env.APIAI_ACCESS_TOKEN;
const APIAI_LANG = process.env.APIAI_LANG || 'en';
const FB_VERIFY_TOKEN = process.env.FB_VERIFY_TOKEN;
const FB_PAGE_ACCESS_TOKEN = process.env.FB_PAGE_ACCESS_TOKEN;

const apiAiService = apiai(APIAI_ACCESS_TOKEN, {language: APIAI_LANG, requestSource: "fb"});
const sessionIds = new Map();

function processEvent(event) {
    var sender = event.sender.id.toString();

    if ((event.message && event.message.text) || (event.postback && event.postback.payload)) {
        var text = event.message ? event.message.text : event.postback.payload;
        // Handle a text message from this sender

        if (!sessionIds.has(sender)) {
            sessionIds.set(sender, uuid.v1());
        }

        console.log("Text", text);

        let apiaiRequest = apiAiService.textRequest(text,
            {
                sessionId: sessionIds.get(sender)
            });

        apiaiRequest.on('response', (response) => {
            if (isDefined(response.result)) {
                //asd
                let responseText = response.result.fulfillment.speech;
                let responseData = response.result.fulfillment.data;
                let action = response.result.action;
                /*console.log(responseText);
                console.log(responseData);
                console.log(action);*/
                if (isDefined(responseData) && isDefined(responseData.facebook)) {
                    if (!Array.isArray(responseData.facebook)) {
                        try {
                            console.log('Response as formatted message');
                            sendFBMessage(sender, responseData.facebook);
                        } catch (err) {
                            sendFBMessage(sender, {text: err.message});
                        }
                    } else {
                        responseData.facebook.forEach((facebookMessage) => {
                            try {
                                if (facebookMessage.sender_action) {
                                    console.log('Response as sender action');
                                    sendFBSenderAction(sender, facebookMessage.sender_action);
                                }
                                else {
                                    console.log('Response as formatted message');
                                    sendFBMessage(sender, facebookMessage);
                                }
                            } catch (err) {
                                sendFBMessage(sender, {text: err.message});
                            }
                        });
                    }
                //} else if (isDefined(responseText)) {
                } else if (isDefined(action) && isDefined(responseText)) {
                    console.log('Response as text message');
                    // facebook API limit for text length is 320,
                    // so we must split message if needed
                    var splittedText = splitResponse(responseText);
                    /*switch (action){
                        case 'show_prod':
                            console.log('generic');
                            async.eachSeries(splittedText, (textPart, callback) => {
                                sendFBMessage(sender, {text: textPart}, callback);
                            });
                            sendFBMessage(sender, generic_message, null);
                            break;
                        default:
                            console.log('default');
                            async.eachSeries(splittedText, (textPart, callback) => {
                                sendFBMessage(sender, {text: textPart}, callback);
                            });
                    }*/
                    async.eachSeries(splittedText, (textPart, callback) => {
                        sendFBMessage(sender, {text: textPart}, callback);
                    });
                }

            }
        });

        apiaiRequest.on('error', (error) => console.error(error));
        apiaiRequest.end();
    }
}

function splitResponse(str) {
    if (str.length <= 320) {
        return [str];
    }

    return chunkString(str, 300);
}

function chunkString(s, len) {
    var curr = len, prev = 0;

    var output = [];

    while (s[curr]) {
        if (s[curr++] == ' ') {
            output.push(s.substring(prev, curr));
            prev = curr;
            curr += len;
        }
        else {
            var currReverse = curr;
            do {
                if (s.substring(currReverse - 1, currReverse) == ' ') {
                    output.push(s.substring(prev, currReverse));
                    prev = currReverse;
                    curr = currReverse + len;
                    break;
                }
                currReverse--;
            } while (currReverse > prev)
        }
    }
    output.push(s.substr(prev));
    //console.log(output);
    //output = ['Length of param message[text] must be less than or equal to 320'];
    return output;
}

/*const generic_message = {
    attachment: {
        type: "template",
        payload: {
            template_type: "generic",
            elements: [{
                title: "rift",
                subtitle: "Next-generation virtual reality",
                item_url: "https://www.oculus.com/en-us/rift/",
                image_url: "http://messengerdemo.parseapp.com/img/rift.png",
                buttons: [{
                    type: "web_url",
                    url: "https://www.oculus.com/en-us/rift/",
                    title: "Open Web URL"
                }, {
                    type: "postback",
                    title: "Call Postback",
                    payload: "Payload for first bubble"
                }]
            }, {
                title: "touch",
                subtitle: "Your Hands, Now in VR",
                item_url: "https://www.oculus.com/en-us/touch/",
                image_url: "http://messengerdemo.parseapp.com/img/touch.png",
                buttons: [{
                    type: "web_url",
                    url: "https://www.oculus.com/en-us/touch/",
                    title: "Open Web URL"
                }, {
                    type: "postback",
                    title: "Call Postback",
                    payload: "Payload for second bubble"
                }]
            }]
        }
    }
};*/

function sendFBMessage(sender, messageData, callback) {
    //console.log(sender);
    request({
        url: 'https://graph.facebook.com/v2.6/me/messages',
        qs: {access_token: FB_PAGE_ACCESS_TOKEN},
        method: 'POST',
        json: {
            recipient: {id: sender},
            message: messageData
            //message: generic_message
        }
    }, (error, response, body) => {
        if (error) {
            console.log('Error sending message: ', error);
        } else if (response.body.error) {
            console.log('Error: ', response.body.error);
        }

        if (callback) {
            callback();
        }
    });
}

function sendFBSenderAction(sender, action, callback) {
    setTimeout(() => {
        request({
            url: 'https://graph.facebook.com/v2.6/me/messages',
            qs: {access_token: FB_PAGE_ACCESS_TOKEN},
            method: 'POST',
            json: {
                recipient: {id: sender},
                sender_action: action
            }
        }, (error, response, body) => {
            if (error) {
                console.log('Error sending action: ', error);
            } else if (response.body.error) {
                console.log('Error: ', response.body.error);
            }
            if (callback) {
                callback();
            }
        });
    }, 1000);
}

function doSubscribeRequest() {
    request({
            method: 'POST',
            uri: "https://graph.facebook.com/v2.6/me/subscribed_apps?access_token=" + FB_PAGE_ACCESS_TOKEN
        },
        (error, response, body) => {
            if (error) {
                console.error('Error while subscription: ', error);
            } else {
                console.log('Subscription result: ', response.body);
            }
        });
}

function isDefined(obj) {
    if (typeof obj == 'undefined') {
        return false;
    }

    if (!obj) {
        return false;
    }

    return obj != null;
}

const app = express();

app.use(bodyParser.text({type: 'application/json'}));

app.get('/webhook/', (req, res) => {
    if (req.query['hub.verify_token'] == FB_VERIFY_TOKEN) {
        res.send(req.query['hub.challenge']);

        setTimeout(() => {
            doSubscribeRequest();
        }, 3000);
    } else {
        res.send('Error, wrong validation token');
    }
});

app.post('/webhook/', (req, res) => {
    try {
        var data = JSONbig.parse(req.body);
        var asd = data;
        //console.log(asd);
        if (data.entry) {
            let entries = data.entry;
            entries.forEach((entry) => {
                let messaging_events = entry.messaging;
                if (messaging_events) {
                    messaging_events.forEach((event) => {
                        //console.log(event);
                        if (event.message && !event.message.is_echo ||
                            event.postback && event.postback.payload) {
                            processEvent(event);
                        }
                    });
                }
            });
        }

        return res.status(200).json({
            status: "ok"
        });
    } catch (err) {
        return res.status(400).json({
            status: "error",
            error: err
        });
    }

});

app.post('/webhook_apiai/', (req, res) => {

    //var weather_query = new Boolean(false);
    var weather_query = 'false';

    const generic_message = {
        attachment: {
            type: "template",
            payload: {
                template_type: "generic",
                elements: [{
                    title: "Fresh Pizza",
                    subtitle: "Be carefull and don't eat your fingers!!!",
                    item_url: "https://en.wikipedia.org/wiki/Pizza",
                    //image_url: "http://www.cbc.ca/inthekitchen/assets_c/2012/11/MargheritaPizza21-thumb-596x350-247022.jpg",
                    buttons: [{
                        type: "web_url",
                        url: "https://en.wikipedia.org/wiki/Pizza",
                        title: "Open Web URL"
                    }/*, {
                     type: "postback",
                     title: "Call Postback",
                     payload: "Payload for first bubble"
                     }*/]
                }]
            }
        }
    };

    try {
        var data = JSONbig.parse(req.body);
        //console.log(data);
        switch(data.result.action){
            case 'show_prod':
                switch(data.result.parameters.pizza_type){
                    case 'Margherita':
                        generic_message.attachment.payload.elements[0].title = data.result.parameters.pizza_type;
                        generic_message.attachment.payload.elements[0].image_url = "http://www.cbc.ca/inthekitchen/assets_c/2012/11/MargheritaPizza21-thumb-596x350-247022.jpg";
                }
            case 'show_weather':
                weather_query = 'true';
                //console.log(data.result.parameters['geo-city']);
                console.log(isDefined(data.result.parameters['geo-city']));
                if(data.result.parameters['geo-city']){
                    var city = data.result.parameters['geo-city'];
                    var base_url = "https://query.yahooapis.com/v1/public/yql?" + "q=select+%2A+from+weather.forecast+where+woeid+in+%28select+woeid+from+geo.places%281%29+where+text%3D%27"+city+"%27%29" + "&format=json";
                    request({
                        url: base_url,
                        method: 'GET', //Specify the method
                    }, function(error, response, body){
                        if(error) {
                            console.log(error);
                            return res.status(400).json({
                                status: "error",
                                error: err
                            });
                        } else {
                            var query = JSON.parse(body).query;
                            var results = query.results;
                            var channel = results.channel;
                            var item = channel.item;
                            var location = channel.location;
                            var units = channel.units;
                            var condition = item.condition;
                            //console.log(channel)
                            var string = "Today in " + location.city + ": " + condition.text + ", the temperature is " + condition.temp + " " + units.temperature
                            generic_message.attachment.payload.elements[0].title = 'Weather in' + city;
                            generic_message.attachment.payload.elements[0].subtitle = string;
                            generic_message.attachment.payload.elements[0].item_url = channel.link;
                            generic_message.attachment.payload.elements[0].image_url = channel.image.url;
                            generic_message.attachment.payload.elements[0].buttons[0].url = channel.link;
                            return res.status(200).json({
                                data: {
                                    facebook: generic_message
                                }
                            })
                        }
                    });
                }
                weather_query = 'false';
                break;
        }

        if (weather_query != 'true'){
            return res.status(200).json({
                data: {
                    facebook: generic_message
                }
            })
        } else {
            return res.status(200).json({
                data: {
                    facebook: {test: 'error'}
                }
            })}
    } catch (err) {
        return res.status(400).json({
            status: "error",
            error: err
        });
    }
});

app.listen(REST_PORT, () => {
    console.log('Rest service ready on port ' + REST_PORT);
});

doSubscribeRequest();
<commit_msg>'webhook_test'<commit_after>'use strict';

const apiai = require('apiai');
const express = require('express');
const bodyParser = require('body-parser');
const uuid = require('node-uuid');
const request = require('request');
const JSONbig = require('json-bigint');
const async = require('async');

const REST_PORT = (process.env.PORT || 5000);
const APIAI_ACCESS_TOKEN = process.env.APIAI_ACCESS_TOKEN;
const APIAI_LANG = process.env.APIAI_LANG || 'en';
const FB_VERIFY_TOKEN = process.env.FB_VERIFY_TOKEN;
const FB_PAGE_ACCESS_TOKEN = process.env.FB_PAGE_ACCESS_TOKEN;

const apiAiService = apiai(APIAI_ACCESS_TOKEN, {language: APIAI_LANG, requestSource: "fb"});
const sessionIds = new Map();

function processEvent(event) {
    var sender = event.sender.id.toString();

    if ((event.message && event.message.text) || (event.postback && event.postback.payload)) {
        var text = event.message ? event.message.text : event.postback.payload;
        // Handle a text message from this sender

        if (!sessionIds.has(sender)) {
            sessionIds.set(sender, uuid.v1());
        }

        console.log("Text", text);

        let apiaiRequest = apiAiService.textRequest(text,
            {
                sessionId: sessionIds.get(sender)
            });

        apiaiRequest.on('response', (response) => {
            if (isDefined(response.result)) {
                //asd
                let responseText = response.result.fulfillment.speech;
                let responseData = response.result.fulfillment.data;
                let action = response.result.action;
                /*console.log(responseText);
                console.log(responseData);
                console.log(action);*/
                if (isDefined(responseData) && isDefined(responseData.facebook)) {
                    if (!Array.isArray(responseData.facebook)) {
                        try {
                            console.log('Response as formatted message');
                            sendFBMessage(sender, responseData.facebook);
                        } catch (err) {
                            sendFBMessage(sender, {text: err.message});
                        }
                    } else {
                        responseData.facebook.forEach((facebookMessage) => {
                            try {
                                if (facebookMessage.sender_action) {
                                    console.log('Response as sender action');
                                    sendFBSenderAction(sender, facebookMessage.sender_action);
                                }
                                else {
                                    console.log('Response as formatted message');
                                    sendFBMessage(sender, facebookMessage);
                                }
                            } catch (err) {
                                sendFBMessage(sender, {text: err.message});
                            }
                        });
                    }
                //} else if (isDefined(responseText)) {
                } else if (isDefined(action) && isDefined(responseText)) {
                    console.log('Response as text message');
                    // facebook API limit for text length is 320,
                    // so we must split message if needed
                    var splittedText = splitResponse(responseText);
                    /*switch (action){
                        case 'show_prod':
                            console.log('generic');
                            async.eachSeries(splittedText, (textPart, callback) => {
                                sendFBMessage(sender, {text: textPart}, callback);
                            });
                            sendFBMessage(sender, generic_message, null);
                            break;
                        default:
                            console.log('default');
                            async.eachSeries(splittedText, (textPart, callback) => {
                                sendFBMessage(sender, {text: textPart}, callback);
                            });
                    }*/
                    async.eachSeries(splittedText, (textPart, callback) => {
                        sendFBMessage(sender, {text: textPart}, callback);
                    });
                }

            }
        });

        apiaiRequest.on('error', (error) => console.error(error));
        apiaiRequest.end();
    }
}

function splitResponse(str) {
    if (str.length <= 320) {
        return [str];
    }

    return chunkString(str, 300);
}

function chunkString(s, len) {
    var curr = len, prev = 0;

    var output = [];

    while (s[curr]) {
        if (s[curr++] == ' ') {
            output.push(s.substring(prev, curr));
            prev = curr;
            curr += len;
        }
        else {
            var currReverse = curr;
            do {
                if (s.substring(currReverse - 1, currReverse) == ' ') {
                    output.push(s.substring(prev, currReverse));
                    prev = currReverse;
                    curr = currReverse + len;
                    break;
                }
                currReverse--;
            } while (currReverse > prev)
        }
    }
    output.push(s.substr(prev));
    //console.log(output);
    //output = ['Length of param message[text] must be less than or equal to 320'];
    return output;
}

/*const generic_message = {
    attachment: {
        type: "template",
        payload: {
            template_type: "generic",
            elements: [{
                title: "rift",
                subtitle: "Next-generation virtual reality",
                item_url: "https://www.oculus.com/en-us/rift/",
                image_url: "http://messengerdemo.parseapp.com/img/rift.png",
                buttons: [{
                    type: "web_url",
                    url: "https://www.oculus.com/en-us/rift/",
                    title: "Open Web URL"
                }, {
                    type: "postback",
                    title: "Call Postback",
                    payload: "Payload for first bubble"
                }]
            }, {
                title: "touch",
                subtitle: "Your Hands, Now in VR",
                item_url: "https://www.oculus.com/en-us/touch/",
                image_url: "http://messengerdemo.parseapp.com/img/touch.png",
                buttons: [{
                    type: "web_url",
                    url: "https://www.oculus.com/en-us/touch/",
                    title: "Open Web URL"
                }, {
                    type: "postback",
                    title: "Call Postback",
                    payload: "Payload for second bubble"
                }]
            }]
        }
    }
};*/

function sendFBMessage(sender, messageData, callback) {
    //console.log(sender);
    request({
        url: 'https://graph.facebook.com/v2.6/me/messages',
        qs: {access_token: FB_PAGE_ACCESS_TOKEN},
        method: 'POST',
        json: {
            recipient: {id: sender},
            message: messageData
            //message: generic_message
        }
    }, (error, response, body) => {
        if (error) {
            console.log('Error sending message: ', error);
        } else if (response.body.error) {
            console.log('Error: ', response.body.error);
        }

        if (callback) {
            callback();
        }
    });
}

function sendFBSenderAction(sender, action, callback) {
    setTimeout(() => {
        request({
            url: 'https://graph.facebook.com/v2.6/me/messages',
            qs: {access_token: FB_PAGE_ACCESS_TOKEN},
            method: 'POST',
            json: {
                recipient: {id: sender},
                sender_action: action
            }
        }, (error, response, body) => {
            if (error) {
                console.log('Error sending action: ', error);
            } else if (response.body.error) {
                console.log('Error: ', response.body.error);
            }
            if (callback) {
                callback();
            }
        });
    }, 1000);
}

function doSubscribeRequest() {
    request({
            method: 'POST',
            uri: "https://graph.facebook.com/v2.6/me/subscribed_apps?access_token=" + FB_PAGE_ACCESS_TOKEN
        },
        (error, response, body) => {
            if (error) {
                console.error('Error while subscription: ', error);
            } else {
                console.log('Subscription result: ', response.body);
            }
        });
}

function isDefined(obj) {
    if (typeof obj == 'undefined') {
        return false;
    }

    if (!obj) {
        return false;
    }

    return obj != null;
}

const app = express();

app.use(bodyParser.text({type: 'application/json'}));

app.get('/webhook/', (req, res) => {
    if (req.query['hub.verify_token'] == FB_VERIFY_TOKEN) {
        res.send(req.query['hub.challenge']);

        setTimeout(() => {
            doSubscribeRequest();
        }, 3000);
    } else {
        res.send('Error, wrong validation token');
    }
});

app.post('/webhook/', (req, res) => {
    try {
        var data = JSONbig.parse(req.body);
        var asd = data;
        //console.log(asd);
        if (data.entry) {
            let entries = data.entry;
            entries.forEach((entry) => {
                let messaging_events = entry.messaging;
                if (messaging_events) {
                    messaging_events.forEach((event) => {
                        //console.log(event);
                        if (event.message && !event.message.is_echo ||
                            event.postback && event.postback.payload) {
                            processEvent(event);
                        }
                    });
                }
            });
        }

        return res.status(200).json({
            status: "ok"
        });
    } catch (err) {
        return res.status(400).json({
            status: "error",
            error: err
        });
    }

});

app.post('/webhook_apiai/', (req, res) => {

    //var weather_query = new Boolean(false);
    var weather_query = 'false';

    const generic_message = {
        attachment: {
            type: "template",
            payload: {
                template_type: "generic",
                elements: [{
                    title: "Fresh Pizza",
                    subtitle: "Be carefull and don't eat your fingers!!!",
                    item_url: "https://en.wikipedia.org/wiki/Pizza",
                    //image_url: "http://www.cbc.ca/inthekitchen/assets_c/2012/11/MargheritaPizza21-thumb-596x350-247022.jpg",
                    buttons: [{
                        type: "web_url",
                        url: "https://en.wikipedia.org/wiki/Pizza",
                        title: "Open Web URL"
                    }/*, {
                     type: "postback",
                     title: "Call Postback",
                     payload: "Payload for first bubble"
                     }*/]
                }]
            }
        }
    };

    try {
        var data = JSONbig.parse(req.body);
        //console.log(data);
        switch(data.result.action){
            case 'show_prod':
                switch(data.result.parameters.pizza_type){
                    case 'Margherita':
                        generic_message.attachment.payload.elements[0].title = data.result.parameters.pizza_type;
                        generic_message.attachment.payload.elements[0].image_url = "http://www.cbc.ca/inthekitchen/assets_c/2012/11/MargheritaPizza21-thumb-596x350-247022.jpg";
                }
            case 'show_weather':
                weather_query = 'true';
                if(isDefined(data.result.parameters['geo-city']) == true){
                    var city = data.result.parameters['geo-city'];
                    var base_url = "https://query.yahooapis.com/v1/public/yql?" + "q=select+%2A+from+weather.forecast+where+woeid+in+%28select+woeid+from+geo.places%281%29+where+text%3D%27"+city+"%27%29" + "&format=json";
                    request({
                        url: base_url,
                        method: 'GET', //Specify the method
                    }, function(error, response, body){
                        if(error) {
                            console.log(error);
                            return res.status(400).json({
                                status: "error",
                                error: err
                            });
                        } else {
                            var query = JSON.parse(body).query;
                            var results = query.results;
                            var channel = results.channel;
                            var item = channel.item;
                            var location = channel.location;
                            var units = channel.units;
                            var condition = item.condition;
                            //console.log(channel)
                            var string = "Today in " + location.city + ": " + condition.text + ", the temperature is " + condition.temp + " " + units.temperature
                            generic_message.attachment.payload.elements[0].title = 'Weather in' + city;
                            generic_message.attachment.payload.elements[0].subtitle = string;
                            generic_message.attachment.payload.elements[0].item_url = channel.link;
                            generic_message.attachment.payload.elements[0].image_url = channel.image.url;
                            generic_message.attachment.payload.elements[0].buttons[0].url = channel.link;
                            return res.status(200).json({
                                data: {
                                    facebook: generic_message
                                }
                            })
                        }
                    });
                } else {
                    return res.status(200).json({
                        data: {
                            facebook: {text: 'no city'}
                        }
                    })}
                weather_query = 'false';
                break;
        }

        if (weather_query != 'true'){
            return res.status(200).json({
                data: {
                    facebook: generic_message
                }
            })
        } else {
            return res.status(200).json({
                data: {
                    facebook: {text: 'error'}
                }
            })}
    } catch (err) {
        return res.status(400).json({
            status: "error",
            error: err
        });
    }
});

app.listen(REST_PORT, () => {
    console.log('Rest service ready on port ' + REST_PORT);
});

doSubscribeRequest();
<|endoftext|>


<commit_before>'use strict'

module.exports = function ($compile) {

  return {
    restrict: "A",
    require: "ngModel",
    scope: {
      checkPhoneNumber: '=checkPhoneNumber'
    },
    link: function(scope, element, attributes, ngModel) {

      scope.$watch('checkPhoneNumber', function(newValue, oldValue) {

        // do not validate the Phone number
        if (!newValue){
          // always return true as we are not validating anymore
          ngModel.$validators.checkPhoneNumber = function(){
            return true
          }
          ngModel.$validate();
        }else{
          // add validator for Phone number
          ngModel.$validators.checkPhoneNumber = function(modelValue) {
            var numberRegex = new RegExp(/^\+?\d{10}$/);

            var isValid = numberRegex.test(modelValue)

            return isValid
          }
          ngModel.$validate();
        }

      }, true);

    }
  };
}<commit_msg>Corrected PhoneNumber validation regex<commit_after>'use strict'

module.exports = function ($compile) {

  return {
    restrict: "A",
    require: "ngModel",
    scope: {
      checkPhoneNumber: '=checkPhoneNumber'
    },
    link: function(scope, element, attributes, ngModel) {

      scope.$watch('checkPhoneNumber', function(newValue, oldValue) {

        // do not validate the Phone number
        if (!newValue){
          // always return true as we are not validating anymore
          ngModel.$validators.checkPhoneNumber = function(){
            return true
          }
          ngModel.$validate();
        }else{
          // add validator for Phone number
          ngModel.$validators.checkPhoneNumber = function(modelValue) {
            var numberRegex = new RegExp(/^(\+\d{1})?\d{10}$/);
            var isValid = numberRegex.test(modelValue)

            return isValid
          }
          ngModel.$validate();
        }

      }, true);

    }
  };
}<|endoftext|>


<commit_before>var HIDDEN="hidden";
var LEVEL = "level";
var PLUS_SRC="dom-images/butplus.gif"
var MIN_SRC="dom-images/butmin.gif"
var newRoot;
var maxColumns=1;

function loadDomViewer(){
	if(window.opener != null){
		//Open in a new window.
		// Start with specified root object.
		// It should be defined as a "newRoot" variable
		// in the tested page. Could be any element in
		// the DOM structure of the page that opened it.
		// Default to document if no object is specified.
		newRoot  = window.opener.newRoot;

		if (newRoot==null)
			newRoot = window.opener.document;

		document.writeln(displayDOM(newRoot));
		document.close();
	}else{
		newRoot = parent.document.all['myiframe'].contentWindow.document;
		newRoot.writeln(displayDOM(newRoot));
		newRoot.close();
	}
}

function displayDOM(root){
	var str = "<title>DOM Viewerr</title><link href='dom-styles/default.css' rel='stylesheet' type='text/css' />";
	str+="
";
	str += treeTraversal(root,0);
	alert(maxColumns);
	// to make table columns work well.
	str += "
";
	for (var i=0; i < maxColumns; i++) {
	    str+= "    	";
	}
	str += "
";
	str += "
";
	return str;
}

function checkForChildren(element){
	if(!element.hasChildNodes())
		return false;

	var nodes = element.childNodes;
	var size = nodes.length;
	var count=0;

	for(var i=0; i< size; i++){
		var node = nodes.item(i);
		//if(node.toString()=="[object Text]"){
		//this is equalent to the above
		//but will work with more browsers
		if(node.nodeType!=1){
			count++;
		}
	}

	if(count == size)
		return false;
	else
		return true;
}

function treeTraversal(root, level){
	var str = "";
	var nodes= null;
	var size = null;
	//it is supposed to show the last node,
	//but the last node is always nodeText type
	//and we don't show it
	if(!root.hasChildNodes())
		return "";//displayNode(root,level,false);

	nodes = root.childNodes;
	size = nodes.length;

	for(var i=0; i< size; i++){
		var element = nodes.item(i);
		//if the node is textNode, don't display
		if(element.nodeType==1){
			str+= displayNode(element,level,checkForChildren(element));
			str+=treeTraversal(element, level+1);
		}
	}
	return str;
}

function displayNode(element, level, isLink){
        nodeContent = getNodeContent(element);
        columns = Math.round((nodeContent.length / 12) + 0.5);
        if (columns + level > maxColumns) {
            maxColumns = columns + level;
        }
		var str ="
";
		for (var i=0; i < level; i++)
			str+= " 	";
		str+="";
		if(isLink){
			str+='';
			str+='';
		}
        str += nodeContent;
		if(isLink)
			str+="
";
		return str;
}

function getNodeContent(element) {
        str = "";
		id ="";
		if (element.id != null && element.id != "") {
		    id = " ID(" + element.id +")";
		}
		name ="";
		if (element.name != null && element.name != "") {
		    name = " NAME(" + element.name + ")";
		}
		value ="";
		if (element.value != null && element.value != "") {
		    value = " VALUE(" + element.value + ")";
		}
		href ="";
		if (element.href != null && element.href != "") {
		    href = " HREF(" + element.href + ")";
		}
		str+=" "+ element.nodeName + id + name + value + href + "";
		return str;

}

function hide(hlink){
	var isHidden = false;
	var image = hlink.firstChild;
	if(image.src.toString().indexOf(MIN_SRC)!=-1){
		image.src=PLUS_SRC;
		isHidden=true;
	}else{
		image.src=MIN_SRC;
	}
	var rowObj= hlink.parentNode.parentNode;
	var rowLevel = parseInt(rowObj.className.substring(LEVEL.length));

	var sibling = rowObj.nextSibling;
	var siblingLevel = sibling.className.substring(LEVEL.length);
	if(siblingLevel.indexOf(HIDDEN)!=-1){
		siblingLevel = siblingLevel.substring(0,siblingLevel.length - HIDDEN.length-1);
	}
	siblingLevel=parseInt(siblingLevel);
	while(sibling!=null && rowLevel<siblingLevel){
		if(isHidden){
			sibling.className += " "+ HIDDEN;
		}else if(!isHidden && sibling.className.indexOf(HIDDEN)!=-1){
			var str = sibling.className;
			sibling.className=str.substring(0, str.length - HIDDEN.length-1);
		}
		sibling = sibling.nextSibling;
		siblingLevel = parseInt(sibling.className.substring(LEVEL.length));
	}
}

<commit_msg>#text if appl<commit_after>var HIDDEN="hidden";
var LEVEL = "level";
var PLUS_SRC="dom-images/butplus.gif"
var MIN_SRC="dom-images/butmin.gif"
var newRoot;
var maxColumns=1;

function loadDomViewer(){
	if(window.opener != null){
		//Open in a new window.
		// Start with specified root object.
		// It should be defined as a "newRoot" variable
		// in the tested page. Could be any element in
		// the DOM structure of the page that opened it.
		// Default to document if no object is specified.
		newRoot  = window.opener.newRoot;

		if (newRoot==null)
			newRoot = window.opener.document;

		document.writeln(displayDOM(newRoot));
		document.close();
	}else{
		newRoot = parent.document.all['myiframe'].contentWindow.document;
		newRoot.writeln(displayDOM(newRoot));
		newRoot.close();
	}
}

function displayDOM(root){
	var str = "<title>DOM Viewerr</title><link href='dom-styles/default.css' rel='stylesheet' type='text/css' />";
	str+="
";
	str += treeTraversal(root,0);
	// to make table columns work well.
	str += "
";
	for (var i=0; i < maxColumns; i++) {
	    str+= "    	";
	}
	str += "
";
	str += "
";
	return str;
}

function checkForChildren(element){
	if(!element.hasChildNodes())
		return false;

	var nodes = element.childNodes;
	var size = nodes.length;
	var count=0;

	for(var i=0; i< size; i++){
		var node = nodes.item(i);
		//if(node.toString()=="[object Text]"){
		//this is equalent to the above
		//but will work with more browsers
		if(node.nodeType!=1){
			count++;
		}
	}

	if(count == size)
		return false;
	else
		return true;
}

function treeTraversal(root, level){
	var str = "";
	var nodes= null;
	var size = null;
	//it is supposed to show the last node,
	//but the last node is always nodeText type
	//and we don't show it
	if(!root.hasChildNodes())
		return "";//displayNode(root,level,false);

	nodes = root.childNodes;
	size = nodes.length;

	for(var i=0; i< size; i++){
		var element = nodes.item(i);
		//if the node is textNode, don't display
		if(element.nodeType==1){
			str+= displayNode(element,level,checkForChildren(element));
			str+=treeTraversal(element, level+1);
		}
	}
	return str;
}

function displayNode(element, level, isLink){
        nodeContent = getNodeContent(element);
        columns = Math.round((nodeContent.length / 12) + 0.5);
        if (columns + level > maxColumns) {
            maxColumns = columns + level;
        }
		var str ="
";
		for (var i=0; i < level; i++)
			str+= " 	";
		str+="";
		if(isLink){
			str+='';
			str+='';
		}
        str += nodeContent;
		if(isLink)
			str+="
";
		return str;
}

function getNodeContent(element) {
        str = "";
		id ="";
		if (element.id != null && element.id != "") {
		    id = " ID(" + element.id +")";
		}
		name ="";
		if (element.name != null && element.name != "") {
		    name = " NAME(" + element.name + ")";
		}
		value ="";
		if (element.value != null && element.value != "") {
		    value = " VALUE(" + element.value + ")";
		}
		href ="";
		if (element.href != null && element.href != "") {
		    href = " HREF(" + element.href + ")";
		}
		text ="";
		if (element.text != null && element.text != "" && element.text != "undefined") {
		    text = " #TEXT(" + trim(element.text) +")";
		}
		str+=" "+ element.nodeName + id + name + value + href + text + "";
		return str;

}

function trim(val) {
        val2 = val.substring(0,20) + "                   ";
        var spaceChr = String.fromCharCode(32);
        var length = val2.length;
        var retVal = "";
        var ix = length -1;

        while(ix > -1){
            if(val2.charAt(ix) == spaceChr) {
            } else {
                retVal = val2.substring(0, ix +1);
                break;
            }
            ix = ix-1;
        }
        if (val.length > 20) {
            retVal += "...";
        }
        return retVal;
}

function hide(hlink){
	var isHidden = false;
	var image = hlink.firstChild;
	if(image.src.toString().indexOf(MIN_SRC)!=-1){
		image.src=PLUS_SRC;
		isHidden=true;
	}else{
		image.src=MIN_SRC;
	}
	var rowObj= hlink.parentNode.parentNode;
	var rowLevel = parseInt(rowObj.className.substring(LEVEL.length));

	var sibling = rowObj.nextSibling;
	var siblingLevel = sibling.className.substring(LEVEL.length);
	if(siblingLevel.indexOf(HIDDEN)!=-1){
		siblingLevel = siblingLevel.substring(0,siblingLevel.length - HIDDEN.length-1);
	}
	siblingLevel=parseInt(siblingLevel);
	while(sibling!=null && rowLevel<siblingLevel){
		if(isHidden){
			sibling.className += " "+ HIDDEN;
		}else if(!isHidden && sibling.className.indexOf(HIDDEN)!=-1){
			var str = sibling.className;
			sibling.className=str.substring(0, str.length - HIDDEN.length-1);
		}
		sibling = sibling.nextSibling;
		siblingLevel = parseInt(sibling.className.substring(LEVEL.length));
	}
}

<|endoftext|>


<commit_before>const express = require('@feathersjs/express');
const feathers = require('@feathersjs/feathers');
const configuration = require('@feathersjs/configuration');
const { Configuration } = require('@hpi-schul-cloud/commons');
const path = require('path');
const favicon = require('serve-favicon');
const compress = require('compression');
const cors = require('cors');
const rest = require('@feathersjs/express/rest');
const bodyParser = require('body-parser');
const socketio = require('@feathersjs/socketio');
const { ObjectId } = require('mongoose').Types;

const { BODYPARSER_JSON_LIMIT, LEAD_TIME } = require('../config/globals');

const middleware = require('./middleware');
const setupConfiguration = require('./configuration');
const sockets = require('./sockets');
const services = require('./services');
const components = require('./components');

const requestLog = require('./logger/RequestLogger');

const defaultHeaders = require('./middleware/defaultHeaders');
const handleResponseType = require('./middleware/handleReponseType');
const errorHandler = require('./middleware/errorHandler');
const sentry = require('./middleware/sentry');
const rabbitMq = require('./utils/rabbitmq');
const prometheus = require('./utils/prometheus');

const { setupFacadeLocator, setupFacades } = require('./utils/facadeLocator');
const { setupFacadeLocator } = require('./utils/facadeLocator');
const setupSwagger = require('./swagger');
const { initializeRedisClient } = require('./utils/redis');
const { setupAppHooks } = require('./app.hooks');
const versionService = require('./services/versionService');

const setupApp = async () => {
	const app = express(feathers());
	app.disable('x-powered-by');

	const config = configuration();
	app.configure(config);

	if (LEAD_TIME) {
		app.use((req, res, next) => {
			req.leadTime = Date.now();
			next();
		});
	}

	app.configure(prometheus);

	setupFacadeLocator(app);
	setupSwagger(app);
	initializeRedisClient();
	rabbitMq.setup(app);

	app
		.use(compress())
		.options('*', cors())
		.use(cors())
		.use(favicon(path.join(app.get('public'), 'favicon.ico')))
		.use('/', express.static('public'))
		.configure(setupConfiguration)
		.configure(sentry)
		.use('/helpdesk', bodyParser.json({ limit: BODYPARSER_JSON_LIMIT }))
		.use('/', bodyParser.json({ limit: '10mb' }))
		.use(bodyParser.urlencoded({ extended: true }))
		.use(bodyParser.raw({ type: () => true, limit: '10mb' }))
		.use(versionService)
		.use(defaultHeaders)
		.get('/system_info/haproxy', (req, res) => {
			res.send({ timestamp: new Date().getTime() });
		})
		.get('/ping', (req, res) => {
			res.send({ message: 'pong', timestamp: new Date().getTime() });
		})
		.configure(rest(handleResponseType))
		.configure(socketio())
		.use((req, res, next) => {
			// pass header into hooks.params
			// todo: To create a fake requestId on this place is a temporary solution
			// it MUST be removed after the API gateway is established
			const uid = ObjectId();
			req.headers.requestId = uid.toString();
			req.feathers.leadTime = req.leadTime;
			req.feathers.headers = req.headers;
			req.feathers.originalUrl = req.originalUrl;
			next();
		});

	if (Configuration.get('REQUEST_LOGGING_ENABLED') === true) {
		app.use((req, res, next) => {
			requestLog(`${req.method} ${req.originalUrl}`);
			next();
		});
	}
	app
		.configure(services)
		.configure(components)
		.configure(sockets)
		.configure(middleware)
		.configure(setupAppHooks)
		.configure(errorHandler);

	return app;
};

module.exports = setupApp();
<commit_msg>fix merge mistake<commit_after>const express = require('@feathersjs/express');
const feathers = require('@feathersjs/feathers');
const configuration = require('@feathersjs/configuration');
const { Configuration } = require('@hpi-schul-cloud/commons');
const path = require('path');
const favicon = require('serve-favicon');
const compress = require('compression');
const cors = require('cors');
const rest = require('@feathersjs/express/rest');
const bodyParser = require('body-parser');
const socketio = require('@feathersjs/socketio');
const { ObjectId } = require('mongoose').Types;

const { BODYPARSER_JSON_LIMIT, LEAD_TIME } = require('../config/globals');

const middleware = require('./middleware');
const setupConfiguration = require('./configuration');
const sockets = require('./sockets');
const services = require('./services');
const components = require('./components');

const requestLog = require('./logger/RequestLogger');

const defaultHeaders = require('./middleware/defaultHeaders');
const handleResponseType = require('./middleware/handleReponseType');
const errorHandler = require('./middleware/errorHandler');
const sentry = require('./middleware/sentry');
const rabbitMq = require('./utils/rabbitmq');
const prometheus = require('./utils/prometheus');

const { setupFacadeLocator } = require('./utils/facadeLocator');
const setupSwagger = require('./swagger');
const { initializeRedisClient } = require('./utils/redis');
const { setupAppHooks } = require('./app.hooks');
const versionService = require('./services/versionService');

const setupApp = async () => {
	const app = express(feathers());
	app.disable('x-powered-by');

	const config = configuration();
	app.configure(config);

	if (LEAD_TIME) {
		app.use((req, res, next) => {
			req.leadTime = Date.now();
			next();
		});
	}

	app.configure(prometheus);

	setupFacadeLocator(app);
	setupSwagger(app);
	initializeRedisClient();
	rabbitMq.setup(app);

	app
		.use(compress())
		.options('*', cors())
		.use(cors())
		.use(favicon(path.join(app.get('public'), 'favicon.ico')))
		.use('/', express.static('public'))
		.configure(setupConfiguration)
		.configure(sentry)
		.use('/helpdesk', bodyParser.json({ limit: BODYPARSER_JSON_LIMIT }))
		.use('/', bodyParser.json({ limit: '10mb' }))
		.use(bodyParser.urlencoded({ extended: true }))
		.use(bodyParser.raw({ type: () => true, limit: '10mb' }))
		.use(versionService)
		.use(defaultHeaders)
		.get('/system_info/haproxy', (req, res) => {
			res.send({ timestamp: new Date().getTime() });
		})
		.get('/ping', (req, res) => {
			res.send({ message: 'pong', timestamp: new Date().getTime() });
		})
		.configure(rest(handleResponseType))
		.configure(socketio())
		.use((req, res, next) => {
			// pass header into hooks.params
			// todo: To create a fake requestId on this place is a temporary solution
			// it MUST be removed after the API gateway is established
			const uid = ObjectId();
			req.headers.requestId = uid.toString();
			req.feathers.leadTime = req.leadTime;
			req.feathers.headers = req.headers;
			req.feathers.originalUrl = req.originalUrl;
			next();
		});

	if (Configuration.get('REQUEST_LOGGING_ENABLED') === true) {
		app.use((req, res, next) => {
			requestLog(`${req.method} ${req.originalUrl}`);
			next();
		});
	}
	app
		.configure(services)
		.configure(components)
		.configure(sockets)
		.configure(middleware)
		.configure(setupAppHooks)
		.configure(errorHandler);

	return app;
};

module.exports = setupApp();
<|endoftext|>