<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();

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"
                 }*/]
            }]
        }
    }
};

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) => {
    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':
                if(!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);
                        } else {
                            //console.log(response.statusCode, body);
                            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;
                            console.log(JSON.stringify(generic_message))
                        }
                    });
                }
        }
        return res.status(200).json({
            data: {
                facebook: generic_message
            }
        })
    } 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();

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"
                 }*/]
            }]
        }
    }
};

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) => {
    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':
                if(!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);
                        } else {
                            //console.log(response.statusCode, body);
                            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;
                        }
                    });
                }
        }
        console.log(JSON.stringify(generic_message));
        return res.status(200).json({
            data: {
                facebook: generic_message
            }
        })
    } 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';

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

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;

    if (event.message && event.message.text) {
        var text = event.message.text;
        // 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)) {
                let responseText = response.result.fulfillment.speech;
                let responseData = response.result.fulfillment.data;
                let action = response.result.action;
                let parameters = response.result.parameters;

                try {
                    var misc = require('./'+ action);
                    console.log("Adding %d to 10 gives us %d", misc.x, misc.addX(JSON.stringify(parameters)));
                } catch(e) {
                    console.error(action +" is not found");
                }

                if (isDefined(responseData) && isDefined(responseData.facebook)) {
                    try {
                        console.log('Response as formatted message');
                        sendFBMessage(sender, responseData.facebook);
                    } catch (err) {
                        sendFBMessage(sender, {text: err.message });
                    }
                } else if (isDefined(responseText)) {
                    console.log('Response as text message');
                    // facebook API limit for text length is 320,
                    // so we split message if needed
                    var splittedText = splitResponse(responseText);

                    for (var i = 0; i < splittedText.length; i++) {
                        sendFBMessage(sender, {text: splittedText[i]});
                    }
                }

            }
        });

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

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

    var result = chunkString(str, 300);

    return result;

}

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));
    return output;
}

function sendFBMessage(sender, messageData) {
    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
        }
    }, function (error, response, body) {
        if (error) {
            console.log('Error sending message: ', error);
        } else if (response.body.error) {
            console.log('Error: ', response.body.error);
        }
    });
}

function doSubscribeRequest() {
    request({
            method: 'POST',
            uri: "https://graph.facebook.com/v2.6/me/subscribed_apps?access_token=" + FB_PAGE_ACCESS_TOKEN
        },
        function (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.json());
app.all('*', function (req, res, next) {
    // res.header("Access-Control-Allow-Origin", '*');
    // res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, content-type, accept");
    next();
});

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

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

app.post('/webhook/', function (req, res) {
    try {
        var messaging_events = req.body.entry[0].messaging;
        for (var i = 0; i < messaging_events.length; i++) {
            var event = req.body.entry[0].messaging[i];
            processEvent(event);
        }
        return res.status(200).json({
            status: "ok"
        });
    } catch (err) {
        return res.status(400).json({
            status: "error",
            error: err
        });
    }

});

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

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 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;

    if (event.message && event.message.text) {
        var text = event.message.text;
        // 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)) {
                let responseText = response.result.fulfillment.speech;
                let responseData = response.result.fulfillment.data;
                let action = response.result.action;
                let parameters = response.result.parameters;

                try {
                    var misc = require('./'+ action);
                    console.log(misc.addX(JSON.stringify(parameters)));
                } catch(e) {
                    console.error(action +" is not found");
                }

                if (isDefined(responseData) && isDefined(responseData.facebook)) {
                    try {
                        console.log('Response as formatted message');
                        sendFBMessage(sender, responseData.facebook);
                    } catch (err) {
                        sendFBMessage(sender, {text: err.message });
                    }
                } else if (isDefined(responseText)) {
                    console.log('Response as text message');
                    // facebook API limit for text length is 320,
                    // so we split message if needed
                    var splittedText = splitResponse(responseText);

                    for (var i = 0; i < splittedText.length; i++) {
                        sendFBMessage(sender, {text: splittedText[i]});
                    }
                }

            }
        });

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

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

    var result = chunkString(str, 300);

    return result;

}

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));
    return output;
}

function sendFBMessage(sender, messageData) {
    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
        }
    }, function (error, response, body) {
        if (error) {
            console.log('Error sending message: ', error);
        } else if (response.body.error) {
            console.log('Error: ', response.body.error);
        }
    });
}

