<commit_before>/**
 * Created by Michael on 16/07/15.
 */
console.log('Loading function');
var colors = require('colors');
var request = require('request');
var async = require('async');
var aws = require('aws-sdk');
var s3 = new aws.S3();//{apiVersion: '2006-03-01'});
var JSZip = require("jszip");
var path = require("path");
var getFileType = require('file-type');
var crypto = require('crypto');
var uuid = require('uuid');
var fs = require('fs');
require('pro-array');
var http = require('http');

exports.handler = function(event, context) {

    console.log( "Running index.handler" );

    var settings = {
        endpoints : {
            auth :  event.api_version + "/oauth/access_token",
            images : event.api_version + "/images",
            cba : event.api_version + "/comicbookarchives",
            s3_base : process.env.S3_BASE_URL
        },
        param: {
            grant_type : process.env[event.environment + '_GRANT_TYPE'],
            client_id : process.env[event.environment + '_CLIENT_ID'],
            client_secret : process.env[event.environment + '_CLIENT_SECRET'],
            scope: process.env[event.environment + '_API_SCOPE']
        },
        access_token : null
    };

   var cba_id = event.cba_id;

    async.waterfall([
        function(callback) {//1 - Authorise
            console.log("Authenticating Client".green);

            request.post(settings.endpoints.auth , {form: settings.param}, function (error, response, body) {//TODO: This should eventually be a JSON raw body not a form
                body = JSON.parse(body);
                if (!error && response.statusCode == 200) {
                    settings.access_token = body.access_token;
                    console.log("Client successfully authenticated".green);
                    callback();
                }else{
                    context.fail(("Client authentication failed: " + JSON.parse(error)).red);
                }
            });
        },
        function(callback){
            console.log("Checking Comic Book Archive Status".green);

            request.get(settings.endpoints.cba + "/" + cba_id  ,{ headers : {'Authorization' : settings.access_token}}, function (error, response, body) {//TODO: This should eventually be a JSON raw body not a form
                body = JSON.parse(body);
                if (!error && response.statusCode == 200) {
                    cba_status = body.comic_book_archive[0].comic_book_archive_status;
                    if(cba_status == 1){
                        callback({error : "Comic Book Archive Already Successfully Processed"});
                    }
                    callback();
                }else if(response.statusCode == 404){
                    callback({error : "Comic Book Archive Not Found"});
                }
            });
        },
        function(callback) {//2 - Download Archive
            console.log("Retrieving file".green);
            request.get(event.fileLocation, {encoding: null}, function(error, response, body) {
                if (!error && response.statusCode == 200) {
                    console.log('File successfully retrieved.');
                    callback(null, body);
                }else{
                    context.fail("Error getting file: " + JSON.stringify(error).red);
                }
            });
        },
        function(filestream, callback){//3 - Process Archive
            console.log('Processing Comic Book Archive'.green);

            var zip = new JSZip(filestream);//Load archive into JSZip

            var pages = [];

            async.forEachOf(zip.files, function (file, filename, callback) {
                console.log("Processing file: ".green + filename.blue);
                if(file.dir === true){
                    console.log('Directory found.');
                    return callback();
                }

                var fileExt = path.extname(filename).split('.').join('');
                var acceptedExtensions = ['jpg', 'jpeg'];

                if(!acceptedExtensions.hasObject(fileExt)){
                    console.log('Unaccepted File type \'' + fileExt + '\' found.');
                    return callback();
                }
                var fileType = getFileType(file.asNodeBuffer());
                var basename = path.basename(filename, path.extname(filename));
                var fileSize = file.asNodeBuffer().length;

                var user_images_uploads = process.env.AWS_S3_Images;
                var user_images_uploads_key_without_ext = uuid.v4();
                var user_images_uploads_key = user_images_uploads_key_without_ext + "." + fileExt;
                var user_images_uploads_body = file.asNodeBuffer();

                var fileHash = crypto.createHash('md5').update(user_images_uploads_body).digest('hex');
                var image_exists = false;

                var image_id = "";

                async.waterfall([
                    function(callback){//Check if image exists
                        request.get(settings.endpoints.images + "?image_hash=" + fileHash, { headers : {'Authorization' : settings.access_token}}, function (error, response, body) {
                            if (error) {
                                callback({error : "Error getting file: " + JSON.stringify(error)});
                            }else {
                                callback(null, JSON.parse(body))
                            }
                        });

                    },
                    function(response, callback){
                        if(response.total == 0){//Post Image to Storage

                            console.log("Image Match Not Found".green);

                            var params = {
                                Bucket: user_images_uploads,
                                Key: user_images_uploads_key, //TODO: Consider changing key of upload to be more secure
                                Body: user_images_uploads_body,
                                ACL: 'public-read' //TODO: Change to 'authenticated-read' on production. Also maybe extract to variable
                            };

                            s3.putObject(params, function(err, data) {
                                if (err) {
                                    console.log(("Error putting object " + user_images_uploads_key + " into bucket " + user_images_uploads +
                                    ".\nMake sure they exist and your bucket is in the same region as this function.").red);
                                    //context.fail(("Error getting file: " + JSON.stringify(err)).red);
                                    callback({error : "Error getting file: " + JSON.stringify(err)});
                                } else {
                                    console.log("Image successfully uploaded".green);
                                    var upload_url = settings.endpoints.s3_base + "/"+ user_images_uploads + "/" +user_images_uploads_key; //TODO: This ideally needs to something returned from S3's upload
                                    var new_image_request = {
                                        "image_slug" : user_images_uploads_key_without_ext,
                                        "image_hash" : fileHash,
                                        "image_url" : upload_url,
                                        "image_size" : fileSize,
                                        "related_comic_book_archive_id" : cba_id
                                    };
                                    request.post(settings.endpoints.images , {body : new_image_request, json : true, headers : {'Authorization' : settings.access_token}}, function (error, response, body) {//TODO: This should eventually be a JSON raw body not a form
                                        if (!error && response.statusCode == 201) {
                                            //body = JSON.parse(body);
                                            console.log(("Image Record Succesfully added at Image ID: " + body.images[0].id).green);
                                            callback();
                                        }else{
                                            callback({error : "API Request Error: " + JSON.stringify(error)});
                                        };
                                    });
                                }
                            });

                        }else{//Attach ID to related archive.
                            console.log('Image Match Found'.blue);
                            var attachImageId = response.images[0].id;
                            request.put(settings.endpoints.cba + "/" + cba_id , {body : { "attach_image_id" : attachImageId}, json : true, headers : {'Authorization' : settings.access_token}}, function (error, response, body) {//TODO: This should eventually be a JSON raw body not a form
                                if (!error && response.statusCode == 204) {
                                    console.log(("Image ID: " + attachImageId + " success attached to " + cba_id).green);
                                    callback();
                                }else{
                                    callback({error : "API Request Error: " + JSON.stringify(error)});
                                }
                            });
                        }

                    }
                ], function(err, result){
                    if(err) {
                        callback(err);
                    }else {
                        pages[basename] = user_images_uploads_key_without_ext;
                        callback();
                    }
                });
            }, function(err){
                if(err) {
                    callback(err);
                }else {
                    callback(null, pages);
                }

            });
        },
        function(pages, callback){
            console.log('Ready to sort.'.rainbow);

            pages.natsort();
            var pages_final = [];
            for (var items in pages){
                pages_final.push(pages[items]);
            }

            pages_final.unshift('presentation_value');
            delete pages_final[0];
            pages_final = pages_final.toObject();

            //console.log(JSON.stringify(pages_final).rainbow);

            request.put(settings.endpoints.cba + "/" + cba_id , {body : { "comic_book_archive_status" : 1, "comic_book_archive_contents" : pages_final}, json : true, headers : {'Authorization' : settings.access_token}}, function (error, response, body) {//TODO: This should eventually be a JSON raw body not a form
                if (!error && response.statusCode == 204) {
                    console.log(("Comic Book Archive Update Successful").green);
                    callback();
                }else{
                    //context.fail(("API Request Error: " + JSON.stringify(error)).red);
                    callback({error : "API Request Error: " + JSON.stringify(error)});
                }
            });
        }
    ],
    function(err, results){
        //TODO: Post error to DB if fails and write to error log
        if(err){
            request.put(settings.endpoints.cba + "/" + cba_id , {body : { "comic_book_archive_status" : 2}, json : true, headers : {'Authorization' : settings.access_token}}, function (error, response, body) {
                //console.log(body.green);
                if (!error && response.statusCode == 204) {
                    console.log(("Comic Book Archive Update Successful").green);
                    context.fail("Error: "+  JSON.stringify(err));
                }else{
                    context.fail("Comic Book Archive Update Process Failed: " + error);
                }
            });
        }else {
            context.succeed('Comic Book Archive successfully processed.'.green);
        }
    });

};

Array.prototype.hasObject = (
    !Array.indexOf ? function (o)
    {
        var l = this.length + 1;
        while (l -= 1)
        {
            if (this[l - 1] === o)
            {
                return true;
            }
        }
        return false;
    } : function (o)
    {
        return (this.indexOf(o) !== -1);
    }
);
Array.prototype.toObject = function(){
    var arr = this;
    var rv = {};
    for (var i = 0; i < arr.length; ++i)
        rv[i] = arr[i];
    return rv;
};
<commit_msg>S3 buckets and now prefix with environment.<commit_after>/**
 * Created by Michael on 16/07/15.
 */
console.log('Loading function');
var colors = require('colors');
var request = require('request');
var async = require('async');
var aws = require('aws-sdk');
var s3 = new aws.S3();//{apiVersion: '2006-03-01'});
var JSZip = require("jszip");
var path = require("path");
var getFileType = require('file-type');
var crypto = require('crypto');
var uuid = require('uuid');
var fs = require('fs');
require('pro-array');
var http = require('http');

exports.handler = function(event, context) {

    console.log( "Running index.handler" );

    var settings = {
        endpoints : {
            auth :  event.api_version + "/oauth/access_token",
            images : event.api_version + "/images",
            cba : event.api_version + "/comicbookarchives",
            s3_base : process.env.S3_BASE_URL
        },
        param: {
            grant_type : process.env[event.environment + '_GRANT_TYPE'],
            client_id : process.env[event.environment + '_CLIENT_ID'],
            client_secret : process.env[event.environment + '_CLIENT_SECRET'],
            scope: process.env[event.environment + '_API_SCOPE']
        },
        access_token : null
    };

   var cba_id = event.cba_id;

    async.waterfall([
        function(callback) {//1 - Authorise
            console.log("Authenticating Client".green);

            request.post(settings.endpoints.auth , {form: settings.param}, function (error, response, body) {//TODO: This should eventually be a JSON raw body not a form
                body = JSON.parse(body);
                if (!error && response.statusCode == 200) {
                    settings.access_token = body.access_token;
                    console.log("Client successfully authenticated".green);
                    callback();
                }else{
                    context.fail(("Client authentication failed: " + JSON.parse(error)).red);
                }
            });
        },
        function(callback){
            console.log("Checking Comic Book Archive Status".green);

            request.get(settings.endpoints.cba + "/" + cba_id  ,{ headers : {'Authorization' : settings.access_token}}, function (error, response, body) {//TODO: This should eventually be a JSON raw body not a form
                body = JSON.parse(body);
                if (!error && response.statusCode == 200) {
                    cba_status = body.comic_book_archive[0].comic_book_archive_status;
                    if(cba_status == 1){
                        callback({error : "Comic Book Archive Already Successfully Processed"});
                    }
                    callback();
                }else if(response.statusCode == 404){
                    callback({error : "Comic Book Archive Not Found"});
                }
            });
        },
        function(callback) {//2 - Download Archive
            console.log("Retrieving file".green);
            request.get(event.fileLocation, {encoding: null}, function(error, response, body) {
                if (!error && response.statusCode == 200) {
                    console.log('File successfully retrieved.');
                    callback(null, body);
                }else{
                    context.fail("Error getting file: " + JSON.stringify(error).red);
                }
            });
        },
        function(filestream, callback){//3 - Process Archive
            console.log('Processing Comic Book Archive'.green);

            var zip = new JSZip(filestream);//Load archive into JSZip

            var pages = [];

            async.forEachOf(zip.files, function (file, filename, callback) {
                console.log("Processing file: ".green + filename.blue);
                if(file.dir === true){
                    console.log('Directory found.');
                    return callback();
                }

                var fileExt = path.extname(filename).split('.').join('');
                var acceptedExtensions = ['jpg', 'jpeg'];

                if(!acceptedExtensions.hasObject(fileExt)){
                    console.log('Unaccepted File type \'' + fileExt + '\' found.');
                    return callback();
                }
                var fileType = getFileType(file.asNodeBuffer());
                var basename = path.basename(filename, path.extname(filename));
                var fileSize = file.asNodeBuffer().length;

                var user_images_uploads = process.env[ event.environment + 'AWS_S3_Images'];
                var user_images_uploads_key_without_ext = uuid.v4();
                var user_images_uploads_key = user_images_uploads_key_without_ext + "." + fileExt;
                var user_images_uploads_body = file.asNodeBuffer();

                var fileHash = crypto.createHash('md5').update(user_images_uploads_body).digest('hex');
                var image_exists = false;

                var image_id = "";

                async.waterfall([
                    function(callback){//Check if image exists
                        request.get(settings.endpoints.images + "?image_hash=" + fileHash, { headers : {'Authorization' : settings.access_token}}, function (error, response, body) {
                            if (error) {
                                callback({error : "Error getting file: " + JSON.stringify(error)});
                            }else {
                                callback(null, JSON.parse(body))
                            }
                        });

                    },
                    function(response, callback){
                        if(response.total == 0){//Post Image to Storage

                            console.log("Image Match Not Found".green);

                            var params = {
                                Bucket: user_images_uploads,
                                Key: user_images_uploads_key, //TODO: Consider changing key of upload to be more secure
                                Body: user_images_uploads_body,
                                ACL: 'public-read' //TODO: Change to 'authenticated-read' on production. Also maybe extract to variable
                            };

                            s3.putObject(params, function(err, data) {
                                if (err) {
                                    console.log(("Error putting object " + user_images_uploads_key + " into bucket " + user_images_uploads +
                                    ".\nMake sure they exist and your bucket is in the same region as this function.").red);
                                    //context.fail(("Error getting file: " + JSON.stringify(err)).red);
                                    callback({error : "Error getting file: " + JSON.stringify(err)});
                                } else {
                                    console.log("Image successfully uploaded".green);
                                    var upload_url = settings.endpoints.s3_base + "/"+ user_images_uploads + "/" +user_images_uploads_key; //TODO: This ideally needs to something returned from S3's upload
                                    var new_image_request = {
                                        "image_slug" : user_images_uploads_key_without_ext,
                                        "image_hash" : fileHash,
                                        "image_url" : upload_url,
                                        "image_size" : fileSize,
                                        "related_comic_book_archive_id" : cba_id
                                    };
                                    request.post(settings.endpoints.images , {body : new_image_request, json : true, headers : {'Authorization' : settings.access_token}}, function (error, response, body) {//TODO: This should eventually be a JSON raw body not a form
                                        if (!error && response.statusCode == 201) {
                                            //body = JSON.parse(body);
                                            console.log(("Image Record Succesfully added at Image ID: " + body.images[0].id).green);
                                            callback();
                                        }else{
                                            callback({error : "API Request Error: " + JSON.stringify(error)});
                                        };
                                    });
                                }
                            });

                        }else{//Attach ID to related archive.
                            console.log('Image Match Found'.blue);
                            var attachImageId = response.images[0].id;
                            request.put(settings.endpoints.cba + "/" + cba_id , {body : { "attach_image_id" : attachImageId}, json : true, headers : {'Authorization' : settings.access_token}}, function (error, response, body) {//TODO: This should eventually be a JSON raw body not a form
                                if (!error && response.statusCode == 204) {
                                    console.log(("Image ID: " + attachImageId + " success attached to " + cba_id).green);
                                    callback();
                                }else{
                                    callback({error : "API Request Error: " + JSON.stringify(error)});
                                }
                            });
                        }

                    }
                ], function(err, result){
                    if(err) {
                        callback(err);
                    }else {
                        pages[basename] = user_images_uploads_key_without_ext;
                        callback();
                    }
                });
            }, function(err){
                if(err) {
                    callback(err);
                }else {
                    callback(null, pages);
                }

            });
        },
        function(pages, callback){
            console.log('Ready to sort.'.rainbow);

            pages.natsort();
            var pages_final = [];
            for (var items in pages){
                pages_final.push(pages[items]);
            }

            pages_final.unshift('presentation_value');
            delete pages_final[0];
            pages_final = pages_final.toObject();

            //console.log(JSON.stringify(pages_final).rainbow);

            request.put(settings.endpoints.cba + "/" + cba_id , {body : { "comic_book_archive_status" : 1, "comic_book_archive_contents" : pages_final}, json : true, headers : {'Authorization' : settings.access_token}}, function (error, response, body) {//TODO: This should eventually be a JSON raw body not a form
                if (!error && response.statusCode == 204) {
                    console.log(("Comic Book Archive Update Successful").green);
                    callback();
                }else{
                    //context.fail(("API Request Error: " + JSON.stringify(error)).red);
                    callback({error : "API Request Error: " + JSON.stringify(error)});
                }
            });
        }
    ],
    function(err, results){
        //TODO: Post error to DB if fails and write to error log
        if(err){
            request.put(settings.endpoints.cba + "/" + cba_id , {body : { "comic_book_archive_status" : 2}, json : true, headers : {'Authorization' : settings.access_token}}, function (error, response, body) {
                //console.log(body.green);
                if (!error && response.statusCode == 204) {
                    console.log(("Comic Book Archive Update Successful").green);
                    context.fail("Error: "+  JSON.stringify(err));
                }else{
                    context.fail("Comic Book Archive Update Process Failed: " + error);
                }
            });
        }else {
            context.succeed('Comic Book Archive successfully processed.'.green);
        }
    });

};

Array.prototype.hasObject = (
    !Array.indexOf ? function (o)
    {
        var l = this.length + 1;
        while (l -= 1)
        {
            if (this[l - 1] === o)
            {
                return true;
            }
        }
        return false;
    } : function (o)
    {
        return (this.indexOf(o) !== -1);
    }
);
Array.prototype.toObject = function(){
    var arr = this;
    var rv = {};
    for (var i = 0; i < arr.length; ++i)
        rv[i] = arr[i];
    return rv;
};
<|endoftext|>


<commit_before>var ddg = require('ddg')
  , commands

commands = [
    '!search'
  , '!whats'
  , '!ddg'
]

notfound = [
    'I don\'t know what that is.'
    ,'You can expect me to know everything!'
    ,'Well if you don\'t know, how am I expected to know?'
]

module.exports = search

function search(ziggy) {
  ziggy.on('message', parse_message)
  ziggy.on('pm', parse_pm)

  function parse_message(user, channel, text) {
    var bits = text.split(/\s+/)

    var command = bits[0]
      , query

    query = bits.slice(1).join(' ').trim()

    if (commands.indexOf(command) === -1) return

    ddg.query(query, display_result)

    function display_result(err, data) {
      if (err) return ziggy.say(channel, 'Not right now, ask later.')

      var result = data.AbstractText ||
          remove_def(data.Definition) ||
          (data.RelatedTopics && data.RelatedTopics.length &&
           data.RelatedTopics[0].Text) ||
          notfound[Math.floor(Math.random() * notfound.length)];

      ziggy.say(channel, result)
    }
    function remove_def(text) {
      return text.replace(query + ' definition', query)
    }
  }

  function parse_pm(user, text) {
    parse_message(user, user.nick, text)
  }
}
<commit_msg>Update index.js<commit_after>var ddg = require('ddg')
  , commands

commands = [
    '!search'
  , '!whats'
  , '!ddg'
]

notfound = [
    'I don\'t know what that is.'
    ,'You can expect me to know everything!'
    ,'Well if you don\'t know, how am I expected to know?'
]

module.exports = search

function search(ziggy) {
  ziggy.on('message', parse_message)
  ziggy.on('pm', parse_pm)

  function parse_message(user, channel, text) {
    var bits = text.split(/\s+/)

    var command = bits[0]
      , query

    query = bits.slice(1).join(' ').trim()

    if (commands.indexOf(command) === -1) return

    ddg.query(query, display_result)

    function display_result(err, data) {
      if (err) return ziggy.say(channel, 'Not right now, ask later.')

      var result = data.AbstractText ||
          remove_def(data.Definition) ||
          (data.RelatedTopics && data.RelatedTopics.length &&
           data.RelatedTopics[0].Text) ||
          var notfound[Math.floor(Math.random() * notfound.length)]

      ziggy.say(channel, result)
    }
    function remove_def(text) {
      return text.replace(query + ' definition', query)
    }
  }

  function parse_pm(user, text) {
    parse_message(user, user.nick, text)
  }
}
<|endoftext|>


<commit_before>/*
 * fis
 * http://fis.baidu.com/
 */

'use strict';