function doSubscribeRequest() {
    request({
            method: 'POST',
            uri: "https://graph.facebook.com/v2.6/me/subscribed_apps?access_token=" + FB_PAGE_ACCESS_TOKEN
        },
        function (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.json());
app.all('*', function (req, res, next) {
    // res.header("Access-Control-Allow-Origin", '*');
    // res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, content-type, accept");
    next();
});

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

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

app.post('/webhook/', function (req, res) {
    try {
        var messaging_events = req.body.entry[0].messaging;
        for (var i = 0; i < messaging_events.length; i++) {
            var event = req.body.entry[0].messaging[i];
            processEvent(event);
        }
        return res.status(200).json({
            status: "ok"
        });
    } catch (err) {
        return res.status(400).json({
            status: "error",
            error: err
        });
    }

});

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

doSubscribeRequest();
<|endoftext|>


<commit_before>import {div} from '@cycle/dom';
import {Observable} from 'rx';
import tinycolor from 'tinycolor2';

import {either} from './helpers';

import {
  renderSaturationInput,
  renderHueInput,
  renderAlphaInput,
  renderSwatch,
  renderColorInput
} from './views';

import makeReducer$ from './reducers';

// TODO:
// - Eat food (don't work on this while you're hungry)
// - Tidy up calls to tinycolor and make sure they aren't mutating state. Also use tinycolor.fromRatio to simplify a bunch of shit.
// - Fix indicators overshooting by 10px
// - Pretty up the CSS (add SASS, move some things to JS, that kinda thing)
// - Add Hex/RGBA/HSL to display
//  - Allow users to cycle between them
// - Allow clicking on components (rather than just drag)
// - Test
// - Publish to NPM
//
//
// TODO right now:
// - render current color as HEX
// - render current color as HEX in an input that can be copied from
// - allow HEX input to update the color
// - allow user to switch to rgba input mode
// - automatically switch to rgba input mode if alpha < 1
//
function view (state) {
  return (
    div('.color-picker', [
      renderSaturationInput(state),
      renderHueInput(state),
      renderAlphaInput(state),
      renderSwatch(state),
      renderColorInput(state)
    ])
  );
}

export default function ColorPicker ({DOM, Mouse, props$ = Observable.empty()}) {
  const initialState = {
    dragging: either(['none', 'hue', 'saturation', 'alpha'], 'none'),

    saturationContainer: {width: 0, height: 0},
    hueContainer: {width: 0},
    alphaContainer: {width: 0},

    color: {h: 0, s: 0, v: 1, a: 1},
    colorInputFormat: either(['hex', 'rgba', 'hsla'], 'rgba')
  };

  const action$ = makeReducer$({DOM, Mouse, props$});

  const state$ = action$
    .startWith(initialState)
    .scan((state, action) => action(state))
    .shareReplay(1)
    .distinctUntilChanged(JSON.stringify);

  const color$ = state$.map(state => {
    return tinycolor({...state.color, h: state.color.h * 360}).toRgbString();
  }).distinctUntilChanged();

  return {
    DOM: state$.map(view),
    color$
  };
}
<commit_msg>Small tidy<commit_after>import {div} from '@cycle/dom';
import {Observable} from 'rx';
import tinycolor from 'tinycolor2';

import {either} from './helpers';

import {
  renderSaturationInput,
  renderHueInput,
  renderAlphaInput,
  renderSwatch,
  renderColorInput
} from './views';

import makeReducer$ from './reducers';

// TODO:
// - Eat food (don't work on this while you're hungry)
// - Tidy up calls to tinycolor and make sure they aren't mutating state. Also use tinycolor.fromRatio to simplify a bunch of shit.
// - Fix indicators overshooting by 10px
// - Pretty up the CSS (add SASS, move some things to JS, that kinda thing)
// - Add Hex/RGBA/HSL to display
//  - Allow users to cycle between them
// - Allow clicking on components (rather than just drag)
// - Test
// - Publish to NPM
//
//
// TODO right now:
// - Allow user to cycle through input modes
// - automatically switch to rgba input mode if alpha < 1
//
function view (state) {
  return (
    div('.color-picker', [
      renderSaturationInput(state),
      renderHueInput(state),
      renderAlphaInput(state),
      renderSwatch(state),
      renderColorInput(state)
    ])
  );
}

export default function ColorPicker ({DOM, Mouse, props$ = Observable.empty()}) {
  const initialState = {
    dragging: either(['none', 'hue', 'saturation', 'alpha'], 'none'),

    saturationContainer: {width: 0, height: 0},
    hueContainer: {width: 0},
    alphaContainer: {width: 0},

    color: {h: 0, s: 0, v: 1, a: 1},
    colorInputFormat: either(['hex', 'rgba', 'hsla'], 'rgba')
  };

  const action$ = makeReducer$({DOM, Mouse, props$});

  const state$ = action$
    .startWith(initialState)
    .scan((state, action) => action(state))
    .shareReplay(1)
    .distinctUntilChanged(JSON.stringify);

  const color$ = state$
    .map(state => {
      return tinycolor.fromRatio(state.color).toRgbString();
    })
    .distinctUntilChanged();

  return {
    DOM: state$.map(view),
    color$
  };
}
<|endoftext|>


<commit_before>/*
 * Notes :
 * need to figure out if there is a way to continously check if
 * the alarms sets off.
 */

/**
 * Welcome to Pebble.js!
 * Test
 * This is where you write your app.
 */

// Calls in required stuff
var UI = require('ui');
var Vibe = require('ui/vibe');
var Settings = require('settings');
var date = new Date();

//var Vector2 = require('vector2');

// A for loop to make array of hours
var hours = [];
for (var i = 0; i < 24; i++) {
    hours.push(i + 1);
}

var alarms = Settings.data('alarms') || [];
var createAlarmItems = function(alarms) {
    var items = [];
    items.push({
        title: "Add New Alarm"
    });
    console.log("alarm length : " + alarms.length);
    if (alarms.length > 0)
        for (var i = 0; i < alarms.length; i++) {
            try {
                items.push({
                    title: alarms[i].time,
                    subtitle: alarms[i].enabled
                });
                console.log(i);
            } catch (err) {
            }
    }
    console.log("Created item list");
    return items;
};

var detectTimeLoop = function() {

	for (var i = 0; i < alarms.length; i++) {

		console.log("alarm " + alarms[i].hour + "h ");
        console.log(alarms[i].minute + "m");
		console.log("actual " + date.getHours() + "h  " + date.getMinutes() + "m");

		// break if no longer valid alarm(s)
		if ( !alarms[i].hour || !alarms[i].minute ) { break; }

		if ( alarms[i].hour == date.getHours() && alarms[i].minute == date.getMinutes() ) {
			// vibrates.. add more later
			Vibe.vibrate('long');
		console.log(i + ": I vibrated");
		}
    }

	setTimeout(function() {
		detectTimeLoop();
	}, 1000);
};

detectTimeLoop();

/*
	Formats time from the 24-hour clock to 12-hour
*/
var formatTime = function( h, m ) {
	var hour = ( h % 12 !== 0 ? h % 12 : 12 );
    var minute = m < 10 ? "0" + m : m;
	return hour + ":" + minute + " " + ( ( h < 12 ) ? "AM" : "PM" );
}

// Sets up the alarms
var alarmItems = createAlarmItems(alarms);

/*
// Creates a loop to make an array of hours
var createHourItems = function() {
  var items = [];
  for (var i = 0; i hideurs.length; i++) {
    items.push({
      title: hours[i]
    });
  }
  return items;
};
*/

/*
var main = new UI.Menu({
   sections:[{
     items: createItems()
  }]
});

main.show();
*/

// The Splashscreen
var splashScreen = new UI.Card({
    title: 'Alarm',
    icon: 'images/menu_icon.png',
    subtitle: 'Welcome to Our App',
    body: 'This is the splash page'
    //banner (future plans)
});

// Makes a menu with New Alarms
var main = new UI.Menu({
    sections: [{
        items: alarmItems
        /*
            [{
            title: 'Add New Alarm',
            subtitle: 'New Alarm'
        }, {
            // Dr. Seuss
            title: 'One Alarm'
        }, {
            title: 'Two Alarm'
        }, {
            title: 'Red Alarm'
        }, {
            title: 'Blue Alarm'
        }]
        */
        //, createAlarmItems(alarms)
    }]
});

// Shows the spashscreen and goes to the menu after 400 ms
splashScreen.show();
setTimeout(function() {
    splashScreen.hide();
    main.show();
}, 800);

var createAlarm = function(callback) {
    alarms.push({
        time: formatTime( date.getHours(), date.getMinutes() + 2 ),
        hour: date.getHours(),
        minute: date.getMinutes() + 2,
        enabled: true
    });
    console.log("hour : " + date.getHours());
    console.log("minute : " + date.getMinutes());
    console.log("time : " + formatTime( date.getHours(), date.getMinutes() ));
    callback();
};

main.on('select', function(e) {
    console.log(e.sectionIndex);
    // If it is on the "New Alarm Option"
    if (e.itemIndex === 0) {
        // Has a random card as a placeholder
        var card = new UI.Card();
        card.title('A Card');
        card.subtitle('Is a Window');
        card.body('The simplest window type in Pebble.js.');
        card.show();

        // When click the middle button it makes an alarm
        card.on('click', 'select', function() {
            createAlarm(function() {
                alarmItems = createAlarmItems(alarms);
                console.log('Items done');
                console.log(alarmItems);
                card.hide();
                main.section(0, section = {
                    items: alarmItems
                });
                console.log("success");
            });
        });
    } else {
        // Otherwise the user selects an alarm
        // Creates the Menu for Alarm Options
        var alarmOptions = new UI.Menu({
            sections : [{
                items: [{
                    title: 'Disable'
                }, {
                    title: 'Edit'
                }, {
                    title: 'Delete'
                }]
            }]
        });
        alarmOptions.show();

        alarmOptions.on('select', function(e) {
            switch(e.itemIndex) {
                case 0:
                    // Disable or Enable the Alarm
                    if (e.item.enabled) {
                        e.item.enabled = false;
                    } else {
                        e.item.enabled = true;
                    }
                    break;
                case 1:
                    // Edit the time of the alarm
                    break;
                case 2:
                    // Deletes the alarm
                    alarms.splice(e.itemIndex, 1);
                    console.log("deleted at : " + e.itemIndex);
                    break;
                default:
                    console.log("error");
                    break;
            }
            // Update the alarms and gets rid of the option menu
            alarmItems = createAlarmItems(alarms);
            alarmOptions.hide();
            main.section(0, section = {
                items: alarmItems
            });
        });
    }
    // Choose an option to chnage alarm
});

// Code from before, I don't currently remove it for reference
/*
// Try but doesn't work
main.on('click', 'select', function(e) {
    var item = this.items(0);
    if (item.title == "Add New Alarm") {
        Vibe.vibrate('long');
        var card = new UI.Card();
        card.title('A Card');
        card.subtitle('Is a Window');
        card.body('The simplest window type in Pebble.js.');
        card.show();
    }
});
*/

/*
main.on('click', 'up', function(e) {
    var menu = new UI.Menu({
        sections: [{
            items: [{
                title: 'Pebble.js',
                icon: 'images/menu_icon.png',
                subtitle: 'Can do Menus'
            }, {
                title: 'Second Item',
                subtitle: 'Subtitle Text'
            }]
        }]
    });
    menu.on('select', function(e) {
        console.log('Selected item #' + e.itemIndex + ' of section #' + e.sectionIndex);
        console.log('The item is titled "' + e.item.title + '"');
    });
    menu.show();
});
*/

// When click middle button
/*
main.on('click', 'up', function(e) {
    //test vibrqtion and date fubction
    console.log("foo");
    if (new Date() == new Date()) {
        Vibe.vibrate('long');
    }
    var wind = new UI.Window();
    //var time = new UI.TimeText();
    // Time in Text form
    var textfield = new UI.TimeText({
        position: new Vector2(0, 50),
        size: new Vector2(144, 30),
        font: 'gothic-24-bold',
        text: '%M:%S, %a',
        textAlign: 'center'
    });
    wind.add(textfield);
    wind.show();
});
*/

/*
main.on('click', 'down', function(e) {
    var card = new UI.Card();
    card.title('A Card');
    card.subtitle('Is a Window');
    card.body('The simplest window type in Pebble.js.');
    card.show();
});
*/
<commit_msg>formating of console.log<commit_after>/*
 * Notes :
 * need to figure out if there is a way to continously check if
 * the alarms sets off.
 */

/**
 * Welcome to Pebble.js!
 * Test
 * This is where you write your app.
 */

// Calls in required stuff
var UI = require('ui');
var Vibe = require('ui/vibe');
var Settings = require('settings');
var date = new Date();

//var Vector2 = require('vector2');

// A for loop to make array of hours
var hours = [];
for (var i = 0; i < 24; i++) {
    hours.push(i + 1);
}

var alarms = Settings.data('alarms') || [];
var createAlarmItems = function(alarms) {
    var items = [];
    items.push({
        title: "Add New Alarm"
    });
    console.log("alarm length : " + alarms.length);
    if (alarms.length > 0)
        for (var i = 0; i < alarms.length; i++) {
            try {
                items.push({
                    title: alarms[i].time,
                    subtitle: alarms[i].enabled
                });
                console.log(i);
            } catch (err) {
            }
    }
    console.log("Created item list");
    return items;
};

var detectTimeLoop = function() {

	for (var i = 0; i < alarms.length; i++) {

		console.log("alarm " + alarms[i].hour + "h " + alarms[i].minute + "m");
		console.log("actual " + date.getHours() + "h  " + date.getMinutes() + "m");

		// break if no longer valid alarm(s)
		if ( !alarms[i].hour || !alarms[i].minute ) { break; }

		if ( alarms[i].hour == date.getHours() && alarms[i].minute == date.getMinutes() ) {
			// vibrates.. add more later
			Vibe.vibrate('long');
		console.log(i + ": I vibrated");
		}
    }

	setTimeout(function() {
		detectTimeLoop();
	}, 1000);
};

detectTimeLoop();

/*
	Formats time from the 24-hour clock to 12-hour
*/
var formatTime = function( h, m ) {
	var hour = ( h % 12 !== 0 ? h % 12 : 12 );
    var minute = m < 10 ? "0" + m : m;
	return hour + ":" + minute + " " + ( ( h < 12 ) ? "AM" : "PM" );
}

// Sets up the alarms
var alarmItems = createAlarmItems(alarms);

/*
// Creates a loop to make an array of hours
var createHourItems = function() {
  var items = [];
  for (var i = 0; i hideurs.length; i++) {
    items.push({
      title: hours[i]
    });
  }
  return items;
};
*/

/*
var main = new UI.Menu({
   sections:[{
     items: createItems()
  }]
});

main.show();
*/

// The Splashscreen
var splashScreen = new UI.Card({
    title: 'Alarm',
    icon: 'images/menu_icon.png',
    subtitle: 'Welcome to Our App',
    body: 'This is the splash page'
    //banner (future plans)
});

// Makes a menu with New Alarms
var main = new UI.Menu({
    sections: [{
        items: alarmItems
        /*
            [{
            title: 'Add New Alarm',
            subtitle: 'New Alarm'
        }, {
            // Dr. Seuss
            title: 'One Alarm'
        }, {
            title: 'Two Alarm'
        }, {
            title: 'Red Alarm'
        }, {
            title: 'Blue Alarm'
        }]
        */
        //, createAlarmItems(alarms)
    }]
});

// Shows the spashscreen and goes to the menu after 400 ms
splashScreen.show();
setTimeout(function() {
    splashScreen.hide();
    main.show();
}, 800);

var createAlarm = function(callback) {
    alarms.push({
        time: formatTime( date.getHours(), date.getMinutes() + 2 ),
        hour: date.getHours(),
        minute: date.getMinutes() + 2,
        enabled: true
    });
    console.log("hour : " + date.getHours());
    console.log("minute : " + date.getMinutes());
    console.log("time : " + formatTime( date.getHours(), date.getMinutes() ));
    callback();
};

main.on('select', function(e) {
    console.log(e.sectionIndex);
    // If it is on the "New Alarm Option"
    if (e.itemIndex === 0) {
        // Has a random card as a placeholder
        var card = new UI.Card();
        card.title('A Card');
        card.subtitle('Is a Window');
        card.body('The simplest window type in Pebble.js.');
        card.show();

        // When click the middle button it makes an alarm
        card.on('click', 'select', function() {
            createAlarm(function() {
                alarmItems = createAlarmItems(alarms);
                console.log('Items done');
                console.log(alarmItems);
                card.hide();
                main.section(0, section = {
                    items: alarmItems
                });
                console.log("success");
            });
        });
    } else {
        // Otherwise the user selects an alarm
        // Creates the Menu for Alarm Options
        var alarmOptions = new UI.Menu({
            sections : [{
                items: [{
                    title: 'Disable'
                }, {
                    title: 'Edit'
                }, {
                    title: 'Delete'
                }]
            }]
        });
        alarmOptions.show();

        alarmOptions.on('select', function(e) {
            switch(e.itemIndex) {
                case 0:
                    // Disable or Enable the Alarm
                    if (e.item.enabled) {
                        e.item.enabled = false;
                    } else {
                        e.item.enabled = true;
                    }
                    break;
                case 1:
                    // Edit the time of the alarm
                    break;
                case 2:
                    // Deletes the alarm
                    alarms.splice(e.itemIndex, 1);
                    console.log("deleted at : " + e.itemIndex);
                    break;
                default:
                    console.log("error");
                    break;
            }
            // Update the alarms and gets rid of the option menu
            alarmItems = createAlarmItems(alarms);
            alarmOptions.hide();
            main.section(0, section = {
                items: alarmItems
            });
        });
    }
    // Choose an option to chnage alarm
});

// Code from before, I don't currently remove it for reference
/*
// Try but doesn't work
main.on('click', 'select', function(e) {
    var item = this.items(0);
    if (item.title == "Add New Alarm") {
        Vibe.vibrate('long');
        var card = new UI.Card();
        card.title('A Card');
        card.subtitle('Is a Window');
        card.body('The simplest window type in Pebble.js.');
        card.show();
    }
});
*/

/*
main.on('click', 'up', function(e) {
    var menu = new UI.Menu({
        sections: [{
            items: [{
                title: 'Pebble.js',
                icon: 'images/menu_icon.png',
                subtitle: 'Can do Menus'
            }, {
                title: 'Second Item',
                subtitle: 'Subtitle Text'
            }]
        }]
    });
    menu.on('select', function(e) {
        console.log('Selected item #' + e.itemIndex + ' of section #' + e.sectionIndex);
        console.log('The item is titled "' + e.item.title + '"');
    });
    menu.show();
});
*/

// When click middle button
/*
main.on('click', 'up', function(e) {
    //test vibrqtion and date fubction
    console.log("foo");
    if (new Date() == new Date()) {
        Vibe.vibrate('long');
    }
    var wind = new UI.Window();
    //var time = new UI.TimeText();
    // Time in Text form
    var textfield = new UI.TimeText({
        position: new Vector2(0, 50),
        size: new Vector2(144, 30),
        font: 'gothic-24-bold',
        text: '%M:%S, %a',
        textAlign: 'center'
    });
    wind.add(textfield);
    wind.show();
});
*/

/*
main.on('click', 'down', function(e) {
    var card = new UI.Card();
    card.title('A Card');
    card.subtitle('Is a Window');
    card.body('The simplest window type in Pebble.js.');
    card.show();
});
*/
<|endoftext|>


<commit_before>var assert = require('chai').assert;
var LiveMatch = require('../src/LiveMatch');
var common = require('./common');

describe('LiveMatch', function () {
    var matchParams = Object.create(common.matchParams);
    matchParams.startTime =

    var match = new LiveMatch(matchParams);

    describe('#simulate()', function () {
        match.simulate();

        it('should return the number of goals', function () {
        });
    });
});
<commit_msg>Fixes last<commit_after>var assert = require('chai').assert;
var LiveMatch = require('../src/LiveMatch');
var common = require('./common');

describe('LiveMatch', function () {
    var matchParams = Object.create(common.matchParams);

    var match = new LiveMatch(matchParams);

    describe('#simulate()', function () {
        match.simulate();

        it('should return the number of goals', function () {
        });
    });
});
<|endoftext|>


<commit_before>var googleImages = require('google-images');
var exif = require('exif2');
var request = require('request');
var fs = require('fs');
var md5 = require('MD5');
var shredfile = require('shredfile')({});
var gui = require('nw.gui');
var exec = require('child_process').exec;
var csv = require('csv-to-json');
var http = require('http');
var urlHelper = require('url');
var fdialogs = require('node-webkit-fdialogs');

var packageJsonFile = fs.readFileSync('package.json');
packageJson = JSON.parse(packageJsonFile);
useragent = packageJson['user-agent'];

// Mouse positions; see readMouseMove().
var x;
var y;

function imageSearch(query) {
  var resultsCount = 0;
  var imagesDiv = document.getElementById('images');
  var endOfResults = document.getElementById('eor');
  var eorBreak = document.getElementById('eor-break');

  // The deprecated Google Images API only allows us to recieve a maximum
  // of 60 results.
  for (var i = 0; i < 57; i = i +4) {
    // NOTE: Eventually this should be refactored, but I'm not overly
    // concerned about it at this time.

    /* jshint loopfunc: true */
    googleImages.search(query, { page: i, proxy: getSetting('proxy'), callback: function(err, images) {
      var resultsDiv = document.getElementById('results');
      if (images[0]) {
      results.className = 'page-header';
        images.forEach(function(image) {
          // NOTE: This is a little hack I implemented to replace imgur
          // thumbnails with the full image.
          if (image.url.substring(0, 19) === 'http://i.imgur.com/') {
            image.url = image.url.replace('b.jpg', '.jpg');
          }

          resultsCount++;
          var file = fs.createWriteStream('./tmp/' + md5(image.url));
          var req = request({url: decodeURIComponent(image.url), proxy: getSetting('proxy'), headers: { 'User-Agent': useragent }});
          req.pipe(file);

          req.on('end', function() {
            exif ('./tmp/' + md5(image.url), function(err, obj) {
              var exifData = '';
              if (err === null) {
                for(var key in obj) {
                  if (obj.hasOwnProperty(key) &&
                      key !== 'exiftool version number' &&
                      key !== 'file name' &&
                      key !== 'directory' &&
                      key !== 'file inode change date time' &&
                      key !== 'file modification date time' &&
                      key !== 'file access date time' &&
                      key !== 'file permissions') {
                      exifData += ucwords(key) + ': ' + obj[key] + '
';
                  }
                }
              } else {
                exifData = err;
              }
              shredfile.shred('./tmp/' + md5(image.url), function(err, file) {

              });
              results.innerHTML = '
' + resultsCount + ' Results
';

              // If we don't have a proxy setup there's no point in trying to
              // proxy the image.
              var src = proxify_url(image.url);
              if(getSetting('proxy') === '') {
                src = image.url;
              }

              // Let's pretend I never wrote this...
              /* jshint maxlen: false */
              imagesDiv.innerHTML += '

';
              eorBreak.className = '';
              endOfResults.className = 'lead text-center text-muted';
            });
          });
        });
      } else {
        eorBreak.className = 'hidden';
        endOfResults.className = 'lead text-center text-muted hidden';
        results.className = 'page-header';
        results.innerHTML = '
No images found.
';
        return false;
      }
    }});
  }
}

/**
 * Uppercase Words
 * @param string str
 */
function ucwords(str) {
    return (str + '').replace(/^([a-z])|\s+([a-z])/g, function($1) {
        return $1.toUpperCase();
    });
}

// Stolen! Credits go to this chap: http://stackoverflow.com/users/1219011/twist
// Original: http://stackoverflow.com/a/11840120
// Modified to remove non-webkit CSS rules.
function getRotationDegrees(obj) {
  var angle;
  var matrix = obj.css('-webkit-transform') ||
  obj.css('transform');
  if (matrix !== 'none') {
    var values = matrix.split('(')[1].split(')')[0].split(',');
    var a = values[0];
    var b = values[1];
    angle = Math.round(Math.atan2(b, a) * (180/Math.PI));
  } else {
    angle = 0;
  }
  return (angle < 0) ? angle +=360 : angle;
}

function showExifData(url, data) {
  var exifData = document.getElementById('exif-data');
  var exifTitle = document.getElementById('exif-title');

  exifTitle.innerHTML = getFileName(url);
  exifData.innerHTML = window.atob(data);
  $('#exif-data-modal').modal('show');
}

function showContextMenu(url, from) {
  // TODO: Reduce the amount of statements. Yeah, this is a pile of fuck.
  /* jshint maxstatements:25 */
  var menu = new gui.Menu();
  var clipboard = gui.Clipboard.get();

  var flipImageItem = new gui.MenuItem(
    { label: 'Toggle Flip Image',
      click: function() {
        var image = $('img[src="' + url + '"]');
        if (image.hasClass('flipped')) {
          image.removeClass('flipped');
        } else {
          image.addClass('flipped');
        }
      }
    });

  // TODO: Shred images.
  var genderAgeItem = new gui.MenuItem(
    { label: 'Age/Gender (Experimental)',
      click: function() {
        var file = fs.createWriteStream('./tmp/br/' + md5(url) + '.image');
        var req = request({url: decodeURIComponent(url), proxy: getSetting('proxy'), headers: { 'User-Agent': useragent }});
        req.pipe(file);

        req.on('end', function() {
          exec('br -algorithm GenderEstimation -enroll ' + process.cwd() +
               '/tmp/br/' + md5(url) + '.image ' + process.cwd() +
               '/tmp/br/gender_' + md5(url) + '.csv', function(err, result) {
            if (err) {
              alert(err);
              return;
            }
            var genderResult = csv.parse('./tmp/br/gender_' + md5(url) +
                                         '.csv');

            var gender = genderResult[0].Gender;
            if (typeof(gender) === 'undefined') {
              gender = 'Unknown';
            }
            var genderSpan = document.getElementById('gender');
            genderSpan.innerHTML = gender;
          });

          exec('br -algorithm AgeEstimation -enroll ' + process.cwd() +
               '/tmp/br/' + md5(url) + '.image ' + process.cwd() +
               '/tmp/br/age_' + md5(url) + '.csv', function(err, result) {
            if (err) {
              alert(err);
              return;
            }
            var ageResult = csv.parse('./tmp/br/age_' + md5(url) + '.csv');

            var age = ageResult[0].Age;
            var ageSpan = document.getElementById('age');
            if (typeof(age) === 'undefined') {
              ageSpan.innerHTML = 'Unknown';
            } else {
              ageSpan.innerHTML = Math.round(age);
            }
          });
          $('#age-gender-modal').modal('show');
        });
      }
    });

  var viewFullImageItem = new gui.MenuItem(
    { label: 'View Full Image',
      click: function() {
        var src = proxify_url(url);
        if(getSetting('proxy') === '') {
          src = url;
        }

        var pwin = open('private.html');
        pwin.document.write('');
      }
    });

  var previewPageItem = new gui.MenuItem(
    { label: 'Preview Page (No Proxy)',
      click: function() {
        // Let's pretend I never wrote this...
        /* jshint maxlen: false */
        var pwin = open('private.html');
        pwin.document.write('');
      }
    });

  var rotateRightItem = new gui.MenuItem(
    { label: 'Rotate Right',
      click: function() {
        var degrees = getRotationDegrees($('img[src="' + url + '"]'));
        $('img[src="' + url + '"]').rotate(degrees + 90);
      }
    });

  var rotateLeftItem = new gui.MenuItem(
    { label: 'Rotate Left',
      click: function() {
        var degrees = getRotationDegrees($('img[src="' + url + '"]'));
        $('img[src="' + url + '"]').rotate(degrees - 90);
      }
    });

  var copyImageUrlItem = new gui.MenuItem(
    { label: 'Copy Image URL',
      click: function() {
        clipboard.set(decodeURIComponent(url), 'text');
      }
    });

  var copyPageUrlItem = new gui.MenuItem(
    { label: 'Copy Page URL',
      click: function() {
        clipboard.set(decodeURIComponent(from), 'text');
      }
    });

  var saveImageItem = new gui.MenuItem(
    { label: 'Save Image',
      click: function() {
        var imageData = '';
        var req = request({url: decodeURIComponent(url), proxy: getSetting('proxy'), encoding: 'binary', headers: { 'User-Agent': useragent }}, function(error, response, body) {
          var content = new Buffer(body, 'binary');
          var fileName = getFileName(url);

          fdialogs.saveFile(content, fileName, function (err, path) {
              if(err) {
                alert('Could not save image. Reason: ' + err);
              }
          });
        });
      }
    });

  // It's my party and I'll cry if I want to.
  menu.append(viewFullImageItem);
  menu.append(previewPageItem);
  menu.append(new gui.MenuItem({ type: 'separator' }));
  menu.append(rotateLeftItem);
  menu.append(rotateRightItem);
  menu.append(flipImageItem);
  menu.append(genderAgeItem);
  menu.append(new gui.MenuItem({ type: 'separator' }));
  menu.append(copyImageUrlItem);
  menu.append(copyPageUrlItem);
  menu.append(saveImageItem);
  menu.popup(x, y);
}

function getSetting(name) {
  var defaultSettings = {
    'proxy': '',
    'local-proxy-port': '',
    'deletion': 'shred-images'
  };

  if(localStorage.getItem(name)) {
    return localStorage.getItem(name);
  } else {
    return defaultSettings[name];
  }
}

function saveSetting(name, value) {
  localStorage.setItem(name, value);
}

function proxify_url(url) {
  return 'http://127.0.0.1:' + getSetting('local-proxy-port') +
         '/get?url=' + url;
}

function getFileName(url) {
  // NOTE: I tried to get this to unescape the file name, but failed. Epicly.
  // If you know how to do this, feel free to submit a pull request.
  var parsedUrl = urlHelper.parse(url);
  var splitUrl = parsedUrl.path.split('/');
  return splitUrl[splitUrl.length-1];
}

function readMouseMove(e) {
  x = e.clientX;
  y = e.clientY;
}

$(document).ready(function() {
  document.onmousemove = readMouseMove;

  document.onkeydown = function(e) {
    // Debug console (` key)
    if (e.keyCode === 192) {
      e.preventDefault();
      gui.Window.get().showDevTools();
      return false;
    }
  };

  http.createServer(function(req, resp) {
    if (req.url.substring(0, 9) === '/get?url=') {
      if (req.method === 'GET') {
        var imageUrl = urlHelper.parse(req.url, true);
        if(imageUrl.query.url === '') {
          resp.writeHead(200, {'Content-Type': 'text/plain'});
          resp.end('EMPTY');
          return;
        }
        request({url: decodeURIComponent(imageUrl.query.url), proxy: getSetting('proxy'), headers: { 'User-Agent': useragent }})
        .pipe(resp);
      }
    }
  }).listen(getSetting('local-proxy-port'));

  if (getSetting('proxy') === '') {
    $('#no-proxy-warning').removeClass('hidden');
  }

  // We need to reset the age and gender otherwise we're left with
  // stale data.
  $('#age-gender-modal').on('hidden.bs.modal', function () {
      $('#age').html('Waiting...');
      $('#gender').html('Waiting...');
  });

  $('a[href="#settings"]').click(function() {
    $('#' + getSetting('deletion')).prop('checked', true);
    $('#http-proxy').val(getSetting('proxy'));
    $('#local-proxy-port').val(getSetting('local-proxy-port'));
    $('#settings-modal').modal('show');
    return false;
  });

  $('a[href="#top"]').click(function() {
    $('html, body').animate({ scrollTop: 0 }, 'slow');
    return false;
  });

  $('#eor').click(function() {
    $('html, body').animate({ scrollTop: 100 }, 'slow');
    return false;
  });

  $('#save-settings').click(function() {

    if($('#http-proxy').val() !== '' && $('#local-proxy-port').val() === '') {
      alert('You must specify an unused local port to use a proxy.');
      return false;
    }

    if($('#local-proxy-port').val() !== getSetting('local-proxy-port')) {
      alert('You must restart Open Source Media for these changes to take ' +
            'effect.');
    }

    if($('#keep-images').is(':checked')) {
      saveSetting('deletion', 'keep-images');
    } else if($('#delete-images').is(':checked')) {
      saveSetting('deletion', 'delete-images');
    } else if($('#shred-images').is(':checked')) {
      saveSetting('deletion', 'shred-images');
    }

    saveSetting('local-proxy-port', $('#local-proxy-port').val());

    saveSetting('proxy', $('#http-proxy').val());

    if (getSetting('proxy') === '') {
      $('#no-proxy-warning').removeClass('hidden');
    } else {
      $('#no-proxy-warning').addClass('hidden');
    }

    $('#settings-modal').modal('hide');
  });

  $('#search-form').on('submit', function() {
    $('#images').html('');
    imageSearch($('#query').val());
    return false;
  });

});
<commit_msg>Introduce safeDecodeURIComponent()<commit_after>var googleImages = require('google-images');
var exif = require('exif2');
var request = require('request');
var fs = require('fs');
var md5 = require('MD5');
var shredfile = require('shredfile')({});
var gui = require('nw.gui');
var exec = require('child_process').exec;
var csv = require('csv-to-json');
var http = require('http');
var urlHelper = require('url');
var fdialogs = require('node-webkit-fdialogs');

var packageJsonFile = fs.readFileSync('package.json');
packageJson = JSON.parse(packageJsonFile);
useragent = packageJson['user-agent'];

// Mouse positions; see readMouseMove().
var x;
var y;

function imageSearch(query) {
  var resultsCount = 0;
  var imagesDiv = document.getElementById('images');
  var endOfResults = document.getElementById('eor');
  var eorBreak = document.getElementById('eor-break');

  // The deprecated Google Images API only allows us to recieve a maximum
  // of 60 results.
  for (var i = 0; i < 57; i = i +4) {
    // NOTE: Eventually this should be refactored, but I'm not overly
    // concerned about it at this time.

    /* jshint loopfunc: true */
    googleImages.search(query, { page: i, proxy: getSetting('proxy'), callback: function(err, images) {
      var resultsDiv = document.getElementById('results');
      if (images[0]) {
      results.className = 'page-header';
        images.forEach(function(image) {
          // NOTE: This is a little hack I implemented to replace imgur
          // thumbnails with the full image.
          if (image.url.substring(0, 19) === 'http://i.imgur.com/') {
            image.url = image.url.replace('b.jpg', '.jpg');
          }

          resultsCount++;
          var file = fs.createWriteStream('./tmp/' + md5(image.url));
          var req = request({url: safeDecodeURIComponent(image.url), proxy: getSetting('proxy'), headers: { 'User-Agent': useragent }});
          req.pipe(file);

          req.on('end', function() {
            exif ('./tmp/' + md5(image.url), function(err, obj) {
              var exifData = '';
              if (err === null) {
                for(var key in obj) {
                  if (obj.hasOwnProperty(key) &&
                      key !== 'exiftool version number' &&
                      key !== 'file name' &&
                      key !== 'directory' &&
                      key !== 'file inode change date time' &&
                      key !== 'file modification date time' &&
                      key !== 'file access date time' &&
                      key !== 'file permissions') {
                      exifData += ucwords(key) + ': ' + obj[key] + '
';
                  }
                }
              } else {
                exifData = err;
              }
              shredfile.shred('./tmp/' + md5(image.url), function(err, file) {

              });
              results.innerHTML = '
' + resultsCount + ' Results
';

              // If we don't have a proxy setup there's no point in trying to
              // proxy the image.
              var src = proxify_url(image.url);
              if(getSetting('proxy') === '') {
                src = image.url;
              }

              // Let's pretend I never wrote this...
              /* jshint maxlen: false */
              imagesDiv.innerHTML += '

';
              eorBreak.className = '';
              endOfResults.className = 'lead text-center text-muted';
            });
          });
        });
      } else {
        eorBreak.className = 'hidden';
        endOfResults.className = 'lead text-center text-muted hidden';
        results.className = 'page-header';
        results.innerHTML = '
No images found.
';
        return false;
      }
    }});
  }
}

/**
 * Uppercase Words
 * @param string str
 */
function ucwords(str) {
    return (str + '').replace(/^([a-z])|\s+([a-z])/g, function($1) {
        return $1.toUpperCase();
    });
}

// Stolen! Credits go to this chap: http://stackoverflow.com/users/1219011/twist
// Original: http://stackoverflow.com/a/11840120
// Modified to remove non-webkit CSS rules.
function getRotationDegrees(obj) {
  var angle;
  var matrix = obj.css('-webkit-transform') ||
  obj.css('transform');
  if (matrix !== 'none') {
    var values = matrix.split('(')[1].split(')')[0].split(',');
    var a = values[0];
    var b = values[1];
    angle = Math.round(Math.atan2(b, a) * (180/Math.PI));
  } else {
    angle = 0;
  }
  return (angle < 0) ? angle +=360 : angle;
}

function showExifData(url, data) {
  var exifData = document.getElementById('exif-data');
  var exifTitle = document.getElementById('exif-title');

  exifTitle.innerHTML = getFileName(url);
  exifData.innerHTML = window.atob(data);
  $('#exif-data-modal').modal('show');
}

function showContextMenu(url, from) {
  // TODO: Reduce the amount of statements. Yeah, this is a pile of fuck.
  /* jshint maxstatements:25 */
  var menu = new gui.Menu();
  var clipboard = gui.Clipboard.get();

  var flipImageItem = new gui.MenuItem(
    { label: 'Toggle Flip Image',
      click: function() {
        var image = $('img[src="' + url + '"]');
        if (image.hasClass('flipped')) {
          image.removeClass('flipped');
        } else {
          image.addClass('flipped');
        }
      }
    });

  // TODO: Shred images.
  var genderAgeItem = new gui.MenuItem(
    { label: 'Age/Gender (Experimental)',
      click: function() {
        var file = fs.createWriteStream('./tmp/br/' + md5(url) + '.image');
        var req = request({url: safeDecodeURIComponent(url), proxy: getSetting('proxy'), headers: { 'User-Agent': useragent }});
        req.pipe(file);

        req.on('end', function() {
          exec('br -algorithm GenderEstimation -enroll ' + process.cwd() +
               '/tmp/br/' + md5(url) + '.image ' + process.cwd() +
               '/tmp/br/gender_' + md5(url) + '.csv', function(err, result) {
            if (err) {
              alert(err);
              return;
            }
            var genderResult = csv.parse('./tmp/br/gender_' + md5(url) +
                                         '.csv');

            var gender = genderResult[0].Gender;
            if (typeof(gender) === 'undefined') {
              gender = 'Unknown';
            }
            var genderSpan = document.getElementById('gender');
            genderSpan.innerHTML = gender;
          });

          exec('br -algorithm AgeEstimation -enroll ' + process.cwd() +
               '/tmp/br/' + md5(url) + '.image ' + process.cwd() +
               '/tmp/br/age_' + md5(url) + '.csv', function(err, result) {
            if (err) {
              alert(err);
              return;
            }
            var ageResult = csv.parse('./tmp/br/age_' + md5(url) + '.csv');

            var age = ageResult[0].Age;
            var ageSpan = document.getElementById('age');
            if (typeof(age) === 'undefined') {
              ageSpan.innerHTML = 'Unknown';
            } else {
              ageSpan.innerHTML = Math.round(age);
            }
          });
          $('#age-gender-modal').modal('show');
        });
      }
    });

  var viewFullImageItem = new gui.MenuItem(
    { label: 'View Full Image',
      click: function() {
        var src = proxify_url(url);
        if(getSetting('proxy') === '') {
          src = url;
        }

        var pwin = open('private.html');
        pwin.document.write('');
      }
    });

  var previewPageItem = new gui.MenuItem(
    { label: 'Preview Page (No Proxy)',
      click: function() {
        // Let's pretend I never wrote this...
        /* jshint maxlen: false */
        var pwin = open('private.html');
        pwin.document.write('');
      }
    });

  var rotateRightItem = new gui.MenuItem(
    { label: 'Rotate Right',
      click: function() {
        var degrees = getRotationDegrees($('img[src="' + url + '"]'));
        $('img[src="' + url + '"]').rotate(degrees + 90);
      }
    });

  var rotateLeftItem = new gui.MenuItem(
    { label: 'Rotate Left',
      click: function() {
        var degrees = getRotationDegrees($('img[src="' + url + '"]'));
        $('img[src="' + url + '"]').rotate(degrees - 90);
      }
    });

  var copyImageUrlItem = new gui.MenuItem(
    { label: 'Copy Image URL',
      click: function() {
        clipboard.set(safeDecodeURIComponent(url), 'text');
      }
    });

  var copyPageUrlItem = new gui.MenuItem(
    { label: 'Copy Page URL',
      click: function() {
        clipboard.set(safeDecodeURIComponent(from), 'text');
      }
    });

  var saveImageItem = new gui.MenuItem(
    { label: 'Save Image',
      click: function() {
        var imageData = '';
        var req = request({url: safeDecodeURIComponent(url), proxy: getSetting('proxy'), encoding: 'binary', headers: { 'User-Agent': useragent }}, function(error, response, body) {
          var content = new Buffer(body, 'binary');
          var fileName = getFileName(url);

          fdialogs.saveFile(content, fileName, function (err, path) {
              if(err) {
                alert('Could not save image. Reason: ' + err);
              }
          });
        });
      }
    });

  // It's my party and I'll cry if I want to.
  menu.append(viewFullImageItem);
  menu.append(previewPageItem);
  menu.append(new gui.MenuItem({ type: 'separator' }));
  menu.append(rotateLeftItem);
  menu.append(rotateRightItem);
  menu.append(flipImageItem);
  menu.append(genderAgeItem);
  menu.append(new gui.MenuItem({ type: 'separator' }));
  menu.append(copyImageUrlItem);
  menu.append(copyPageUrlItem);
  menu.append(saveImageItem);
  menu.popup(x, y);
}

function getSetting(name) {
  var defaultSettings = {
    'proxy': '',
    'local-proxy-port': '',
    'deletion': 'shred-images'
  };

  if(localStorage.getItem(name)) {
    return localStorage.getItem(name);
  } else {
    return defaultSettings[name];
  }
}

function saveSetting(name, value) {
  localStorage.setItem(name, value);
}

function proxify_url(url) {
  return 'http://127.0.0.1:' + getSetting('local-proxy-port') +
         '/get?url=' + url;
}

/**
 * Takes a URL and decodes it, if possible. If it can't it returns the
 * original URL.
 * @param string url - The URL to decode.
 */
function safeDecodeURIComponent(url) {
  try {
    return decodeURIComponent(url);
  } catch (ex) {
    return url;
  }
}

function getFileName(url) {
  // NOTE: I tried to get this to unescape the file name, but failed. Epicly.
  // If you know how to do this, feel free to submit a pull request.
  var parsedUrl = urlHelper.parse(url);
  var splitUrl = parsedUrl.path.split('/');
  return splitUrl[splitUrl.length-1];
}

function readMouseMove(e) {
  x = e.clientX;
  y = e.clientY;
}

$(document).ready(function() {
  document.onmousemove = readMouseMove;

  document.onkeydown = function(e) {
    // Debug console (` key)
    if (e.keyCode === 192) {
      e.preventDefault();
      gui.Window.get().showDevTools();
      return false;
    }
  };

  http.createServer(function(req, resp) {
    if (req.url.substring(0, 9) === '/get?url=') {
      if (req.method === 'GET') {
        var imageUrl = urlHelper.parse(req.url, true);
        if(imageUrl.query.url === '') {
          resp.writeHead(200, {'Content-Type': 'text/plain'});
          resp.end('EMPTY');
          return;
        }
        request({url: safeDecodeURIComponent(imageUrl.query.url), proxy: getSetting('proxy'), headers: { 'User-Agent': useragent }})
        .pipe(resp);
      }
    }
  }).listen(getSetting('local-proxy-port'));

  if (getSetting('proxy') === '') {
    $('#no-proxy-warning').removeClass('hidden');
  }

  // We need to reset the age and gender otherwise we're left with
  // stale data.
  $('#age-gender-modal').on('hidden.bs.modal', function () {
      $('#age').html('Waiting...');
      $('#gender').html('Waiting...');
  });

  $('a[href="#settings"]').click(function() {
    $('#' + getSetting('deletion')).prop('checked', true);
    $('#http-proxy').val(getSetting('proxy'));
    $('#local-proxy-port').val(getSetting('local-proxy-port'));
    $('#settings-modal').modal('show');
    return false;
  });

  $('a[href="#top"]').click(function() {
    $('html, body').animate({ scrollTop: 0 }, 'slow');
    return false;
  });

  $('#eor').click(function() {
    $('html, body').animate({ scrollTop: 100 }, 'slow');
    return false;
  });

  $('#save-settings').click(function() {

    if($('#http-proxy').val() !== '' && $('#local-proxy-port').val() === '') {
      alert('You must specify an unused local port to use a proxy.');
      return false;
    }

    if($('#local-proxy-port').val() !== getSetting('local-proxy-port')) {
      alert('You must restart Open Source Media for these changes to take ' +
            'effect.');
    }

    if($('#keep-images').is(':checked')) {
      saveSetting('deletion', 'keep-images');
    } else if($('#delete-images').is(':checked')) {
      saveSetting('deletion', 'delete-images');
    } else if($('#shred-images').is(':checked')) {
      saveSetting('deletion', 'shred-images');
    }

    saveSetting('local-proxy-port', $('#local-proxy-port').val());

    saveSetting('proxy', $('#http-proxy').val());

    if (getSetting('proxy') === '') {
      $('#no-proxy-warning').removeClass('hidden');
    } else {
      $('#no-proxy-warning').addClass('hidden');
    }

    $('#settings-modal').modal('hide');
  });

  $('#search-form').on('submit', function() {
    $('#images').html('');
    imageSearch($('#query').val());
    return false;
  });

});
<|endoftext|>


<commit_before>import BaseTracker from './BaseTracker'

function loadFacebookPixel () {
  !function(f,b,e,v,n,t,s)
  {if(f.fbq)return;n=f.fbq=function(){n.callMethod?
    n.callMethod.apply(n,arguments):n.queue.push(arguments)};
    if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
    n.queue=[];t=b.createElement(e);t.async=!0;
    t.src=v;s=b.getElementsByTagName(e)[0];
    s.parentNode.insertBefore(t,s)}(window, document,'script',
    'https://connect.facebook.net/en_US/fbevents.js');

  fbq('init', '514962702046652');
  fbq('track', 'PageView')
}

export default class FacebookPixelTracker extends BaseTracker {
  constructor (store) {
    super()

    this.store = store
  }

  async _initializeTracker () {
    this.watchForDisableAllTrackingChanges(this.store)

    if (!this.disableAllTracking) {
      loadFacebookPixel()
    }

    this.onInitializeSuccess()
  }

  // Facebook JS automatically tracks pageviews using history API.  Their docs recommend letting
  // them manage the pageview tracking.
  async trackPageView (includeIntegrations = []) {}

  async trackEvent (action, properties = {}, includeIntegrations = []) {
    if (this.disableAllTracking) {
      return
    }

    await this.initializationComplete

    if (!includeIntegrations.includes('facebook')) {
      return
    }

    fbq('trackCustom', action, properties)
  }
}
<commit_msg>fix: disable facebook tracking for students teachers and in china<commit_after>import BaseTracker from './BaseTracker'

function loadFacebookPixel () {
  !function(f,b,e,v,n,t,s)
  {if(f.fbq)return;n=f.fbq=function(){n.callMethod?
    n.callMethod.apply(n,arguments):n.queue.push(arguments)};
    if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
    n.queue=[];t=b.createElement(e);t.async=!0;
    t.src=v;s=b.getElementsByTagName(e)[0];
    s.parentNode.insertBefore(t,s)}(window, document,'script',
    'https://connect.facebook.net/en_US/fbevents.js');

  fbq('init', '514962702046652');
  fbq('track', 'PageView')
}

export default class FacebookPixelTracker extends BaseTracker {
  constructor (store) {
    super()

    this.store = store
  }

  async _initializeTracker () {
    this.watchForDisableAllTrackingChanges(this.store)

    // Facebook pixels are currently tracked via Segment, which is enabled for all teachers so do not
    // double enable it for teachers
    const isTeacher = this.store.getters['me/isTeacher']

    const isStudent = this.store.getters['me/isStudent']
    const isChina = (window.features || {}).china

    if (!this.disableAllTracking && !isTeacher && !isStudent && !isChina) {
      loadFacebookPixel()
      this.enabled = true
    } else {
      this.enabled = false
    }

    this.onInitializeSuccess()
  }

  // Facebook JS automatically tracks pageviews using history API.  Their docs recommend letting
  // them manage the pageview tracking.
  async trackPageView (includeIntegrations = []) {}

  async trackEvent (action, properties = {}, includeIntegrations = []) {
    if (this.disableAllTracking) {
      return
    }

    await this.initializationComplete

    if (!this.enabled || !includeIntegrations.includes('facebook')) {
      return
    }

    fbq('trackCustom', action, properties)
  }
}
<|endoftext|>