var messages = require('./node_modules/jshint/src/messages.js');
var JSHINT = require("jshint").JSHINT;
var ignored, globals, i18n = {};
var po = {
    'zh-CN' : {
        "Missing semicolon." : "缺少分号.",
        "Use the function form of \"use strict\"." : "使用标准化定义function.",
        "Unexpected space after '-'." : "在'-'后面不应出现空格.",
        "Expected a JSON value." : "请传入一个json的值.",
        "Mixed spaces and tabs.": "空格和TAB重复.",
        "Unsafe character." : "不安全的字符.",
        "Line too long.": "本行中的字符超过设定的最大长度.",
        "Trailing whitespace.": "本行末尾有过多无用空格.",
        "Script URL." : "脚本URL.",
        "Unexpected {a} in '{b}'." : "在 '{b}' 中不该出现 {a}.",
        "Unexpected '{a}'." : "不该在此出现'{a}'.",
        "Strings must use doublequote." : "字符串需要用双引号",
        "Unnecessary escapement." : "不需要转义",
        "Control character in string: {a}." : "在字符串中出现了Control的字符",
        "Avoid \\'." : "避免 \\",
        "Avoid \\v." : "避免 \\v",
        "Avoid \\x-." : "避免 \\x-",
        "Use '{a}' to compare with '{b}'." : "使用'{a}'与'{b}'比较",
        "Bad escapement." : "错误的转义字符",
        "Bad number '{a}'." : "错误的数字 '{a}'",
        "Missing space after '{a}'." : "在'{a}'之后缺少空格",
        "Don't use extra leading zeros '{a}'." : "不要再'{a}'的前面用多余的0",
        "Avoid 0x-. '{a}'." : "避免使用 0x-. '{a}'.",
        "A trailing decimal point can be confused with a dot '{a}'." : "在'{a}'中使用点尾随小数点",
        "Unexpected comment." : "不该在此处出现注释",
        "Unescaped '{a}'." : "没有转义 '{a}'",
        "Unexpected control character in regular expression." : "在正则表达式中出现了control字符",
        "Unexpected escaped character '{a}' in regular expression." : "在正则表达式中出现了没有转义的字符 '{a}'",
        "Expected '{a}' and instead saw '{b}'." : "应该用 '{a}'代替'{b}'",
        "Spaces are hard to count. Use {{a}}." : "空格难以统计，请使用 {{a}}",
        "Insecure '{a}'." : "不安全的 '{a}'",
        "Empty class." : "空的class",
        "Expected a number and instead saw '{a}'.":"应该用数字代替'{a}'",
        "'{a}' should not be greater than '{b}'.":"'{a}'不应该比'{b}'大",
        "'hasOwnProperty' is a really bad name.": "'hasOwnProperty'是关键字",
        "'{a}' was used before it was defined.":"'{a}'未定义就已经使用了.",
        "'{a}' is already defined.":"'{a}'被重复定义",
        "A dot following a number can be confused with a decimal point.":"数字后面的一个点会被误认为是十进制的小数点",
        "Confusing minusses" : "容易混淆的负数表达-",
        "Confusing plusses." : "容易混淆的正数表达+",
        "Unmatched '{a}'." : "无法匹配的'{a}'",
        "Expected '{a}' to match '{b}' from line {c} and instead saw '{d}'.":"在行{c}中需要用'{a}'和'{b}'匹配，用来代替'{d}'",
        "Unexpected early end of program.":"程序不可预期的提前终止",
        "A leading decimal point can be confused with a dot: '.{a}'.":"'{a}'前的点容易混淆成小数点",
        "Use the array literal notation [].":"使用数组的符号 []",
        "Expected an operator and instead saw '{a}'.":"需要用一个符号来代替'{a}'",
        "Unexpected space after '{a}'.":"在'{a}'之后不能出现空格",
        "Unexpected space before '{a}'.":"在'{a}'之前不能出现空格",
        "Bad line breaking before '{a}'.":"在'{a}'之前错误的换行",
        "Expected '{a}' to have an indentation at {b} instead at {c}.":"'{a}'需要在{c}而不是{b}处缩进",
        "Line breaking error '{a}'.":"换行错误 '{a}'",
        "Unexpected use of '{a}'.":"此处不能用'{a}'",
        "Bad operand.":"错误的操作数",
        "Use the isNaN function to compare with NaN.":"使用isNaN来与NaN比较",
        "Confusing use of '{a}'.":"容易混淆的'{a}'的使用",
        "Read only.":"只读的属性",
        "'{a}' is a function.":"'{a}'是一个函数",
        "Bad assignment." : "错误的赋值",
        "Did you mean to return a conditional instead of an assignment?" : "你是否想返回条件判断结果，而不是赋值运算?",
        "Do not assign to the exception parameter.":"不要给额外的参数赋值",
        "Expected an identifier in an assignment and instead saw a function invocation.":"在赋值的语句中需要有一个标识符，而不是一个方法的调用",
        "Expected an identifier and instead saw '{a}' (a reserved word).":"需要有一个标识符，而不是'{a}'(保留字符)",
        "Missing name in function declaration.":"在方法声明中缺少名称",
        "Expected an identifier and instead saw '{a}'.":"需要有一个标识符，而不是'{a}'",
        "Inner functions should be listed at the top of the outer function.":"内部函数的声明应该放在此函数的顶部。",
        "Unreachable '{a}' after '{b}'.":"在'{b}'之后无法获取'{a}'",
        "Unnecessary semicolon.":"不必要的分号",
        "Label '{a}' on {b} statement.":"将'{a}'放在{b}的声明中",
        "Label '{a}' looks like a javascript url.":"'{a}'看上去像一个js的链接",
        "Expected an assignment or function call and instead saw an expression":"需要一个赋值或者一个函数调用，而不是一个表达式.",
        "Do not use 'new' for side effects.":"不要用'new'语句.",
        "Unnecessary \"use strict\".":"不必要的\"use strict\".",
        "Missing \"use strict\" statement.":"缺少\"use strict\"的声明",
        "Empty block.":"空的模块",
        "Unexpected /*member '{a}'.":"不应出现 /*元素 '{a}'.",
        "'{a}' is a statement label.":"'{a}'是一个声明",
        "'{a}' used out of scope.":"'{a}'使用超出范围",
        "'{a}' is not allowed.":"不允许使用'{a}'",
        "'{a}' is not defined.":"'{a}'没有被定义",
        "Use '{a}' to compare with '{b}'.":"使用'{a}'与'{b}'相比",
        "Variables should not be deleted.":"变量需要被删除",
        "Use the object literal notation {}.":"使用对象的文字符号 {}",
        "Do not use {a} as a constructor.":"不要使用{a}作为一个构造对象",
        "The Function constructor is a form of eval.":"函数构造器是一种eval语句.",
        "A constructor name should start with an uppercase letter.":"一个构造对象的名称必须用大写字母开头.",
        "Bad constructor.":"错误的构造对象",
        "Weird construction. Delete 'new'.":"构造对象有误，请删除'new'",
        "Missing '()' invoking a constructor.":"缺少括号()",
        "Avoid arguments.{a}.":"避免参数.{a}.",
        "document.write can be a form of eval.":"document.write是eval的一种形式",
        "eval is evil.":"尽量不要使用eval",
        "Math is not a function.":"Math不是一个函数",
        "Missing 'new' prefix when invoking a constructor.":"此处缺少了'new'",
        "Missing radix parameter.":"缺少参数",
        "Implied eval is evil. Pass a function instead of a string.":"传递一个函数，而不是一个字符串",
        "Bad invocation.":"错误的调用",
        "['{a}'] is better written in dot notation.":"['{a}']最好用点.的方式",
        "Extra comma.":"多余的逗号",
        "Don't make functions within a loop.":"不要用循环的方式创建函数",
        "Unexpected parameter '{a}' in get {b} function.":"在{b}方法中不该用到参数'{a}'",
        "Duplicate member '{a}'.":"重复的'{a}'",
        "Expected to see a statement and instead saw a block.":"此处应该是语句声明.",
        "Too many var statements.":"过多var的声明",
        "Redefinition of '{a}'.":"'{a}'被重复定义",
        "It is not necessary to initialize '{a}' to 'undefined'.":"无需将'{a}'初始化为'undefined'",
        "Expected a conditional expression and instead saw an assignment.":"此处需要一个表达式，而不是赋值语句",
        "Expected a 'break' statement before 'case'.":"在'case'之前需要有'break'.",
        "Expected a 'break' statement before 'default'.":"在'default'之前需要有'break'.",
        "This 'switch' should be an 'if'.":"此处'switch'应该是'if'.",
        "All 'debugger' statements should be removed.":"请删除'debugger'的语句",
        "'{a}' is not a statement label.":"'{a}'不是一个声明标签.",
        "Expected an assignment or function call and instead saw an expression.":"需要一个语句或者一个函数调用，而不是一个表达式",
        "Function declarations should not be placed in blocks. Use a function expression or move the statement to the top of the outer function.":"函数的声明不能放在类似if的块中，需要放在外部函数的顶部."
    }
};

module.exports = function(content, file, conf){
    if(conf.ignored){
        if(typeof conf.ignored === 'string' || fis.util.is(conf.ignored, 'RegExp')){
            ignored = [ conf.ignored ];
        } else if(fis.util.is(conf.ignored, 'Array')) {
            ignored = conf.ignored;
        }
        delete conf.ignored;
    }
    if(ignored){
        for(var i = 0, len = ignored.length; i < len; i++){
            if(fis.util.filter(file.subpath, ignored[i])) return;
        }
    }
    if(conf.globals){
        globals = conf.globals;
        delete conf.globals;
    }
    if(conf.i18n && po[conf.i18n]){
        fis.util.map(messages.errors, function(code, msg){
            if(po[conf.i18n][msg.desc]){
                msg.desc = po[conf.i18n][msg.desc]
            }
        });
        fis.util.map(messages.info, function(code, msg){
            if(po[conf.i18n][msg.desc]){
                msg.desc = po[conf.i18n][msg.desc]
            }
        });
        fis.util.map(messages.warnings, function(code, msg){
            if(po[conf.i18n][msg.desc]){
                msg.desc = po[conf.i18n][msg.desc]
            }
        });
        delete conf.i18n;
    }
    delete conf.filename;
    if(!JSHINT(content, conf, globals)){
        var errors = JSHINT.data().errors;
        for(var j = 0, err; err = errors[j]; j++){
            var reason = i18n[err.reason] || err.reason;
            var msg = 'lint.jshint : ' + reason + ' [' + file.subpath + ':' + err.line + ':' + err.character + ']';
            if(err.code[0] === 'E'){
                fis.log.error(msg);
            } else {
                fis.log.warning(msg);
            }
        }
    }
};

//module.exports.defaultOptions = {
//    maxerr : 100
//};<commit_msg>[UPD]增加错误代号<commit_after>/*
 * fis
 * http://fis.baidu.com/
 */

'use strict';

var messages = require('./node_modules/jshint/src/messages.js');
var JSHINT = require("jshint").JSHINT;
var ignored, globals, i18n = {};
var po = {
    'zh-CN' : {
        "Missing semicolon." : "缺少分号.",
        "Use the function form of \"use strict\"." : "使用标准化定义function.",
        "Unexpected space after '-'." : "在'-'后面不应出现空格.",
        "Expected a JSON value." : "请传入一个json的值.",
        "Mixed spaces and tabs.": "空格和TAB重复.",
        "Unsafe character." : "不安全的字符.",
        "Line too long.": "本行中的字符超过设定的最大长度.",
        "Trailing whitespace.": "本行末尾有过多无用空格.",
        "Script URL." : "脚本URL.",
        "Unexpected '{a}' in '{b}'." : "在 '{b}' 中不该出现 {a}.",
        "Unexpected '{a}'." : "不该在此出现'{a}'.",
        "Strings must use doublequote." : "字符串需要用双引号",
        "Unnecessary escapement." : "不需要转义",
        "Control character in string: {a}." : "在字符串中出现了Control的字符",
        "Avoid \\'." : "避免 \\",
        "Avoid \\v." : "避免 \\v",
        "Avoid \\x-." : "避免 \\x-",
        "Use {a}' to compare with '{b}'." : "使用'{a}'与'{b}'比较",
        "Bad escapement." : "错误的转义字符",
        "Bad number '{a}'." : "错误的数字 '{a}'",
        "Missing space after '{a}'." : "在'{a}'之后缺少空格",
        "Don't use extra leading zeros '{a}'." : "不要再'{a}'的前面用多余的0",
        "Avoid 0x-. '{a}'." : "避免使用 0x-. '{a}'.",
        "A trailing decimal point can be confused with a dot '{a}'." : "在'{a}'中使用点尾随小数点",
        "Unexpected comment." : "不该在此处出现注释",
        "Unescaped '{a}'." : "没有转义 '{a}'",
        "Unexpected control character in regular expression." : "在正则表达式中出现了control字符",
        "Unexpected escaped character '{a}' in regular expression." : "在正则表达式中出现了没有转义的字符 '{a}'",
        "Expected '{a}' and instead saw '{b}'." : "应该用 '{a}'代替'{b}'",
        "Spaces are hard to count. Use {{a}}." : "空格难以统计，请使用 {{a}}",
        "Insecure '{a}'." : "不安全的 '{a}'",
        "Empty class." : "空的class",
        "Expected a number and instead saw '{a}'.":"应该用数字代替'{a}'",
        "'{a}' should not be greater than '{b}'.":"'{a}'不应该比'{b}'大",
        "'hasOwnProperty' is a really bad name.": "'hasOwnProperty'是关键字",
        "'{a}' was used before it was defined.":"'{a}'未定义就已经使用了.",
        "'{a}' is already defined.":"'{a}'被重复定义",
        "A dot following a number can be confused with a decimal point.":"数字后面的一个点会被误认为是十进制的小数点",
        "Confusing minusses" : "容易混淆的负数表达-",
        "Confusing plusses." : "容易混淆的正数表达+",
        "Unmatched '{a}'." : "无法匹配的'{a}'",
        "Expected '{a}' to match '{b}' from line {c} and instead saw '{d}'.":"在行{c}中需要用'{a}'和'{b}'匹配，用来代替'{d}'",
        "Unexpected early end of program.":"程序不可预期的提前终止",
        "A leading decimal point can be confused with a dot: '.{a}'.":"'{a}'前的点容易混淆成小数点",
        "Use the array literal notation [].":"使用数组的符号 []",
        "Expected an operator and instead saw '{a}'.":"需要用一个符号来代替'{a}'",
        "Unexpected space after '{a}'.":"在'{a}'之后不能出现空格",
        "Unexpected space before '{a}'.":"在'{a}'之前不能出现空格",
        "Bad line breaking before '{a}'.":"在'{a}'之前错误的换行",
        "Expected '{a}' to have an indentation at {b} instead at {c}.":"'{a}'需要在{c}而不是{b}处缩进",
        "Line breaking error '{a}'.":"换行错误 '{a}'",
        "Unexpected use of '{a}'.":"此处不能用'{a}'",
        "Bad operand.":"错误的操作数",
        "Use the isNaN function to compare with NaN.":"使用isNaN来与NaN比较",
        "Confusing use of '{a}'.":"容易混淆的'{a}'的使用",
        "Read only.":"只读的属性",
        "'{a}' is a function.":"'{a}'是一个函数",
        "Bad assignment." : "错误的赋值",
        "Did you mean to return a conditional instead of an assignment?" : "你是否想返回条件判断结果，而不是赋值运算?",
        "Do not assign to the exception parameter.":"不要给额外的参数赋值",
        "Expected an identifier in an assignment and instead saw a function invocation.":"在赋值的语句中需要有一个标识符，而不是一个方法的调用",
        "Expected an identifier and instead saw '{a}' (a reserved word).":"需要有一个标识符，而不是'{a}'(保留字符)",
        "Missing name in function declaration.":"在方法声明中缺少名称",
        "Expected an identifier and instead saw '{a}'.":"需要有一个标识符，而不是'{a}'",
        "Inner functions should be listed at the top of the outer function.":"内部函数的声明应该放在此函数的顶部。",
        "Unreachable '{a}' after '{b}'.":"在'{b}'之后无法获取'{a}'",
        "Unnecessary semicolon.":"不必要的分号",
        "Label '{a}' on {b} statement.":"将'{a}'放在{b}的声明中",
        "Label '{a}' looks like a javascript url.":"'{a}'看上去像一个js的链接",
        "Expected an assignment or function call and instead saw an expression":"需要一个赋值或者一个函数调用，而不是一个表达式.",
        "Do not use 'new' for side effects.":"不要用'new'语句.",
        "Unnecessary \"use strict\".":"不必要的\"use strict\".",
        "Missing \"use strict\" statement.":"缺少\"use strict\"的声明",
        "Empty block.":"空的模块",
        "Unexpected /*member '{a}'.":"不应出现 /*元素 '{a}'.",
        "'{a}' is a statement label.":"'{a}'是一个声明",
        "'{a}' used out of scope.":"'{a}'使用超出范围",
        "'{a}' is not allowed.":"不允许使用'{a}'",
        "'{a}' is not defined.":"'{a}'没有被定义",
        "Use '{a}' to compare with '{b}'.":"使用'{a}'与'{b}'相比",
        "Variables should not be deleted.":"变量需要被删除",
        "Use the object literal notation {}.":"使用对象的文字符号 {}",
        "Do not use {a} as a constructor.":"不要使用{a}作为一个构造对象",
        "The Function constructor is a form of eval.":"函数构造器是一种eval语句.",
        "A constructor name should start with an uppercase letter.":"一个构造对象的名称必须用大写字母开头.",
        "Bad constructor.":"错误的构造对象",
        "Weird construction. Delete 'new'.":"构造对象有误，请删除'new'",
        "Missing '()' invoking a constructor.":"缺少括号()",
        "Avoid arguments.{a}.":"避免参数.{a}.",
        "document.write can be a form of eval.":"document.write是eval的一种形式",
        "eval is evil.":"尽量不要使用eval",
        "Math is not a function.":"Math不是一个函数",
        "Missing 'new' prefix when invoking a constructor.":"此处缺少了'new'",
        "Missing radix parameter.":"缺少参数",
        "Implied eval is evil. Pass a function instead of a string.":"传递一个函数，而不是一个字符串",
        "Bad invocation.":"错误的调用",
        "['{a}'] is better written in dot notation.":"['{a}']最好用点.的方式",
        "Extra comma.":"多余的逗号",
        "Don't make functions within a loop.":"不要用循环的方式创建函数",
        "Unexpected parameter '{a}' in get {b} function.":"在{b}方法中不该用到参数'{a}'",
        "Duplicate member '{a}'.":"重复的'{a}'",
        "Expected to see a statement and instead saw a block.":"此处应该是语句声明.",
        "Too many var statements.":"过多var的声明",
        "Redefinition of '{a}'.":"'{a}'被重复定义",
        "It is not necessary to initialize '{a}' to 'undefined'.":"无需将'{a}'初始化为'undefined'",
        "Expected a conditional expression and instead saw an assignment.":"此处需要一个表达式，而不是赋值语句",
        "Expected a 'break' statement before 'case'.":"在'case'之前需要有'break'.",
        "Expected a 'break' statement before 'default'.":"在'default'之前需要有'break'.",
        "This 'switch' should be an 'if'.":"此处'switch'应该是'if'.",
        "All 'debugger' statements should be removed.":"请删除'debugger'的语句",
        "'{a}' is not a statement label.":"'{a}'不是一个声明标签.",
        "Expected an assignment or function call and instead saw an expression.":"需要一个语句或者一个函数调用，而不是一个表达式",
        "Function declarations should not be placed in blocks. Use a function expression or move the statement to the top of the outer function.":"函数的声明不能放在类似if的块中，需要放在外部函数的顶部."
    }
};

module.exports = function(content, file, conf){
    if(conf.ignored){
        if(typeof conf.ignored === 'string' || fis.util.is(conf.ignored, 'RegExp')){
            ignored = [ conf.ignored ];
        } else if(fis.util.is(conf.ignored, 'Array')) {
            ignored = conf.ignored;
        }
        delete conf.ignored;
    }
    if(ignored){
        for(var i = 0, len = ignored.length; i < len; i++){
            if(fis.util.filter(file.subpath, ignored[i])) return;
        }
    }
    if(conf.globals){
        globals = conf.globals;
        delete conf.globals;
    }
    if(conf.i18n && po[conf.i18n]){
        fis.util.map(messages.errors, function(code, msg){
            if(po[conf.i18n][msg.desc]){
                msg.desc = po[conf.i18n][msg.desc]
            }
        });
        fis.util.map(messages.info, function(code, msg){
            if(po[conf.i18n][msg.desc]){
                msg.desc = po[conf.i18n][msg.desc]
            }
        });
        fis.util.map(messages.warnings, function(code, msg){
            if(po[conf.i18n][msg.desc]){
                msg.desc = po[conf.i18n][msg.desc]
            }
        });
        delete conf.i18n;
    }
    delete conf.filename;
    if(!JSHINT(content, conf, globals)){
        var errors = JSHINT.data().errors;
        for(var j = 0, err; err = errors[j]; j++){
            var reason = i18n[err.reason] || err.reason;
            // console.log(err);
            var msg = 'lint.jshint : ' + reason + ' [' + file.subpath + ':' + err.line + ':' + err.character + ':' + err.code +']';
            if(err.code[0] === 'E'){
                fis.log.error(msg);
            } else {
                fis.log.warning(msg);
            }
        }
    }
};

//module.exports.defaultOptions = {
//    maxerr : 100
//};<|endoftext|>


<commit_before>import { NativeModules } from 'react-native';
const { AppMetrica } = NativeModules;

export default {

    /**
     * Starts the statistics collection process.
     * @param {string} apiKey
     */
    activateWithApiKey(apiKey) {
        AppMetrica.activateWithApiKey(apiKey);
    },

    /**
     * Sends a custom event message and additional parameters (optional).
     * @param {string} message
     * @param {object} [params=null]
     */
    reportEvent(message, params = null) {
        AppMetrica.reportEvent(message, params);
    },
};
<commit_msg>reportError in js<commit_after>import { NativeModules } from 'react-native';
const { AppMetrica } = NativeModules;

export default {

    /**
     * Starts the statistics collection process.
     * @param {string} apiKey
     */
    activateWithApiKey(apiKey) {
        AppMetrica.activateWithApiKey(apiKey);
    },

    /**
     * Sends a custom event message and additional parameters (optional).
     * @param {string} message
     * @param {object} [params=null]
     */
    reportEvent(message, params = null) {
        AppMetrica.reportEvent(message, params);
    },

    /**
     * Sends error with reason.
     * @param {string} error
     * @param {object} reason
     */
    reportError(error, reason) {
        AppMetrica.reportError(error, reason);
    },
};
<|endoftext|>


<commit_before>var express = require('express'),
  nconf = require('nconf'),
  lazy = require("lazy"),
  childProcess = require('child_process'),
  app = express();

nconf.argv().env();
nconf.file("./config.json");
nconf.load();

var stripWindowsServiceCLILine = function (ioLine) {
  ioLine = ioLine.trim();
  switch (ioLine) {
    case "These Windows services are started:":
    case "The command completed successfully.": return "";
    default: return ioLine;
  }
};

var getServices = function (filter, callback) {
  var child = childProcess.spawn("net", ['start']);
  var errData = '';
  var services = [];
  child.stderr.on('data', function (chunk){
    errData += chunk;
  });
  child.on('exit', function () {
    if (errData) {
      console.log(errData);
      return callback(errData, []);
    }

    callback(undefined, services);
  });

  lazy(child.stdout)
    .lines
    .map(String)
    .skip(2)
    .map(stripWindowsServiceCLILine)
    .filter(function (service){
      if (filter) {
        return service && service.toLowerCase() === filter.toLowerCase()
      }
      else {
        //Ensure service isn't blank
        return service;
      }
    })
    .forEach(function(service){
      services.push(service);
    });
};

app.get('/info/:service', function (req, res) {
  var host = server.address().address;
  if (host === '::') {
    host = "localhost";
  }
  var port = server.address().port;

  res.json({
    "description": "Windows Service is monitored by a REST API - https://github.com/thealah/rest-windows-service-health-fascade",
    "windowsService": req.params.service,
    "serverHost": host,
    "serverPort": port,
    "ui": {
      "hide": ["serverHost", "serverPort"]
    }
  });
  res.end();
});

app.get('/:service', function (req, res) {
  var serviceFilter = req.params.service;
  if (!serviceFilter) {
    response.badRequest(res, "Invalid Service Name");
    return;
  }

  getServices(serviceFilter, function (err, services) {
    if (err) {
      res.status(500).json({
        "type": "Windows Service",
        "message": "Error reading Windows Services",
        "ui": {
          "info": "/info/" + encodeURIComponent(serviceFilter)
        }
      });
    }
    else if (!services.length) {
      res.status(502).json({
        "type": "Windows Service",
        "message": "Missing Windows Service '" + serviceFilter + "' or it is stopped",
        "ui": {
          "info": "/info/" + encodeURIComponent(serviceFilter)
        }
      });
    }
    else {
      res.json({
        "type": "Windows Service",
        "ui": {
          "info": "/info/" + encodeURIComponent(services[0])
        }
      });
    }
    res.end();
  });
});

app.get('/', function (req, res) {
  getServices(undefined, function (err, services) {
    if (err) {
      res.status(500);
    }
    else {
      res.json({
        "services": services,
        "message": "To use the healthcheck portion of the API, use the route: /$WINDOWS_SERVICE_NAME"
      });
    }
    res.end();
  });
});

var server = app.listen(nconf.get('port') || 3000, function () {
  var host = server.address().address;
  if (host === '::') {
    host = "localhost";
  }
  var port = server.address().port;

  console.log('Windows Service HealthCheck REST API listening at http://%s:%s', host, port);
});

module.exports = server;<commit_msg>Added an alternate port<commit_after>var express = require('express'),
  nconf = require('nconf'),
  lazy = require("lazy"),
  childProcess = require('child_process'),
  app = express();

nconf.argv().env();
nconf.file("./config.json");
nconf.load();

var stripWindowsServiceCLILine = function (ioLine) {
  ioLine = ioLine.trim();
  switch (ioLine) {
    case "These Windows services are started:":
    case "The command completed successfully.": return "";
    default: return ioLine;
  }
};

var getServices = function (filter, callback) {
  var child = childProcess.spawn("net", ['start']);
  var errData = '';
  var services = [];
  child.stderr.on('data', function (chunk){
    errData += chunk;
  });
  child.on('exit', function () {
    if (errData) {
      console.log(errData);
      return callback(errData, []);
    }

    callback(undefined, services);
  });

  lazy(child.stdout)
    .lines
    .map(String)
    .skip(2)
    .map(stripWindowsServiceCLILine)
    .filter(function (service){
      if (filter) {
        return service && service.toLowerCase() === filter.toLowerCase()
      }
      else {
        //Ensure service isn't blank
        return service;
      }
    })
    .forEach(function(service){
      services.push(service);
    });
};

app.get('/info/:service', function (req, res) {
  var host = server.address().address;
  if (host === '::') {
    host = "localhost";
  }
  var port = server.address().port;

  res.json({
    "description": "Windows Service is monitored by a REST API - https://github.com/thealah/rest-windows-service-health-fascade",
    "windowsService": req.params.service,
    "serverHost": host,
    "serverPort": port,
    "ui": {
      "hide": ["serverHost", "serverPort"]
    }
  });
  res.end();
});

app.get('/:service', function (req, res) {
  var serviceFilter = req.params.service;
  if (!serviceFilter) {
    response.badRequest(res, "Invalid Service Name");
    return;
  }

  getServices(serviceFilter, function (err, services) {
    if (err) {
      res.status(500).json({
        "type": "Windows Service",
        "message": "Error reading Windows Services",
        "ui": {
          "info": "/info/" + encodeURIComponent(serviceFilter)
        }
      });
    }
    else if (!services.length) {
      res.status(502).json({
        "type": "Windows Service",
        "message": "Missing Windows Service '" + serviceFilter + "' or it is stopped",
        "ui": {
          "info": "/info/" + encodeURIComponent(serviceFilter)
        }
      });
    }
    else {
      res.json({
        "type": "Windows Service",
        "ui": {
          "info": "/info/" + encodeURIComponent(services[0])
        }
      });
    }
    res.end();
  });
});

app.get('/', function (req, res) {
  getServices(undefined, function (err, services) {
    if (err) {
      res.status(500);
    }
    else {
      res.json({
        "services": services,
        "message": "To use the healthcheck portion of the API, use the route: /$WINDOWS_SERVICE_NAME"
      });
    }
    res.end();
  });
});

var server = app.listen(nconf.get('port') || 3000, function () {
  var host = server.address().address;
  if (host === '::') {
    host = "localhost";
  }
  var port = server.address().port;

  console.log('Windows Service HealthCheck REST API listening at http://%s:%s', host, port);
});

if (nconf.get('alternatePort')) {
  var alternateServer = app.listen(nconf.get('alternatePort') || 3000, function () {
    var host = alternateServer.address().address;
    if (host === '::') {
      host = "localhost";
    }
    var port = alternateServer.address().port;

    console.log('Windows Service HealthCheck REST API listening at http://%s:%s', host, port);
  });
}<|endoftext|>


<commit_before>var http = require('http'),
    _ = require("underscore"),
    path = require("path")
    util = require('util'),
    find = require("shelljs").ls,
    runViaCli = require.main === module,
    options = {},
    optimist = null,
    fs = require("fs");

var routeMap = {};

/**
 * @param {Object} options
 * @property options.port {String}
 * @property options.tplDir {String}
 */
exports.init = function (opt) {

  options = opt;
  var tplDir = path.resolve(opt.tplDir);
  options.tplDir = tplDir;

  routeMap = {
    "urlMatch": {
      regex: /^\/([\-0-9a-zA-Z]+)$/,
      handler: function (req, resp, routeName, matched) {
        var label = matched[1];
        var filepath = path.join(tplDir, label);

        // check if view dir exists
        if (fs.existsSync(filepath)) {
          app_handler(req, resp, routeName, matched, filepath);
        } else {
          notfound_handler(req, resp, routeName, matched, filepath);
        }
      }
    }
  };

};

var log = function log() {
  if (runViaCli) {
    console.log.apply(console, arguments);
  }
};

exports.start = function() {
  var port = options.port;
  var s = http.createServer(function (req, res) {
    var found = false,
        routeName = "",
        matched = null;

    req.on('close', function(){
      log('premature close');
      res.end();
    });

    for (var routeName in routeMap) {
      matched = routeMap[routeName].regex.exec(req.url);
      if (matched) {
        found = true;
        s.emit('urlMatched', req, res, routeName, matched);
        break;
      }
    }

    if (!found) {
      res.writeHead(404);
      res.end();
    }
  });

  s.on('urlMatched', function(req, res, routeName, matched) {
    log('found match: ', matched[0]);
    routeMap[routeName].handler(req, res, routeName, matched);
  });

  s.port = port;
  s.url = 'http://localhost:' + port;

  s.listen(s.port, function() {
    log('server started: ', s.url);
  });

  return s;
};

function notfound_handler (req, resp, routeName, matched) {
  resp.writeHead(404);
  resp.end();
}

var get_file_list = exports.get_file_list = function (tplDir, label) {
  var filelist = find( '-R', path.join(tplDir, label) ).filter(function(file){ return file.match(/\.[a-zA-Z]+$/);});

  return _.map(filelist, function(item) {
    return item.split(path.sep);
  });
};

/**
 * @param {Object} obj
 * @param {Array} path
 * @return {Object}
 *
 * original obj = {}
 * [ 'a', 'b', 'c' ] => {a:{b:{c:{}}}}
 * [ 'a' ] => {}
 *
 * original obj = {a:{b:{c:'a'}}}
 * [ 'a', 'b', 'b' ] => {a:{b:{c:'a',b: {}}}}
 */
var create_object = exports.create_object = function (obj, path) {

  if (path.length && path.length == 1) {
    obj[path[0]] = obj[path[0]] ? obj[path[0]] : {};
    return obj[path[0]];
  }

  var marker = obj;
  var len = path.length;

  for (var i=0; i<len; i++) {
    if (!marker[path[i]]) {
      marker[path[i]] = {};
    }
    marker = marker[path[i]];
  }

  return marker;
};

function app_handler (req, resp, routeName, matched) {
  var label = matched[1];
  var filelist = get_file_list(options.tplDir, label);

  var obj = {};

  for (var i=0; i<filelist.length; i++) {
    if (filelist[i].length) {
      var filename = filelist[i].splice(filelist[i].length-1)[0];
      var marker = create_object(obj, filelist[i]);
      var fullpath = path.join(options.tplDir, label, filelist[i].join(path.sep), filename);
      var content = loadFile(fullpath);

      marker[filename.split('.')[0]] = content;
    }
  }

  resp.writeHead(200, {'Content-Type':'application/json'});
  resp.end(JSON.stringify(obj));
}

function loadFile (filename) {
  var content =  fs.readFileSync(filename, "utf8").toString();
  return content.trim();
}
<commit_msg>use custom routeMap if provided<commit_after>var http = require('http'),
    _ = require("underscore"),
    path = require("path")
    util = require('util'),
    find = require("shelljs").ls,
    runViaCli = require.main === module,
    options = {},
    optimist = null,
    fs = require("fs");

var routeMap = {};

/**
 * @param {Object} options
 * @property options.port {String}
 * @property options.tplDir {String}
 */
exports.init = function (opt) {

  options = opt;
  var tplDir = path.resolve(opt.tplDir);
  options.tplDir = tplDir;

  if (opt.routeMap) {
    routeMap = opt.routeMap;
  } else {
    routeMap = {
      "urlMatch": {
        regex: /^\/([\-0-9a-zA-Z]+)$/,
        handler: function (req, resp, routeName, matched) {
          var label = matched[1];
          var filepath = path.join(tplDir, label);

          // check if view dir exists
          if (fs.existsSync(filepath)) {
            app_handler(req, resp, routeName, matched, filepath);
          } else {
            notfound_handler(req, resp, routeName, matched, filepath);
          }
        }
      }
    };
  }

};

var log = function log() {
  if (runViaCli) {
    console.log.apply(console, arguments);
  }
};

exports.start = function() {
  var port = options.port;
  var s = http.createServer(function (req, res) {
    var found = false,
        routeName = "",
        matched = null;

    req.on('close', function(){
      log('premature close');
      res.end();
    });

    for (var routeName in routeMap) {
      matched = routeMap[routeName].regex.exec(req.url);
      if (matched) {
        found = true;
        s.emit('urlMatched', req, res, routeName, matched);
        break;
      }
    }

    if (!found) {
      res.writeHead(404);
      res.end();
    }
  });

  s.on('urlMatched', function(req, res, routeName, matched) {
    log('found match: ', matched[0]);
    routeMap[routeName].handler(req, res, routeName, matched);
  });

  s.port = port;
  s.url = 'http://localhost:' + port;

  s.listen(s.port, function() {
    log('server started: ', s.url);
  });

  return s;
};

function notfound_handler (req, resp, routeName, matched) {
  resp.writeHead(404);
  resp.end();
}

var get_file_list = exports.get_file_list = function (tplDir, label) {
  var filelist = find( '-R', path.join(tplDir, label) ).filter(function(file){ return file.match(/\.[a-zA-Z]+$/);});

  return _.map(filelist, function(item) {
    return item.split(path.sep);
  });
};

/**
 * @param {Object} obj
 * @param {Array} path
 * @return {Object}
 *
 * original obj = {}
 * [ 'a', 'b', 'c' ] => {a:{b:{c:{}}}}
 * [ 'a' ] => {}
 *
 * original obj = {a:{b:{c:'a'}}}
 * [ 'a', 'b', 'b' ] => {a:{b:{c:'a',b: {}}}}
 */
var create_object = exports.create_object = function (obj, path) {

  if (path.length && path.length == 1) {
    obj[path[0]] = obj[path[0]] ? obj[path[0]] : {};
    return obj[path[0]];
  }

  var marker = obj;
  var len = path.length;

  for (var i=0; i<len; i++) {
    if (!marker[path[i]]) {
      marker[path[i]] = {};
    }
    marker = marker[path[i]];
  }

  return marker;
};

function app_handler (req, resp, routeName, matched) {
  var label = matched[1];
  var filelist = get_file_list(options.tplDir, label);

  var obj = {};

  for (var i=0; i<filelist.length; i++) {
    if (filelist[i].length) {
      var filename = filelist[i].splice(filelist[i].length-1)[0];
      var marker = create_object(obj, filelist[i]);
      var fullpath = path.join(options.tplDir, label, filelist[i].join(path.sep), filename);
      var content = loadFile(fullpath);

      marker[filename.split('.')[0]] = content;
    }
  }

  resp.writeHead(200, {'Content-Type':'application/json'});
  resp.end(JSON.stringify(obj));
}

function loadFile (filename) {
  var content =  fs.readFileSync(filename, "utf8").toString();
  return content.trim();
}
<|endoftext|>


<commit_before>var indexes = require('indexes-of')

              require('colors')

function compare (a, b) {
  return a - b
}

function diff (a, b) {
  return a < b ? b - a : a - b
}

function closest (matches, target) {
  return min(matches, function (v, k) {
    return diff(v, target)
  })
}

// THOUGHTS: rank results by:
// * how tightly the terms are grouped.
// * how close a group is to the start.
// * how uncomon those terms are in the corpus,
//   but how common they are in the document...
//   (how surprising it is that document has those words)

function stddev(indexes) {
  var N = indexes.length
  var avg = indexes.reduce(function (a, b) {return a + b}, 0) / N
  return Math.sqrt(indexes.reduce(function (v, e) {
    return v + Math.pow(e - avg, 2)
  }, 0) / N)
}

function min(ary, test) {
  var M, best
  for(var i in ary) {
    var m = test(ary[i])
    if(M == null || m < M)
      M = m, best = i
  }
  return best
}

function highlight (string, query, hi) {
  hi = hi || function (w) {
    return w.bold
  }
  return query.reduce(function (string, term) {
    return string.split(new RegExp(term, 'i')).join(hi(term))
  }, string)
}

function context (doc, best, length) {
  if(!best)
    return doc.substring(0, length)
  length = length || 80
  best.sort()
  var f = best.shift()
  var l = best.pop() || f
  var w = l - f
  var s = f - (Math.max(length - w, 0)/2)
  return doc.substring(s, s + length)
}

function bestGroup (doc, query) {
  var DOC = doc.toUpperCase()
  var QUERY = query.map(function (e) { return e.toUpperCase() })

  var matches = QUERY.map(function (q) { return indexes(DOC, q) })
  //find a close matching group.
  //for each match of the first term
  //find the best groups around that...
  var first = matches.shift()
  var groups = first.map(function (q, i) {
    return [q].concat(
      matches.filter(function (e) {
        return e.length
      }).map(function (list) {
        var l = closest(list, q)
        return list[l]
      })
    )
  })
  return groups[min(groups, stddev)]
}

module.exports = function (doc, query, length) {
  return highlight(
    context(doc, bestGroup(doc, query), length)
  , query)
}

//are there terms that are close together?
//are terms in correct order?
//are the terms close to the start of the document?

//OKAY

//recurse over the matches,
//for a match, find the match closest to the other terms

//pick each term, then pick the terms from the other queries closest to it.
//(TODO remove common words)

<commit_msg>if terms are far apart, show them with ... between contexts<commit_after>var indexes = require('indexes-of')
              require('colors')

function compare (a, b) {
  return a - b
}

function diff (a, b) {
  return a < b ? b - a : a - b
}

function closest (matches, target) {
  return min(matches, function (v, k) {
    return diff(v, target)
  })
}

// THOUGHTS: rank results by:
// * how tightly the terms are grouped.
// * how close a group is to the start.
// * how uncomon those terms are in the corpus,
//   but how common they are in the document...
//   (how surprising it is that document has those words)

function stddev(indexes) {
  var N = indexes.length
  var avg = indexes.reduce(function (a, b) {return a + b}, 0) / N
  return Math.sqrt(indexes.reduce(function (v, e) {
    return v + Math.pow(e - avg, 2)
  }, 0) / N)
}

function min(ary, test) {
  var M, best
  for(var i in ary) {
    var m = test(ary[i])
    if(M == null || m < M)
      M = m, best = i
  }
  return best
}

function highlight (string, query, hi) {
  hi = hi || function (w) {
    return w.bold
  }
  return query.reduce(function (string, term) {
    return string.split(new RegExp(term, 'i')).join(hi(term))
  }, string)
}

function context (doc, _best, length, query) {

  if(!_best)
    return doc.substring(0, length)
  var best = _best.slice().sort()
  length = length || 80
  var f = best.shift()
  var l = best.pop() || f
  var w = l - f
  var s = f - (Math.max(length - w, 0)/2)
  if(w < length)
    return doc.substring(s, s + length)
  //how much space either side
  var dotdotdot = (query.length + 1) * 3
  var tl = (length - query.join('').length - dotdotdot) / (query.length * 2)

  return _best.map(function (q, i) {
    return doc.substring(q - tl, q + query[i].length + tl)
  }).join('...')

}

function bestGroup (doc, query) {
  var DOC = doc.toUpperCase()
  var QUERY = query.map(function (e) { return e.toUpperCase() })

  var matches = QUERY.map(function (q) { return indexes(DOC, q) })
  //find a close matching group.
  //for each match of the first term
  //find the best groups around that...
  var first = matches.shift()
  var groups = first.map(function (q, i) {
    return [q].concat(
      matches.filter(function (e) {
        return e.length
      }).map(function (list) {
        var l = closest(list, q)
        return list[l]
      })
    )
  })
  return groups[min(groups, stddev)]
}

module.exports = function (doc, query, length) {
  return highlight(
    context(doc, bestGroup(doc, query), length, query)
  , query)
}

<|endoftext|>


<commit_before>'use strict';

var async = require('async');
var is = require('annois');
var schedule = require('node-schedule');

module.exports = function(config, tasks, extra) {
    var foundTasks = initialize(config, tasks);
    var unusedTasks = findUnused(Object.keys(tasks), Object.keys(foundTasks));

    if(unusedTasks.length) {
        console.log('Failed to find configuration for `' + unusedTasks.join('`, `') + '`!');
    }

    if(extra && extra.instant) {
        var eachName = extra.series? 'eachSeries': 'each';
        var done = is.fn(extra.instant)? extra.instant: noop;

        async[eachName](Object.keys(foundTasks), function(name, cb) {
            var task = config[name];

            if(!is.object(task) || !('instant' in task) || task.instant) {
                foundTasks[name](cb);
            }
        }, done);
    }
};

function initialize(config, tasks) {
    var foundTasks = {};

    Object.keys(config).forEach(function(name) {
        var pattern = config[name];

        if(name in tasks) {
            var task = tasks[name];

            schedule.scheduleJob(pattern, task.bind(null, noop));

            foundTasks[name] = task;
        }
        else {
            console.warn('Failed to find `' + name + '` amongst tasks!');
        }
    });

    return foundTasks;
}

function findUnused(tasks, foundTasks) {
    return tasks.filter(function(name) {
        return foundTasks.indexOf(name) === -1;
    });
}

function noop() {}

<commit_msg>Add missing callback<commit_after>'use strict';

var async = require('async');
var is = require('annois');
var schedule = require('node-schedule');

module.exports = function(config, tasks, extra) {
    var foundTasks = initialize(config, tasks);
    var unusedTasks = findUnused(Object.keys(tasks), Object.keys(foundTasks));

    if(unusedTasks.length) {
        console.log('Failed to find configuration for `' + unusedTasks.join('`, `') + '`!');
    }

    if(extra && extra.instant) {
        var eachName = extra.series? 'eachSeries': 'each';
        var done = is.fn(extra.instant)? extra.instant: noop;

        async[eachName](Object.keys(foundTasks), function(name, cb) {
            var task = config[name];

            if(!is.object(task) || !('instant' in task) || task.instant) {
                foundTasks[name](cb);
            }
            else {
                cb();
            }
        }, done);
    }
};

function initialize(config, tasks) {
    var foundTasks = {};

    Object.keys(config).forEach(function(name) {
        var pattern = config[name];

        if(name in tasks) {
            var task = tasks[name];

            schedule.scheduleJob(pattern, task.bind(null, noop));

            foundTasks[name] = task;
        }
        else {
            console.warn('Failed to find `' + name + '` amongst tasks!');
        }
    });

    return foundTasks;
}

function findUnused(tasks, foundTasks) {
    return tasks.filter(function(name) {
        return foundTasks.indexOf(name) === -1;
    });
}

function noop() {}

<|endoftext|>


<commit_before>var fs = require('fs');
var config = JSON.parse(fs.readFileSync('./config.json'));

var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io')(server);

app.set('port', (process.env.PORT || 5000));
app.use(express.static(__dirname + '/public'));

var Twit = require('twit');
var twitter = new Twit({
  consumer_key: config.twitter.consumer_key,
  consumer_secret: config.twitter.consumer_secret,
  access_token: config.twitter.access_token,
  access_token_secret: config.twitter.access_token_secret
});

app.get('/', function(request, response) {
  response.send('Hello world!');
});

server.listen(app.get('port'), function() {
  console.log("Node app is running at localhost:" + app.get('port'));
});
<commit_msg>put the comments back in<commit_after>//load the config json file
var fs = require('fs');
var config = JSON.parse(fs.readFileSync('./config.json'));

//create and configure the express app and server
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io')(server);

app.set('port', (process.env.PORT || 5000));
app.use(express.static(__dirname + '/public'));

//set up the twitter instance
var Twit = require('twit');
var twitter = new Twit({
  consumer_key: config.twitter.consumer_key,
  consumer_secret: config.twitter.consumer_secret,
  access_token: config.twitter.access_token,
  access_token_secret: config.twitter.access_token_secret
});

//homepage
app.get('/', function(request, response) {
  response.send('Hello world!');
});

//start the server listening for requests
server.listen(app.get('port'), function() {
  console.log("Node app is running at localhost:" + app.get('port'));
});
<|endoftext|>


<commit_before>var _ = require('lodash');
var request = require('request');
var express = require('express');
var bodyParser = require('body-parser');
var Parse = require('parse/node');
var config = require('./config.json');
var configKeyWhitelist = ['minRating', 'maxRating'];

var loadReviewFromItunes = function(teamSettings, successCallback, errorCallback) {
  var appIdList = teamSettings.get('appIdList');
  var minRating = teamSettings.get('minRating') || 1;
  var maxRating = teamSettings.get('maxRating') || 5;
  var randomAppIndex = Math.floor(Math.random() * (appIdList.length));
  var randomAppId = appIdList[randomAppIndex];
  // Query iTunes
  request(config.itunesApi.baseUrl + randomAppId + '/' + config.itunesApi.responseFormat,
    function(error, response, body) {
      if (!error && response.statusCode == 200) {
        var appName;
        var entries = JSON.parse(body).feed.entry;
        var reviews = _.filter(entries, function(entry) {
          if (entry['im:rating']) {
            // All but the first entry have that property.
            if (entry['im:rating'].label >= minRating && entry['im:rating'].label <= maxRating) {
              return entry;
            } else {
              return null;
            }
          } else {
            // Voila, the first entry is the app info
            appName = entry['im:name'].label;
          }
        });

        // Alright, let's see if we've found some reviews
        if (reviews.length > 0) {
          // Woohoo, let's share some random review
          var randomIndex = Math.floor(Math.random() * (reviews.length - 0)) + 0;
          var slackMessage = appName + '\n' + reviews[randomIndex].content.label;
          successCallback(slackMessage);
        } else {
          var errorMessage = 'No reviews for app: ' + (appName ? appName : randomAppId);
          console.log(errorMessage);
          errorCallback(errorMessage);
        }
      }
    }
  );
};

var persistTeamSettings = function(teamDomain, appIdList, successCallback, errorCallback) {
  var TeamSettings = Parse.Object.extend('TeamSettings');
  var query = new Parse.Query(TeamSettings);
  query.equalTo('teamDomain', teamDomain);
  query.find({
    success: function(results) {
      // No settings yet, create a new entry
      if (results.length === 0) {
        var newTeamSettings = new TeamSettings();
        newTeamSettings.set('teamDomain', teamDomain);
        newTeamSettings.set('appIdList', appIdList);
        newTeamSettings.save(null, {
          success: function(persistedTeamSettings) {
            successCallback('Success! Your app IDs are persisted. From now on, use `/<your-slack-command>` to get a random review. For example: `/appreview`');
          },
          error: function(persistedTeamSettings, error) {
            // Execute any logic that should take place if the save fails.
            // error is a Parse.Error with an error code and message.
            console.log('Failed to create new object, with error code: ' + error.message);
            errorCallback('Failed to create new object, with error code: ' + error.message);
          }
        });
      // Settings available, update
      } else if (results.length === 1) {
        for (var index = 0; index < appIdList.length; index++) {
          var appId = appIdList[index];
          results[0].addUnique('appIdList', appId);
        }
        results[0].save();
        successCallback('Success! Your app IDs are persisted. From now on, use `/<your-slack-command>` to get a random review. For example: `/appreview`');
      // More than 1 settings entry for the given team... problem
      } else {
        console.log('More than 1 settings entry for team: ' + teamDomain);
        errorCallback('Something went wrong... Please try again');
      }
    },
    error: function(error) {
      console.log('Cannot load team settings for team: ' + teamDomain + '. Error: ' + error);
      errorCallback('Something went wrong... Please try again');
    }
  });
};

var listTeamSettings = function(teamDomain, successCallback, errorCallback) {
  // Load team settings
  var TeamSettings = Parse.Object.extend('TeamSettings');
  var query = new Parse.Query(TeamSettings);
  query.equalTo('teamDomain', teamDomain);
  query.find({
    success: function(results) {
      if (results.length === 0) {
        successCallback('We don\'t yet have any app IDs for your team. Please add some app IDs from iTunes Connect like so: `/<your-slack-command> add <comma separated app ID list>`. For example: `/appreview add 123,456`');
      } else if (results.length === 1) {
        successCallback('Your team has the following app IDs configured: ' + results[0].get('appIdList'));
      } else {
        console.log('0 or more than 1 settings entry for team: ' + teamDomain);
        errorCallback('Something went wrong... Please try again');
      }
    },
    error: function(error) {
      console.log('Cannot load team settings for team: ' + teamDomain + '. Error: ' + error);
      errorCallback('Something went wrong... Please try again');
    }
  });
};

var setTeamSettingsConfigValue = function(teamDomain, configKey, configValue, successCallback, errorCallback) {
  var TeamSettings = Parse.Object.extend('TeamSettings');
  var query = new Parse.Query(TeamSettings);
  query.equalTo('teamDomain', teamDomain);
  query.find({
    success: function(results) {
      // No settings yet, create a new entry
      if (results.length === 0) {
        var newTeamSettings = new TeamSettings();
        newTeamSettings.set('teamDomain', teamDomain);
        newTeamSettings.set('appIdList', []);
        if (_.contains(configKeyWhitelist, configKey)) {
          newTeamSettings.set(configKey, configValue);
        }
        newTeamSettings.save(null, {
          success: function(persistedTeamSettings) {
            successCallback('Success! Your settings are persisted.');
          },
          error: function(persistedTeamSettings, error) {
            // Execute any logic that should take place if the save fails.
            // error is a Parse.Error with an error code and message.
            console.log('Failed to create new object, with error code: ' + error.message);
            errorCallback('Failed to create new object, with error code: ' + error.message);
          }
        });
      // Settings available, update
      } else if (results.length === 1) {
        if (_.contains(configKeyWhitelist, configKey)) {
          results[0].set(configKey, configValue);
        }
        results[0].save();
        successCallback('Success! Your settings are persisted.');
      // More than 1 settings entry for the given team... problem
      } else {
        console.log('More than 1 settings entry for team: ' + teamDomain);
        errorCallback('Something went wrong... Please try again');
      }
    },
    error: function(error) {
      console.log('Cannot load team settings for team: ' + teamDomain + '. Error: ' + error);
      errorCallback('Something went wrong... Please try again');
    }
  });
};

var processCommand = function(teamDomain, parameters, successCallback, errorCallback) {
  var parametersArray = parameters.split(' ');
  var command = parametersArray[0];
  if (command === 'add') {
    var appIdList = parametersArray[1].split(',');
    persistTeamSettings(teamDomain, appIdList, successCallback, errorCallback);
  } else if (command === 'list') {
    listTeamSettings(teamDomain, successCallback, errorCallback);
  } else if (command === 'set') {
    var configKey = parametersArray[1].split('=')[0];
    var configValue = parametersArray[1].split('=')[1];
    setTeamSettingsConfigValue(teamDomain, configKey, configValue, successCallback, errorCallback);
  }
  // TODO: Add more commands: 'reset', 'remove'
};

var sendSlackResponse = function(res, message) {
  res.json({
    response_type: 'in_channel',
    text: message
  });
};

var app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
  extended: false
}));

app.post('/app-review', function(req, res) {
  var teamDomain = req.body.team_domain;
  var user = req.body.user_name;
  var command = req.body.command;
  var parameters = req.body.text;
  console.log('Team: ' + teamDomain + '; user: ' + user + '; command: ' + command + '; parameters: ' + parameters);

  // Load team settings
  var TeamSettings = Parse.Object.extend('TeamSettings');
  var query = new Parse.Query(TeamSettings);
  query.equalTo('teamDomain', teamDomain);
  query.find({
    success: function(results) {
      // No team settings persisted yet
      if (results.length === 0) {
        // If parameters were provided, process them
        if (parameters && parameters.length > 0) {
          processCommand(teamDomain, parameters, function(message) {
            sendSlackResponse(res, message);
          }, function(error) {
            sendSlackResponse(res, error);
          });
        } else {
          console.log('No command provided');
          sendSlackResponse(res, 'Please provide a command, such as `/appreview add 123,456,789`');
        }
      // Exactly one team settings row - perfect
      } else if (results.length === 1) {
        // If parameters were provided, process them
        if (parameters && parameters.length > 0) {
          processCommand(teamDomain, parameters, function(message) {
            sendSlackResponse(res, message);
          }, function(error) {
            sendSlackResponse(res, error);
          });
        // If no paramters were provided, load a review
        } else {
          var teamSettings = results[0];
          var appIdList = teamSettings.get('appIdList');
          if (appIdList && appIdList.length === 0) {
            // No settings yet for the given team domain
            sendSlackResponse(res, 'Hey there ' + user + '! We don\'t yet have any app IDs for your team. Please add some app IDs from iTunes Connect like so: `/<your-slack-command> add <comma separated app ID list>`. For example: `/appreview add 123,456`');
          } else {
            loadReviewFromItunes(teamSettings, function(message) {
              sendSlackResponse(res, message);
            }, function(error) {
              sendSlackResponse(res, error);
            });
          }
        }
      } else {
        console.log('More than 1 settings entry for team: ' + teamDomain);
        sendSlackResponse(res, 'Hey there ' + user + '! Something went wrong... Please try again');
      }
    },
    error: function(error) {
      console.log('Cannot load team settings for team: ' + teamDomain + '. Error: ' + error);
      sendSlackResponse(res, 'Hey there ' + user + '! Something went wrong... Please try again');
    }
  });
});

var port = process.env.PORT || 3000;
var server = app.listen(port, function() {
  Parse.initialize(process.env.PARSE_APP_ID, process.env.PARSE_APP_KEY);

  var host = server.address().address;
  var port = server.address().port;

  console.log('Example app listening at http://%s:%s', host, port);
});
<commit_msg>Added rating stars to the message<commit_after>var _ = require('lodash');
var request = require('request');
var express = require('express');
var bodyParser = require('body-parser');
var Parse = require('parse/node');
var config = require('./config.json');
var configKeyWhitelist = ['minRating', 'maxRating'];

var loadReviewFromItunes = function(teamSettings, successCallback, errorCallback) {
  var appIdList = teamSettings.get('appIdList');
  var minRating = teamSettings.get('minRating') || 1;
  var maxRating = teamSettings.get('maxRating') || 5;
  var randomAppIndex = Math.floor(Math.random() * (appIdList.length));
  var randomAppId = appIdList[randomAppIndex];
  // Query iTunes
  request(config.itunesApi.baseUrl + randomAppId + '/' + config.itunesApi.responseFormat,
    function(error, response, body) {
      if (!error && response.statusCode == 200) {
        var appName;
        var entries = JSON.parse(body).feed.entry;
        var reviews = _.filter(entries, function(entry) {
          if (entry['im:rating']) {
            // All but the first entry have that property.
            if (entry['im:rating'].label >= minRating && entry['im:rating'].label <= maxRating) {
              return entry;
            } else {
              return null;
            }
          } else {
            // Voila, the first entry is the app info
            appName = entry['im:name'].label;
          }
        });

        // Alright, let's see if we've found some reviews
        if (reviews.length > 0) {
          // Woohoo, let's share some random review
          var randomIndex = Math.floor(Math.random() * (reviews.length - 0)) + 0;
          var randomReview = reviews[randomIndex];
          var randomReviewRating = randomReview['im:rating'].label;
          var randomReviewRatingStars = '';
          for (var i = 1; i <= 5; i++) {
            if (i <= randomReviewRating) {
              randomReviewRatingStars += '★';
            } else {
              randomReviewRatingStars += '☆';
            }
          }
          var randomReviewLabel = randomReview.content.label;
          var slackMessage = appName + '\n' + randomReviewRatingStars + ': ' + randomReviewLabel;
          successCallback(slackMessage);
        } else {
          var errorMessage = 'No reviews for app: ' + (appName ? appName : randomAppId);
          console.log(errorMessage);
          errorCallback(errorMessage);
        }
      }
    }
  );
};

var persistTeamSettings = function(teamDomain, appIdList, successCallback, errorCallback) {
  var TeamSettings = Parse.Object.extend('TeamSettings');
  var query = new Parse.Query(TeamSettings);
  query.equalTo('teamDomain', teamDomain);
  query.find({
    success: function(results) {
      // No settings yet, create a new entry
      if (results.length === 0) {
        var newTeamSettings = new TeamSettings();
        newTeamSettings.set('teamDomain', teamDomain);
        newTeamSettings.set('appIdList', appIdList);
        newTeamSettings.save(null, {
          success: function(persistedTeamSettings) {
            successCallback('Success! Your app IDs are persisted. From now on, use `/<your-slack-command>` to get a random review. For example: `/appreview`');
          },
          error: function(persistedTeamSettings, error) {
            // Execute any logic that should take place if the save fails.
            // error is a Parse.Error with an error code and message.
            console.log('Failed to create new object, with error code: ' + error.message);
            errorCallback('Failed to create new object, with error code: ' + error.message);
          }
        });
      // Settings available, update
      } else if (results.length === 1) {
        for (var index = 0; index < appIdList.length; index++) {
          var appId = appIdList[index];
          results[0].addUnique('appIdList', appId);
        }
        results[0].save();
        successCallback('Success! Your app IDs are persisted. From now on, use `/<your-slack-command>` to get a random review. For example: `/appreview`');
      // More than 1 settings entry for the given team... problem
      } else {
        console.log('More than 1 settings entry for team: ' + teamDomain);
        errorCallback('Something went wrong... Please try again');
      }
    },
    error: function(error) {
      console.log('Cannot load team settings for team: ' + teamDomain + '. Error: ' + error);
      errorCallback('Something went wrong... Please try again');
    }
  });
};

var listTeamSettings = function(teamDomain, successCallback, errorCallback) {
  // Load team settings
  var TeamSettings = Parse.Object.extend('TeamSettings');
  var query = new Parse.Query(TeamSettings);
  query.equalTo('teamDomain', teamDomain);
  query.find({
    success: function(results) {
      if (results.length === 0) {
        successCallback('We don\'t yet have any app IDs for your team. Please add some app IDs from iTunes Connect like so: `/<your-slack-command> add <comma separated app ID list>`. For example: `/appreview add 123,456`');
      } else if (results.length === 1) {
        successCallback('Your team has the following app IDs configured: ' + results[0].get('appIdList'));
      } else {
        console.log('0 or more than 1 settings entry for team: ' + teamDomain);
        errorCallback('Something went wrong... Please try again');
      }
    },
    error: function(error) {
      console.log('Cannot load team settings for team: ' + teamDomain + '. Error: ' + error);
      errorCallback('Something went wrong... Please try again');
    }
  });
};

var setTeamSettingsConfigValue = function(teamDomain, configKey, configValue, successCallback, errorCallback) {
  var TeamSettings = Parse.Object.extend('TeamSettings');
  var query = new Parse.Query(TeamSettings);
  query.equalTo('teamDomain', teamDomain);
  query.find({
    success: function(results) {
      // No settings yet, create a new entry
      if (results.length === 0) {
        var newTeamSettings = new TeamSettings();
        newTeamSettings.set('teamDomain', teamDomain);
        newTeamSettings.set('appIdList', []);
        if (_.contains(configKeyWhitelist, configKey)) {
          newTeamSettings.set(configKey, configValue);
        }
        newTeamSettings.save(null, {
          success: function(persistedTeamSettings) {
            successCallback('Success! Your settings are persisted.');
          },
          error: function(persistedTeamSettings, error) {
            // Execute any logic that should take place if the save fails.
            // error is a Parse.Error with an error code and message.
            console.log('Failed to create new object, with error code: ' + error.message);
            errorCallback('Failed to create new object, with error code: ' + error.message);
          }
        });
      // Settings available, update
      } else if (results.length === 1) {
        if (_.contains(configKeyWhitelist, configKey)) {
          results[0].set(configKey, configValue);
        }
        results[0].save();
        successCallback('Success! Your settings are persisted.');
      // More than 1 settings entry for the given team... problem
      } else {
        console.log('More than 1 settings entry for team: ' + teamDomain);
        errorCallback('Something went wrong... Please try again');
      }
    },
    error: function(error) {
      console.log('Cannot load team settings for team: ' + teamDomain + '. Error: ' + error);
      errorCallback('Something went wrong... Please try again');
    }
  });
};

var processCommand = function(teamDomain, parameters, successCallback, errorCallback) {
  var parametersArray = parameters.split(' ');
  var command = parametersArray[0];
  if (command === 'add') {
    var appIdList = parametersArray[1].split(',');
    persistTeamSettings(teamDomain, appIdList, successCallback, errorCallback);
  } else if (command === 'list') {
    listTeamSettings(teamDomain, successCallback, errorCallback);
  } else if (command === 'set') {
    var configKey = parametersArray[1].split('=')[0];
    var configValue = parametersArray[1].split('=')[1];
    setTeamSettingsConfigValue(teamDomain, configKey, configValue, successCallback, errorCallback);
  }
  // TODO: Add more commands: 'reset', 'remove'
};

var sendSlackResponse = function(res, message) {
  res.json({
    response_type: 'in_channel',
    text: message
  });
};

var app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
  extended: false
}));

app.post('/app-review', function(req, res) {
  var teamDomain = req.body.team_domain;
  var user = req.body.user_name;
  var command = req.body.command;
  var parameters = req.body.text;
  console.log('Team: ' + teamDomain + '; user: ' + user + '; command: ' + command + '; parameters: ' + parameters);

  // Load team settings
  var TeamSettings = Parse.Object.extend('TeamSettings');
  var query = new Parse.Query(TeamSettings);
  query.equalTo('teamDomain', teamDomain);
  query.find({
    success: function(results) {
      // No team settings persisted yet
      if (results.length === 0) {
        // If parameters were provided, process them
        if (parameters && parameters.length > 0) {
          processCommand(teamDomain, parameters, function(message) {
            sendSlackResponse(res, message);
          }, function(error) {
            sendSlackResponse(res, error);
          });
        } else {
          console.log('No command provided');
          sendSlackResponse(res, 'Please provide a command, such as `/appreview add 123,456,789`');
        }
      // Exactly one team settings row - perfect
      } else if (results.length === 1) {
        // If parameters were provided, process them
        if (parameters && parameters.length > 0) {
          processCommand(teamDomain, parameters, function(message) {
            sendSlackResponse(res, message);
          }, function(error) {
            sendSlackResponse(res, error);
          });
        // If no paramters were provided, load a review
        } else {
          var teamSettings = results[0];
          var appIdList = teamSettings.get('appIdList');
          if (appIdList && appIdList.length === 0) {
            // No settings yet for the given team domain
            sendSlackResponse(res, 'Hey there ' + user + '! We don\'t yet have any app IDs for your team. Please add some app IDs from iTunes Connect like so: `/<your-slack-command> add <comma separated app ID list>`. For example: `/appreview add 123,456`');
          } else {
            loadReviewFromItunes(teamSettings, function(message) {
              sendSlackResponse(res, message);
            }, function(error) {
              sendSlackResponse(res, error);
            });
          }
        }
      } else {
        console.log('More than 1 settings entry for team: ' + teamDomain);
        sendSlackResponse(res, 'Hey there ' + user + '! Something went wrong... Please try again');
      }
    },
    error: function(error) {
      console.log('Cannot load team settings for team: ' + teamDomain + '. Error: ' + error);
      sendSlackResponse(res, 'Hey there ' + user + '! Something went wrong... Please try again');
    }
  });
});

var port = process.env.PORT || 3000;
var server = app.listen(port, function() {
  Parse.initialize(process.env.PARSE_APP_ID, process.env.PARSE_APP_KEY);

  var host = server.address().address;
  var port = server.address().port;

  console.log('Example app listening at http://%s:%s', host, port);
});
<|endoftext|>


<commit_before>var path = require('path');

module.exports = function (source) {
  if (this.cacheable) {
    this.cacheable();
  }

  var filename = path.basename(this.resourcePath),
      matches = 0,
      processedSource;

  processedSource = source.replace(/[Rr]eact\.createClass\s*\(/g, function (match) {
    matches++;
    return '__hotUpdateAPI.createClass(';
  });

  if (!matches) {
    return source;
  }

  return [
    'var __hotUpdateAPI = (function () {',
    '  var React = require("react");',
    '  var getHotUpdateAPI = require(' + JSON.stringify(require.resolve('./getHotUpdateAPI')) + ');',
    '  return getHotUpdateAPI(React, ' + JSON.stringify(filename) + ', module.id);',
    '})();',
    processedSource,
    'if (module.hot) {',
    '  module.hot.accept(function (err) {',
    '    if (err) {',
    '      console.error("Cannot not apply hot update to " + ' + JSON.stringify(filename) + ' + ": " + err.message);',
    '    }',
    '  });',
    '  module.hot.dispose(function () {',
    '    var nextTick = require(' + JSON.stringify(require.resolve('next-tick')) + ');',
    '    nextTick(__hotUpdateAPI.updateMountedInstances);',
    '  });',
    '}'
  ].join('\n');
};
<commit_msg>Errors in module shouldn't disable live reload (fixes #29)<commit_after>var path = require('path');

module.exports = function (source) {
  if (this.cacheable) {
    this.cacheable();
  }

  var filename = path.basename(this.resourcePath),
      matches = 0,
      processedSource;

  processedSource = source.replace(/[Rr]eact\.createClass\s*\(/g, function (match) {
    matches++;
    return '__hotUpdateAPI.createClass(';
  });

  if (!matches) {
    return source;
  }

  return [
    'var __hotUpdateAPI = (function () {',
    '  var React = require("react");',
    '  var getHotUpdateAPI = require(' + JSON.stringify(require.resolve('./getHotUpdateAPI')) + ');',
    '  return getHotUpdateAPI(React, ' + JSON.stringify(filename) + ', module.id);',
    '})();',
    'if (module.hot) {',
    '  module.hot.accept(function (err) {',
    '    if (err) {',
    '      console.error("Cannot not apply hot update to " + ' + JSON.stringify(filename) + ' + ": " + err.message);',
    '    }',
    '  });',
    '  module.hot.dispose(function () {',
    '    var nextTick = require(' + JSON.stringify(require.resolve('next-tick')) + ');',
    '    nextTick(__hotUpdateAPI.updateMountedInstances);',
    '  });',
    '}',
    processedSource
  ].join('\n');
};
<|endoftext|>