<commit_before>/* global global, GLOBAL, module */
/**
 * Created by kaelyang on 2015/5/19.
 */
var http = require('http');

var log4js = require('log4js');
var logger = log4js.getLogger();
var _ = require('underscore');
var UserService = require('./UserService');
var StatisticsService = require('./StatisticsService');
var Exporting = require('node-highcharts-exporting');
var path = require("path");
var fs  = require("fs");

var send_email = require("../utils/" + GLOBAL.pjconfig.email.module);
var dateFormat = require("../utils/dateFormat");

var EmailService = function() {
    this.userService = new UserService();
    this.statisticsService = new StatisticsService();
    this.top = parseInt(GLOBAL.pjconfig.email.top, 10) || 20;
    this.from = GLOBAL.pjconfig.email.from || "noreply-badjs@tencent.com";
    this.homepage = GLOBAL.pjconfig.email.homepage;
};

var getYesterday = function() {
    var date = new Date();
    date.setDate(date.getDate() - 1);
    date.setHours(0, 0, 0, 0);
    return date;
};

var setChartX =  function (number){
    var days = [];
    var nowDay = new Date()-0;

    for(var i = number;i>0; i--){
        var day = nowDay - i*1000*60*60*24;
        days.push(dateFormat(new Date(day), 'MM-dd'));
    }
    return days;
}

var getImageData = function (name  , data){

    var totalArray = [];
    var categories = setChartX(DAY_LENGTH);

    for(var i = 0 ; i < DAY_LENGTH; i++){
        totalArray.push(0)
    }

    function whichDayIndex(day1){
        for(var i =0,len = categories.length; i<len; i++){
            if(day1 == categories[i]){
                return i;
            }
        }
        return false;
    }

    _.forEach(data , function (value ,key){
        var index = whichDayIndex( dateFormat(new Date(value.startDate), 'MM-dd'));
        totalArray[index] = value.total
    });

    return {
        data: {
            xAxis: {
                categories: categories
            },
            series: [
                {
                    data: totalArray,
                    name :"-"
                }
            ]
        },
        options : {
            title : {text : "The last " + DAY_LENGTH + " days line charts"} ,
            "yAxis" : {"title" : {"text": "total" }}
        },
        width : 800
    }
}

var encodeHtml = function (str) {
    return (str + '').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\x60/g, '`').replace(/\x27/g, ''').replace(/\x22/g, '"');
};

EmailService.prototype = {
    render: function(data ,imagePath) {
        var that = this;
        data = data || {};
        var html = [];
        html.push('');
        html.push('
【BadJS日报邮件】 ' + data.title + '
');
        that.homepage && html.push('
日志查看点这: {{homepage}}
'.replace(/{{homepage}}/g, that.homepage));
        var content = data.content;
        if (content && content.length) {

            if(imagePath){
                html.push('
最近' + DAY_LENGTH + '天图表统计
')
                html.push('

');
            }

            html.push('

#	出现次数	错误内容
');
            var total_top = 0;
            content.forEach(function(v, i) {
                v = typeof v === 'object' ? v : null;
                if (v) {
                    html.push('
{{index}}	{{times}}	{{desc}}
'
                        .replace(/{{index}}/g, i + 1)
                        .replace(/{{times}}/g, v.total)
                        .replace(/{{desc}}/g,encodeHtml( v.title))
                        .replace(/{{bgc}}/g, i % 2 ? '#fff' : '#eee')
                    );
                    total_top += v.total;
                }
            });
            html.push('
');
            var total = data.total;
            total > 0 && html.push('
共 {{total}} 条记录, Top {{top}} 占 {{per}}.
'
                .replace(/{{total}}/g, total)
                .replace(/{{top}}/g, that.top)
                .replace(/{{per}}/g, (total_top * 100 / total).toFixed(2) + '%')
            );

        } else {
            html.push('
暂无数据
');
        }

        html.push('');
        return html.join('');
    },
    queryAll: function(isRetry, sendObject) {
        var that = this;
        that.date = getYesterday();
        logger.info('Send mail query all start');
        that.userService.queryListByCondition({
            applyId: -1,
            role: -1
        }, function(err, userlist) {
            if (err) {
                return logger.error('Send email userService queryListByCondition error');
            } else {
                var orderByApplyId = {};
                userlist.forEach(function(v) {
                    // 兼容没有登陆过的用户，自动拼接 邮箱后缀
                    if(!v.email){
                        v.email = v.loginName + GLOBAL.pjconfig.email.emailSuffix;
                    }
                    if (orderByApplyId[v.applyId]) {
                        orderByApplyId[v.applyId].push(v);
                    } else {
                        orderByApplyId[v.applyId] = [v];
                    }
                });
                for (var applyId in orderByApplyId) {
                    (function(users , applyId) {
                        var to_list = []; // 收件方
                        var cc_list = []; // 抄送方
                        var name = '';
                        users.forEach(function(v) {
                            v.role === 0 ? cc_list.push(v.email) : to_list.push(v.email);
                            name = v.name;
                        }); // jshint ignore:line

                        //测试代码
                        if(sendObject){
                            if(sendObject.sendId && sendObject.sendId != applyId) {
                                return;
                            }
                            if(sendObject.sendToList.length) {
                                to_list = sendObject.sendToList ;
                            }
                            cc_list = [];
                        }

                        that.statisticsService.queryById({
                            top: that.top,
                            projectId: applyId,
                            startDate: that.date
                        }, function(err, data) {
                            if (err) return logger.error('Send email statisticsService queryById error');
                            if ( data &&  data.length > 0) {
                                that.statisticsService.queryByChart({projectId : applyId , timeScope :2} , function (err , chartData){
                                    if(err || chartData.data.length <=0){
                                        that.sendEmail({
                                            to: to_list,
                                            cc: cc_list,
                                            title: name
                                        }, data[0]);
                                    }else {
                                        Exporting(getImageData(name , chartData.data), function (err , image){
                                            if(err){
                                                logger.info("generate image error " + err.toString() + ", id =" + applyId)
                                                that.sendEmail({
                                                    to: to_list,
                                                    cc: cc_list,
                                                    title: name
                                                }, data[0]);
                                            }else {
                                                var imagePath = "static/img/tmp/"  + (new Date -0 + applyId) + ".png";
                                                fs.writeFile( path.join(__dirname , ".." ,  imagePath), new Buffer(image, 'base64'), function() {
                                                    that.sendEmail({
                                                        to: to_list,
                                                        cc: cc_list,
                                                        title: name,
                                                        imagePath :imagePath
                                                    }, data[0] );
                                                });
                                            }
                                        });
                                    }
                               })
                            } else {
                                logger.error('Send email data format error');
                            }
                        }); // jshint ignore:line
                    })(orderByApplyId[applyId] , applyId); // jshint ignore:line
                }
            }
        });
        // if( isRetry === undefined ? true : !!isRetry) {
            setTimeout(function() {
                that.queryAll();
            }, 86400000);
        // }
    },
    sendEmail: function(emails, data  ) {
        var title = "【BadJS 日报 " + dateFormat(this.date, "yyyy-MM-dd") + "】- " + emails.title;
        data.title = emails.title;
        var content = this.render(data , emails.imagePath  );
        send_email(this.from, emails.to, emails.cc, title, content);
    },
    start: function() {
        var that = this;
        var date = new Date();
        date.setDate(date.getDate() + 1);
        var time = GLOBAL.pjconfig.email.time.toString().split(':');
        date.setHours(parseInt(time[0], 10) || 9, parseInt(time[1], 10) || 0, parseInt(time[2], 10) || 0, 0);
        var timeDiff = date.valueOf() - (new Date()).valueOf();
        setTimeout(function() {
            that.queryAll();
        }, timeDiff);
        logger.info('Email service will start after: ' + timeDiff);
    }
};

module.exports = EmailService;
<commit_msg>format<commit_after>/* global global, GLOBAL, module, __dirname, Buffer */
/**
 * Created by kaelyang on 2015/5/19.
 */
var fs = require("fs");
var http = require('http');
var path = require("path");

var _ = require('underscore');
var logger = require('log4js').getLogger();
var UserService = require('./UserService');
var dateFormat = require("../utils/dateFormat");
var exporting = require('node-highcharts-exporting');
var StatisticsService = require('./StatisticsService');
var sendEmail = require("../utils/" + GLOBAL.pjconfig.email.module);

var DAY_LENGTH = 30;

var EmailService = function() {
    this.userService = new UserService();
    this.statisticsService = new StatisticsService();
    this.top = parseInt(GLOBAL.pjconfig.email.top, 10) || 20;
    this.from = GLOBAL.pjconfig.email.from || "noreply-badjs@tencent.com";
    this.homepage = GLOBAL.pjconfig.email.homepage;
};

var getYesterday = function() {
    var date = new Date();
    date.setDate(date.getDate() - 1);
    date.setHours(0, 0, 0, 0);
    return date;
};

var setChartX = function(number) {
    var days = [];
    var nowDay = new Date() - 0;

    for (var i = number; i > 0; i--) {
        var day = nowDay - i * 1000 * 60 * 60 * 24;
        days.push(dateFormat(new Date(day), 'MM-dd'));
    }
    return days;
};

var getImageData = function(name, data) {

    var totalArray = [];
    var categories = setChartX(DAY_LENGTH);

    for (var i = 0; i < DAY_LENGTH; i++) {
        totalArray.push(0);
    }

    function whichDayIndex(day1) {
        for (var i = 0, len = categories.length; i < len; i++) {
            if (day1 == categories[i]) {
                return i;
            }
        }
        return false;
    }

    _.forEach(data, function(value, key) {
        var index = whichDayIndex(dateFormat(new Date(value.startDate), 'MM-dd'));
        totalArray[index] = value.total;
    });

    return {
        data: {
            xAxis: {
                categories: categories
            },
            series: [{
                data: totalArray,
                name: "-"
            }]
        },
        options: {
            title: {
                text: "The last " + DAY_LENGTH + " days line charts"
            },
            "yAxis": {
                "title": {
                    "text": "total"
                }
            }
        },
        width: 800
    };
};

var encodeHtml = function(str) {
    return (str + '').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\x60/g, '`').replace(/\x27/g, ''').replace(/\x22/g, '"');
};

EmailService.prototype = {
    render: function(data, imagePath) {
        var that = this;
        data = data || {};
        var html = [];
        html.push('');
        html.push('
【BadJS日报邮件】 ' + data.title + '
');
        that.homepage &&
            html.push('
日志查看点这: {{homepage}}
'
                .replace(/{{homepage}}/g, that.homepage));
        var content = data.content;
        if (content && content.length) {

            if (imagePath) {
                html.push('
最近' + DAY_LENGTH + '天图表统计
');
                html.push('

');
            }

            html.push('

#	出现次数	错误内容
');
            var total_top = 0;
            content.forEach(function(v, i) {
                v = typeof v === 'object' ? v : null;
                if (v) {
                    html.push('
{{index}}	{{times}}	{{desc}}
'
                        .replace(/{{index}}/g, i + 1)
                        .replace(/{{times}}/g, v.total)
                        .replace(/{{desc}}/g, encodeHtml(v.title))
                        .replace(/{{bgc}}/g, i % 2 ? '#fff' : '#eee')
                    );
                    total_top += v.total;
                }
            });
            html.push('
');
            var total = data.total;
            total > 0 && html.push('
共 {{total}} 条记录, Top {{top}} 占 {{per}}.
'
                .replace(/{{total}}/g, total)
                .replace(/{{top}}/g, that.top)
                .replace(/{{per}}/g, (total_top * 100 / total).toFixed(2) + '%')
            );

        } else {
            html.push('
暂无数据
');
        }

        html.push('');
        return html.join('');
    },
    queryAll: function(isRetry, sendObject) {
        var that = this;
        that.date = getYesterday();
        logger.info('Send mail query all start');
        that.userService.queryListByCondition({
            applyId: -1,
            role: -1
        }, function(err, userlist) {
            if (err) {
                return logger.error('Send email userService queryListByCondition error');
            } else {
                var orderByApplyId = {};
                userlist.forEach(function(v) {
                    // 兼容没有登陆过的用户，自动拼接 邮箱后缀
                    if (!v.email) {
                        v.email = v.loginName + GLOBAL.pjconfig.email.emailSuffix;
                    }
                    if (orderByApplyId[v.applyId]) {
                        orderByApplyId[v.applyId].push(v);
                    } else {
                        orderByApplyId[v.applyId] = [v];
                    }
                });
                for (var applyId in orderByApplyId) {
                    (function(users, applyId) {
                        var to_list = []; // 收件方
                        var cc_list = []; // 抄送方
                        var name = '';
                        users.forEach(function(v) {
                            v.role === 0 ? cc_list.push(v.email) : to_list.push(v.email);
                            name = v.name;
                        }); // jshint ignore:line

                        //测试代码
                        if (sendObject) {
                            if (sendObject.sendId && sendObject.sendId != applyId) {
                                return;
                            }
                            if (sendObject.sendToList.length) {
                                to_list = sendObject.sendToList;
                            }
                            cc_list = [];
                        }

                        that.statisticsService.queryById({
                            top: that.top,
                            projectId: applyId,
                            startDate: that.date
                        }, function(err, data) {
                            if (err) return logger.error('Send email statisticsService queryById error');
                            if (data && data.length > 0) {
                                that.statisticsService.queryByChart({
                                    projectId: applyId,
                                    timeScope: 2
                                }, function(err, chartData) {
                                    if (err || chartData.data.length <= 0) {
                                        that.sendEmail({
                                            to: to_list,
                                            cc: cc_list,
                                            title: name
                                        }, data[0]);
                                    } else {
                                        exporting(getImageData(name, chartData.data), function(err, image) {
                                            if (err) {
                                                logger.info("generate image error " + err.toString() + ", id =" + applyId);
                                                that.sendEmail({
                                                    to: to_list,
                                                    cc: cc_list,
                                                    title: name
                                                }, data[0]);
                                            } else {
                                                var imagePath = "static/img/tmp/" + (new Date - 0 + applyId) + ".png";
                                                fs.writeFile(path.join(__dirname, "..", imagePath), new Buffer(image, 'base64'), function() {
                                                    that.sendEmail({
                                                        to: to_list,
                                                        cc: cc_list,
                                                        title: name,
                                                        imagePath: imagePath
                                                    }, data[0]);
                                                });
                                            }
                                        });
                                    }
                                });
                            } else {
                                logger.error('Send email data format error');
                            }
                        }); // jshint ignore:line
                    })(orderByApplyId[applyId], applyId); // jshint ignore:line
                }
            }
        });
        // if( isRetry === undefined ? true : !!isRetry) {
        setTimeout(function() {
            that.queryAll();
        }, 86400000);
        // }
    },
    sendEmail: function(emails, data) {
        var title = "【BadJS 日报 " + dateFormat(this.date, "yyyy-MM-dd") + "】- " + emails.title;
        data.title = emails.title;
        var content = this.render(data, emails.imagePath);
        sendEmail(this.from, emails.to, emails.cc, title, content);
    },
    start: function() {
        var that = this;
        var date = new Date();
        date.setDate(date.getDate() + 1);
        var time = GLOBAL.pjconfig.email.time.toString().split(':');
        date.setHours(parseInt(time[0], 10) || 9, parseInt(time[1], 10) || 0, parseInt(time[2], 10) || 0, 0);
        var timeDiff = date.valueOf() - (new Date()).valueOf();
        setTimeout(function() {
            that.queryAll();
        }, timeDiff);
        logger.info('Email service will start after: ' + timeDiff);
    }
};

module.exports = EmailService;<|endoftext|>


<commit_before>"use strict";

var fs                          = require('fs'),
    path                        = require('path'),
    rng                         = require('crypto').rng,
    _                           = require('underscore'),
    q                           = require('kew'),
    through                     = require('through'),
    nodeResolve                 = require('resolve'),
    browserResolve              = require('browser-resolve'),
    aggregate                   = require('stream-aggregate-promise'),
    asStream                    = require('as-stream'),

    all                         = q.all,
    toPromise                   = q.resolve,
    clone                       = _.clone,
    isString                    = _.isString,
    isObject                    = _.isObject,
    extend                      = _.extend,
    isArray                     = Array.isArray,

    extractDependencies         = require('./transforms/deps'),
    jsonToCommonJS              = require('./transforms/json')

module.exports = function(mains, opts) {
  return new Graph(mains, opts).toStream()
}
module.exports.Graph = Graph

function Graph(mains, opts) {
  var self = this

  self.opts = opts || {}
  self.output = through()
  self.basedir = self.opts.basedir || process.cwd()
  self.resolveImpl = resolveWith.bind(null, self.opts.resolve || browserResolve)
  self.resolved = {}
  self.seen = {}
  self.entries = [].concat(mains).filter(Boolean).map(function(m) {
    var mod = {entry: true}
    if (typeof m.pipe === 'function') {
      mod.id = path.join(self.basedir, rng(8).toString('hex') + '.js')
      mod.sourcePromise = aggregate(m)
    } else {
      mod.id = path.resolve(m)
    }
    return mod
  })
}

Graph.prototype = {

  resolve: function(id, parent) {
    var self = this
    if (self.opts.filter && !self.opts.filter(id))
      return toPromise({id: false})
    else {
      var relativeTo = {
        packageFilter: self.opts.packageFilter,
        extensions: self.opts.extensions,
        modules: self.opts.modules,
        paths: [],
        filename: parent.id,
        package: parent.package
      }
      return self.resolveImpl(id, relativeTo)
        .then(function(r) { return self.resolved[r.id] = r })
        .fail(function(err) {
          err.message += [', module required from', parent.id].join(' ')
          throw err
        })
    }
  },

  resolveDeps: function(ids, parent) {
    var self = this
    var result = {},
        resolutions = all(ids.map(function(id) {
          return self.resolve(id, parent).then(function(r) {result[id] = r.id})
        }))
    return resolutions.then(function() { return result })
  },

  toStream: function() {
    var self = this
    all(self.entries.map(function(mod) {return self.walk(mod, {id: '/'})}))
      .fail(self.output.emit.bind(self.output, 'error'))
      .fin(self.output.queue.bind(self.output, null))
    return self.output
  },

  toPromise: function() {
    return aggregate(this.toStream())
  },

  walk: function(mod, parent) {
    var self = this
    if (isString(mod)) mod = self.resolved[mod]
    if (self.seen[mod.id]) return
    self.seen[mod.id] = true

    var cached = self.checkCache(mod, parent)
    if (cached) {
      self.emit(cached)
      return self.walkDeps(cached, parent)
    }

    return self.applyTransforms(mod)
      .then(self.emit.bind(self))
      .then(self.walkDeps.bind(self))
  },

  walkDeps: function(mod) {
    var self = this
    return all(Object.keys(mod.deps)
      .filter(function(id) { return mod.deps[id] })
      .map(function(id) { return self.walk(mod.deps[id], mod) }))
  },

  emit: function(mod) {
    var self = this,
        result = clone(mod)

    delete result.package
    delete result.sourcePromise

    if (!result.deps)
      result.deps = {}
    if (Buffer.isBuffer(result.source))
      result.source = result.source.toString()

    self.output.queue(result)
    return mod
  },

  checkCache: function(mod, parent) {
    var self = this
    if (!(self.opts.cache && self.opts.cache[parent.id])) return
    var id = self.opts.cache[parent.id].deps[mod.id]
    return self.opts.cache[id]
  },

  readSource: function(mod) {
    if (mod.source) return toPromise(mod)
    var promise = mod.sourcePromise || aggregate(fs.createReadStream(mod.id))
    return promise.then(function(source) {
      mod.source = source
      return mod
    })
  },

  applyTransforms: function(mod) {
    var self = this,
        txs = [],
        p = self.readSource(mod),
        isTopLevel = self.entries.some(function (entry) {
      return path.relative(path.dirname(entry.id), mod.id)
        .split('/').indexOf('node_modules') < 0
    })

    if (isTopLevel)
      txs = txs.concat(self.opts.transform)

    if (mod.package && self.opts.transformKey)
      txs = txs.concat(getTransform(mod.package, self.opts.transformKey))

    txs = txs.filter(Boolean).map(loadTransform.bind(null, mod))
    txs.push(extractDependencies)
    txs.push(jsonToCommonJS)

    return all(txs).then(function(txs) {
      txs.forEach(function(t) {
        p = p.then(function(p) {
          if (t.length === 1)
            return runStreamingTransform(t, p)
          else
            return runTransform(t, p, self)
        })
      })
      return p
    })
  }
}

function mergeInto(target, source) {
  if (!source) return target
  var result = extend({}, target)
  for (var k in source) {
    var t = result[k], s = source[k]
    if (isArray(t) && isArray(s))
      result[k] = t.concat(s)
    else if (isObject(t) && isObject(s))
      result[k] = mergeInto(t, s)
    else
      result[k] = s
  }
  return result
}

function resolveWith(resolve, id, parent) {
  var p = q.defer()
  resolve(id, parent, function(err, filename, pkg) {
    if (err)
      p.reject(err)
    else
      p.resolve({id: filename, package: pkg})
  })
  return p
}

function runStreamingTransform(transform, mod) {
  return aggregate(asStream(mod.source).pipe(transform(mod.id)))
    .then(function(source) {
      mod.source = source
      return mod
    })
}

function runTransform(transform, mod, graph) {
  return toPromise(transform(mod, graph)).then(mergeInto.bind(null, mod))
}

function getTransform(pkg, key) {
  key.forEach(function (k) { if (pkg && typeof pkg === 'object') pkg = pkg[k] })
  return [].concat(pkg).filter(Boolean)
}

var transformResolve = resolveWith.bind(null, nodeResolve)

function loadTransform(mod, transform) {
  if (!isString(transform)) return toPromise(transform)

  return transformResolve(transform, {basedir: path.dirname(mod.id)})
    .fail(function() {
      return transformResolve(transform, {basedir: process.cwd()})
    })
    .then(function(res) {
      if (!res)
        throw new Error([
          'cannot find transform module ', transform,
          ' while transforming ', mod.id
        ].join(''))
      return require(res.id)
    })
    .fail(function(err) {
      err.message += ' which is required as a transform'
      throw err
    })
}
<commit_msg>gardening<commit_after>"use strict";

var fs                          = require('fs'),
    path                        = require('path'),
    rng                         = require('crypto').rng,
    _                           = require('underscore'),
    q                           = require('kew'),
    through                     = require('through'),
    nodeResolve                 = require('resolve'),
    browserResolve              = require('browser-resolve'),
    aggregate                   = require('stream-aggregate-promise'),
    asStream                    = require('as-stream'),

    all                         = q.all,
    toPromise                   = q.resolve,
    clone                       = _.clone,
    isString                    = _.isString,
    isObject                    = _.isObject,
    extend                      = _.extend,
    isArray                     = Array.isArray,

    depsTransform               = require('./transforms/deps'),
    jsonTransform               = require('./transforms/json')

module.exports = function(mains, opts) {
  return new Graph(mains, opts).toStream()
}
module.exports.Graph = Graph

function Graph(mains, opts) {
  var self = this

  self.opts = opts || {}
  self.output = through()
  self.basedir = self.opts.basedir || process.cwd()
  self.resolveImpl = resolveWith.bind(null, self.opts.resolve || browserResolve)
  self.resolved = {}
  self.seen = {}
  self.entries = [].concat(mains).filter(Boolean).map(function(m) {
    var mod = {entry: true}
    if (typeof m.pipe === 'function') {
      mod.id = path.join(self.basedir, rng(8).toString('hex') + '.js')
      mod.sourcePromise = aggregate(m)
    } else {
      mod.id = path.resolve(m)
    }
    return mod
  })
}

Graph.prototype = {

  resolve: function(id, parent) {
    var self = this
    if (self.opts.filter && !self.opts.filter(id))
      return toPromise({id: false})
    else {
      var relativeTo = {
        packageFilter: self.opts.packageFilter,
        extensions: self.opts.extensions,
        modules: self.opts.modules,
        paths: [],
        filename: parent.id,
        package: parent.package
      }
      return self.resolveImpl(id, relativeTo)
        .then(function(r) { return self.resolved[r.id] = r })
        .fail(function(err) {
          err.message += [', module required from', parent.id].join(' ')
          throw err
        })
    }
  },

  resolveDeps: function(ids, parent) {
    var self = this
    var result = {},
        resolutions = all(ids.map(function(id) {
          return self.resolve(id, parent).then(function(r) {result[id] = r.id})
        }))
    return resolutions.then(function() { return result })
  },

  toStream: function() {
    var self = this
    all(self.entries.map(function(mod) {return self.walk(mod, {id: '/'})}))
      .fail(self.output.emit.bind(self.output, 'error'))
      .fin(self.output.queue.bind(self.output, null))
    return self.output
  },

  toPromise: function() {
    return aggregate(this.toStream())
  },

  walk: function(mod, parent) {
    var self = this
    if (isString(mod)) mod = self.resolved[mod]
    if (self.seen[mod.id]) return
    self.seen[mod.id] = true

    var cached = self.checkCache(mod, parent)
    if (cached) {
      self.emit(cached)
      return self.walkDeps(cached, parent)
    }

    return self.applyTransforms(mod)
      .then(self.emit.bind(self))
      .then(self.walkDeps.bind(self))
  },

  walkDeps: function(mod) {
    var self = this
    return all(Object.keys(mod.deps)
      .filter(function(id) { return mod.deps[id] })
      .map(function(id) { return self.walk(mod.deps[id], mod) }))
  },

  emit: function(mod) {
    var self = this,
        result = clone(mod)

    delete result.package
    delete result.sourcePromise

    if (!result.deps)
      result.deps = {}
    if (Buffer.isBuffer(result.source))
      result.source = result.source.toString()

    self.output.queue(result)
    return mod
  },

  checkCache: function(mod, parent) {
    var self = this
    if (!(self.opts.cache && self.opts.cache[parent.id])) return
    var id = self.opts.cache[parent.id].deps[mod.id]
    return self.opts.cache[id]
  },

  readSource: function(mod) {
    if (mod.source) return toPromise(mod)
    var promise = mod.sourcePromise || aggregate(fs.createReadStream(mod.id))
    return promise.then(function(source) {
      mod.source = source
      return mod
    })
  },

  applyTransforms: function(mod) {
    var self = this,
        txs = [],
        p = self.readSource(mod),
        isTopLevel = self.entries.some(function (entry) {
      return path.relative(path.dirname(entry.id), mod.id)
        .split('/').indexOf('node_modules') < 0
    })

    if (isTopLevel)
      txs = txs.concat(self.opts.transform)

    if (mod.package && self.opts.transformKey)
      txs = txs.concat(getTransform(mod.package, self.opts.transformKey))

    txs = txs.filter(Boolean).map(loadTransform.bind(null, mod))
    txs.push(depsTransform)
    txs.push(jsonTransform)

    return all(txs).then(function(txs) {
      txs.forEach(function(t) {
        p = p.then(function(p) {
          if (t.length === 1)
            return runStreamingTransform(t, p)
          else
            return runTransform(t, p, self)
        })
      })
      return p
    })
  }
}

function mergeInto(target, source) {
  if (!source) return target
  var result = extend({}, target)
  for (var k in source) {
    var t = result[k], s = source[k]
    if (isArray(t) && isArray(s))
      result[k] = t.concat(s)
    else if (isObject(t) && isObject(s))
      result[k] = mergeInto(t, s)
    else
      result[k] = s
  }
  return result
}

function resolveWith(resolve, id, parent) {
  var p = q.defer()
  resolve(id, parent, function(err, filename, pkg) {
    if (err)
      p.reject(err)
    else
      p.resolve({id: filename, package: pkg})
  })
  return p
}

function runStreamingTransform(transform, mod) {
  return aggregate(asStream(mod.source).pipe(transform(mod.id)))
    .then(function(source) {
      mod.source = source
      return mod
    })
}

function runTransform(transform, mod, graph) {
  return toPromise(transform(mod, graph)).then(mergeInto.bind(null, mod))
}

function getTransform(pkg, key) {
  key.forEach(function (k) { if (pkg && typeof pkg === 'object') pkg = pkg[k] })
  return [].concat(pkg).filter(Boolean)
}

var transformResolve = resolveWith.bind(null, nodeResolve)

function loadTransform(mod, transform) {
  if (!isString(transform)) return toPromise(transform)

  return transformResolve(transform, {basedir: path.dirname(mod.id)})
    .fail(function() {
      return transformResolve(transform, {basedir: process.cwd()})
    })
    .then(function(res) {
      if (!res)
        throw new Error([
          'cannot find transform module ', transform,
          ' while transforming ', mod.id
        ].join(''))
      return require(res.id)
    })
    .fail(function(err) {
      err.message += ' which is required as a transform'
      throw err
    })
}
<|endoftext|>


<commit_before>function putData() {
  if (myChart.data.datasets[0].data.length > 11) {
      myChart.data.datasets[0].data.shift();
      myChart.data.labels.shift();
  }
  myChart.data.datasets[0].data.push(Math.random() * 100);
  myChart.data.labels.push(Math.floor(new Date()));
  myChart.options.scales.xAxes[0].ticks.min = myChart.data.labels[myChart.data.labels.length - 10];
  myChart.options.scales.xAxes[0].ticks.max = Math.floor(new Date());
  myChart.update();
}

function registerGradient() {
  var gradientLinePlugin = {
      // Called at start of update.
      beforeUpdate: function(chartInstance) {
        if (chartInstance.options.linearGradientLine) {
          // The context, needed for the creation of the linear gradient.
          var ctx = chartInstance.chart.ctx;
          // The first (and, assuming, only) dataset.
          var dataset = chartInstance.data.datasets[0];
          // Calculate min and max values of the dataset.
          var minValue = Number.MAX_VALUE;
          var maxValue = Number.MIN_VALUE;
          for (var i = 0; i < dataset.data.length; ++i) {
            if (minValue > dataset.data[i])
              minValue = dataset.data[i];
            if (maxValue < dataset.data[i])
              maxValue = dataset.data[i];
          }
          // Calculate Y pixels for min and max values.
          var yAxis = chartInstance.scales['y-axis-0'];
          var minValueYPixel = yAxis.getPixelForValue(minValue);
          var maxValueYPixel = yAxis.getPixelForValue(maxValue);
          // Create the gradient.
          var gradient = ctx.createLinearGradient(0, minValueYPixel, 0, maxValueYPixel);
          // A kind of red for min.
          gradient.addColorStop(0, '#26cce0');
          // A kind of blue for max.
          gradient.addColorStop(1, '#26e089');
          // Assign the gradient to the dataset's border color.
          dataset.borderColor = gradient;
          // Uncomment this for some effects, especially together with commenting the `fill: false` option below.
          // dataset.backgroundColor = gradient;
        }
      }
    };

    Chart.pluginService.register(gradientLinePlugin);
}

function newChart(id) {
  return (new Chart(id, {
        type: 'line',
        data: {
            datasets: [
                {
                    type: 'line',
                    lineTension: 0,
                    borderWidth: 1,
                    pointRadius: 0,
                    fill: false
                }
            ]
        },
        options: {
            linearGradientLine: true,
            legend: {
              display: false
            },
            scales: {
                xAxes: [{
                    display: false,
                    ticks: {}
                }],
                yAxes: [{
                    display: false,
                    ticks: {
                        beginAtZero: true,
                        max: 100
                    }
                }]
            }
        }
    }))
}

function ready(fn) {
  if (document.readyState != 'loading'){
    fn();
  } else {
    document.addEventListener('DOMContentLoaded', fn);
  }
}
<commit_msg>Tests<commit_after>function putData(myChart, value) {
  if (myChart.data.datasets[0].data.length > 11) {
      myChart.data.datasets[0].data.shift();
      myChart.data.labels.shift();
  }
  myChart.data.datasets[0].data.push(value);
  myChart.data.labels.push(Math.floor(new Date()));
  myChart.options.scales.xAxes[0].ticks.min = myChart.data.labels[myChart.data.labels.length - 10];
  myChart.options.scales.xAxes[0].ticks.max = Math.floor(new Date());
  myChart.update();
}

function registerGradient() {
  var gradientLinePlugin = {
      // Called at start of update.
      beforeUpdate: function(chartInstance) {
        if (chartInstance.options.linearGradientLine) {
          // The context, needed for the creation of the linear gradient.
          var ctx = chartInstance.chart.ctx;
          // The first (and, assuming, only) dataset.
          var dataset = chartInstance.data.datasets[0];
          // Calculate min and max values of the dataset.
          var minValue = Number.MAX_VALUE;
          var maxValue = Number.MIN_VALUE;
          for (var i = 0; i < dataset.data.length; ++i) {
            if (minValue > dataset.data[i])
              minValue = dataset.data[i];
            if (maxValue < dataset.data[i])
              maxValue = dataset.data[i];
          }
          // Calculate Y pixels for min and max values.
          var yAxis = chartInstance.scales['y-axis-0'];
          var minValueYPixel = yAxis.getPixelForValue(minValue);
          var maxValueYPixel = yAxis.getPixelForValue(maxValue);
          // Create the gradient.
          var gradient = ctx.createLinearGradient(0, minValueYPixel, 0, maxValueYPixel);
          // A kind of red for min.
          gradient.addColorStop(0, '#26cce0');
          // A kind of blue for max.
          gradient.addColorStop(1, '#26e089');
          // Assign the gradient to the dataset's border color.
          dataset.borderColor = gradient;
          // Uncomment this for some effects, especially together with commenting the `fill: false` option below.
          // dataset.backgroundColor = gradient;
        }
      }
    };

    Chart.pluginService.register(gradientLinePlugin);
}

function newChart(id) {
  return (new Chart(id, {
    type: 'line',
    data: {
      labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
      datasets: [
        {
          data: [12, 50, 7, 4, 42, 25, 4, 98, 43, 25, 0, 12],
          type: 'line',
          lineTension: 0,
          borderWidth: 1,
          pointRadius: 0,
          fill: false,
          borderColor: 'rgba(255,99,132,1)'
        }
      ]
    },
    options: {
      legend: {
        display: false
      },
      scales: {
        xAxes: [{
          display: false,
          ticks: {}
        }],
        yAxes: [{
          display: false,
          ticks: {
            beginAtZero: true,
            max: 100
          }
        }]
      }
    }
  }))
}

function ready(fn) {
  if (document.readyState != 'loading'){
    fn();
  } else {
    document.addEventListener('DOMContentLoaded', fn);
  }
}
<|endoftext|>


<commit_before>/*
* mvcApp
* author: ronglin
* create date: 2014.6.24
*/

'use strict';

var utils = require('./utilities'),
    caching = require('./caching'),
	mvcAreas = require('./mvcAreas'),
    mvcHandler = require('./mvcHandler'),
    mvcController = require('./mvcController'),
    mvcAttributes = require('./attributes/index'),
    mvcViewEngines = require('./mvcViewEngines'),
    mvcHandlerRouter = require('./mvcHandlerRouter');

var midError = require('./middles/error'),
    midHeader = require('./middles/header'),
    midRequest = require('./middles/request'),
    midResponse = require('./middles/response');

var bodyParser = require('body-parser'),
    cookieParser = require('cookie-parser');

var mvcApp = function(set) {
    utils.extend(this, set);
    if (!this.appPath) { throw new Error('Parameter "appPath" is required'); }
    this.areas = new mvcAreas(this.appPath);
    this.engines = new mvcViewEngines();
    this.attributes = new mvcAttributes();
    this._handlers = new mvcHandlerRouter();
    this._setts = caching.region('mvc-runtime-settings');
    this._setts.set('env', process.env.NODE_ENV || 'development');
};

mvcApp.prototype = {

    _setts: null, _handlers: null,

    appPath: null, areas: null, engines: null, attributes: null,

    constructor: mvcApp, className: 'mvcApp',

    get: function(key) {
        return this._setts.get(key);
    },

    set: function(key, val) {
        return this._setts.set(key, val);
    },

    use: function() {
        return this._handlers.register.apply(this._handlers, arguments);
    },

    disuse: function() {
        return this._handlers.unregister.apply(this._handlers, arguments);
    },

    handler: function () {
        // init
        this.areas.registerAll();
        this.attributes.registerAll();
        this.engines.register('.vash', require('./engines/vash'));
        //
        var handlers = this._handlers;
        handlers.register(bodyParser.json());
        handlers.register(bodyParser.json({ type: 'application/hal+json' }));
        handlers.register(bodyParser.urlencoded({ extended: true }));
        handlers.register(cookieParser());
        //
        handlers.register('/', 'midHeader', midHeader());
        handlers.register('/', 'midRequest', midRequest());
        handlers.register('/', 'midResponse', midResponse());
        handlers.registerAtLast('/', 'midError', midError());
        //
        handlers.register(mvcHandler(this));
        // entrance
        return function(req, res) {
            handlers.execute(req, res);
        };
    }
};

// export
module.exports = {
    caching: caching,
    controller: mvcController.define,
    newApp: function(set) {
        return new mvcApp(set);
    }
};
<commit_msg>update<commit_after>/*
* mvcApp
* author: ronglin
* create date: 2014.6.24
*/

'use strict';

var utils = require('./utilities'),
    caching = require('./caching'),
	mvcAreas = require('./mvcAreas'),
    mvcHandler = require('./mvcHandler'),
    mvcController = require('./mvcController'),
    mvcAttributes = require('./attributes/index'),
    mvcViewEngines = require('./mvcViewEngines'),
    mvcHandlerRouter = require('./mvcHandlerRouter');

var midError = require('./middles/error'),
    midHeader = require('./middles/header'),
    midRequest = require('./middles/request'),
    midResponse = require('./middles/response');

var bodyParser = require('body-parser'),
    cookieParser = require('cookie-parser');

var mvcApp = function(set) {
    utils.extend(this, set);
    if (!this.appPath) { throw new Error('Parameter "appPath" is required'); }
    this.areas = new mvcAreas(this.appPath);
    this.engines = new mvcViewEngines();
    this.attributes = new mvcAttributes();
    this._handlers = new mvcHandlerRouter();
    this._setts = caching.region('mvc-runtime-settings');
    this._setts.set('env', process.env.NODE_ENV || 'development');
};

mvcApp.prototype = {

    _setts: null, _handlers: null,

    appPath: null, areas: null, engines: null, attributes: null,

    constructor: mvcApp, className: 'mvcApp',

    get: function(key) {
        return this._setts.get(key);
    },

    set: function(key, val) {
        return this._setts.set(key, val);
    },

    use: function() {
        return this._handlers.register.apply(this._handlers, arguments);
    },

    disuse: function() {
        return this._handlers.unregister.apply(this._handlers, arguments);
    },

    handler: function () {
        // init
        this.areas.registerAll();
        this.attributes.registerAll();
        this.engines.register('.vash', require('./engines/vash'));
        //
        var handlers = this._handlers;
        handlers.register(bodyParser.json());
        handlers.register(bodyParser.json({ type: 'application/hal+json' }));
        handlers.register(bodyParser.urlencoded({ extended: true }));
        handlers.register(cookieParser());
        //
        handlers.register('/', 'midHeader', midHeader());
        handlers.register('/', 'midRequest', midRequest());
        handlers.register('/', 'midResponse', midResponse());
        handlers.registerAtLast('/', 'midError', midError());
        //
        handlers.register(mvcHandler(this));
        // entrance
        return function(req, res) {
            handlers.execute(req, res);
        };
    }
};

// export
module.exports = {
    utils: utils,
    caching: caching,
    controller: mvcController.define,
    current: null,
    newApp: function(set) {
        return (this.current = new mvcApp(set));
    }
};
<|endoftext|>


<commit_before>'use strict';

let util = require('util');
let twitterAPI = require('node-twitter-api');
let validUrl = require('valid-url');

let BotPlug = require( './BotPlug.js' );
let twitterConfig = require( '../config.js' ).twitter;

class DagensMixBotPlug extends BotPlug {
    constructor( bot ){
        super( bot );

        this.mixes = [];

        this.initMix = 'Kokarn: Lägg in dagens mix!';
        this.addCommand = '!addmix';
        this.sayCommand = '!mix';
        this.listCommands = ['!listmix', '!mixlist'];
        this.response = 'Tack %s! Nu blir det dunkadunka!'

        this.resetTimer = 0

        this.setup();
    }

    setup() {
        this.detectCommand( this.sayCommand, ( from, text, message ) => {
            if( this.currentMix ){
                this.sendMessageToChannel( message.args[ 0 ], this.currentMix );
            } else {
                this.sendMessageToChannel( message.args[ 0 ], this.initMix );
            }
        });

        for ( let i = 0; i < this.listCommands.length; i = i + 1) {
            this.detectCommand( this.listCommands[ i ], ( from, text, message ) => {
                this.list( message.args[ 0 ] );
            });
        }

        this.detectCommand( this.addCommand, ( from, text, message ) => {
            var mix = text.substring( this.addCommand.length );
            if( validUrl.isUri( mix ) ){
                this.add( mix, from, message.args[ 0 ] );
            } else {
                console.log( 'Not adding', mix, 'as a mix because it\'s not a valid URI' );
            }
        });

        // start reset timeouts
        this.reset();
    }

    reset() {
        if (this.dayMixAdded < today()) {
            this.currentMix = false;
        }

        this.resetTimer = setTimeout(() => {
            this.reset();
        }, 300000 );
    }

    tweetMix(mix) {
        let twitter = new twitterAPI({
            consumerKey: twitterConfig.consumerKey,
            consumerSecret: twitterConfig.consumerSecret
        });

        twitter.statuses('update', {
                status: mix
            },
            twitterConfig.accessToken,
            twitterConfig.accessTokenSecret,
            ( error, data ) => {
                if (error) {
                    console.log(error);
                } else {
                    console.log('Tweet successfull');
                    console.log(data);
                }
            }
        );
    }

    addMix(mix) {
        this.mixes.push(mix);
        this.currentMix = mix;
        this.dayMixAdded = today();

        this.tweetMix(mix);
    }

    list( channel ) {
        var mixes = this.mixes.filter( (item) => {
            return item !== this.initMix;
        }, this );

        this.sendMessageToChannel( channel, mixes.join( '\n' ) );
    }

    add( mix, from, channel ) {
        this.addMix( mix );

        this.sendMessageToChannel( channel, util.format( this.response, from ) );
    }
}

function today() {
    var now = new Date();
    return now - (now % 86400000);
}

module.exports = DagensMixBotPlug;
<commit_msg>Trim mix so it's actually a valid URI<commit_after>'use strict';

let util = require('util');
let twitterAPI = require('node-twitter-api');
let validUrl = require('valid-url');

let BotPlug = require( './BotPlug.js' );
let twitterConfig = require( '../config.js' ).twitter;

class DagensMixBotPlug extends BotPlug {
    constructor( bot ){
        super( bot );

        this.mixes = [];

        this.initMix = 'Kokarn: Lägg in dagens mix!';
        this.addCommand = '!addmix';
        this.sayCommand = '!mix';
        this.listCommands = ['!listmix', '!mixlist'];
        this.response = 'Tack %s! Nu blir det dunkadunka!'

        this.resetTimer = 0

        this.setup();
    }

    setup() {
        this.detectCommand( this.sayCommand, ( from, text, message ) => {
            if( this.currentMix ){
                this.sendMessageToChannel( message.args[ 0 ], this.currentMix );
            } else {
                this.sendMessageToChannel( message.args[ 0 ], this.initMix );
            }
        });

        for ( let i = 0; i < this.listCommands.length; i = i + 1) {
            this.detectCommand( this.listCommands[ i ], ( from, text, message ) => {
                this.list( message.args[ 0 ] );
            });
        }

        this.detectCommand( this.addCommand, ( from, text, message ) => {
            var mix = text.substring( this.addCommand.length ).trim();
            if( validUrl.isUri( mix ) ){
                this.add( mix, from, message.args[ 0 ] );
            } else {
                console.log( 'Not adding', mix, 'as a mix because it\'s not a valid URI' );
            }
        });

        // start reset timeouts
        this.reset();
    }

    reset() {
        if (this.dayMixAdded < today()) {
            this.currentMix = false;
        }

        this.resetTimer = setTimeout(() => {
            this.reset();
        }, 300000 );
    }

    tweetMix(mix) {
        let twitter = new twitterAPI({
            consumerKey: twitterConfig.consumerKey,
            consumerSecret: twitterConfig.consumerSecret
        });

        twitter.statuses('update', {
                status: mix
            },
            twitterConfig.accessToken,
            twitterConfig.accessTokenSecret,
            ( error, data ) => {
                if (error) {
                    console.log(error);
                } else {
                    console.log('Tweet successfull');
                    console.log(data);
                }
            }
        );
    }

    addMix(mix) {
        this.mixes.push(mix);
        this.currentMix = mix;
        this.dayMixAdded = today();

        this.tweetMix(mix);
    }

    list( channel ) {
        var mixes = this.mixes.filter( (item) => {
            return item !== this.initMix;
        }, this );

        this.sendMessageToChannel( channel, mixes.join( '\n' ) );
    }

    add( mix, from, channel ) {
        this.addMix( mix );

        this.sendMessageToChannel( channel, util.format( this.response, from ) );
    }
}

function today() {
    var now = new Date();
    return now - (now % 86400000);
}

module.exports = DagensMixBotPlug;
<|endoftext|>


<commit_before>/**
 *  FsTools
 *
 *  Collection of FS related tools, that stdlib lack of.
 **/

'use strict';

// stdlib
var fs = require('fs'),
    path_join = require('path').join,
    dirname = require('path').dirname;

// 3rd-party
var Promise = require('simple-promise'),
    _ = require('underscore');

// INTERNAL HELPERS
////////////////////////////////////////////////////////////////////////////////

//  walk_flat(path, iterator, callback) -> void
//  - path (String): Path to iterate through
//  - iterator (Function): Will be fired on each element within `path`
//  - callback (Function): Will be fired once all files were processed
//
//  Walks through given `path` and calls `iterator(path, stats, callback)` for
//  each foun entry (regardless to it's type) and waits for all `callback`s
//  (passed to iterator) to be fired. After all callbacks were fired, fires
//  `callback` (given to walk_flat itself).
//
//  NOTICE: It walks through single dimension of file system - it won't go into
//          found sub-directories. See `walk_recursive` for this puprpose.
//
//  Example:
//
//    walk_flat('/home/nodeca', function (path, stats, callback) {
//      if ('/home/nodeca/secrets.yml' === path) {
//        callback(Error("There is secrets file."));
//        return;
//      }
//
//      if ('/home/nodeca/xxx' === path && stats.isDirectory()) {
//        callback(Error("Path contains xxx directory."));
//        return;
//      }
//
//      callback();
//    }, function (err) {
//      if (err) console.error(err);
//      console.log('Done');
//    });
var walk_flat = function walk_flat(path, iterator, callback) {
  fs.readdir(path, function (err, files) {
    var all;

    if (err) {
      callback(err);
      return;
    }

    all = new Promise.Joint(callback);

    _(files).chain().map(function(file) {
      return path_join(path, file);
    }).each(function (path) {
      var promise = all.promise();

      fs.stat(path, function (err, stats) {
        if (err) {
          all.reject(err);
          return;
        }

        iterator(path, stats, function (err) {
          if (err) {
            all.reject(err);
            return;
          }

          promise.resolve();
        });
      });
    });

    all.wait();
  });
};

//  walk_recursive(path, iterator, callback) -> void
//
//  Proxies call to `walk_flat`, but wraps `iterator` so that it will
//  recursively go deeper inside each found directoy instead of calling
//  iterator on it.
var walk_recursive = function walk_recursive(path, iterator, callback) {
  // walk through given path
  walk_flat(path, function (path, stats, callback) {
    // go deeper inside
    if (stats.isDirectory()) {
      walk_recursive(path, iterator, callback);
      return;
    }

    // call iterator if not directory
    iterator(path, stats, callback);
  }, callback);
};

// PUBLIC API
////////////////////////////////////////////////////////////////////////////////

/**
 *  FsTools.walk(path, pattern, iterator[, callback]) -> void
 *  FsTools.walk(path, iterator[, callback]) -> void
 *
 *  Walks throught all files withing `path` (including sub-dirs) and calls
 *  `iterator` on each found file (or block device etc.) matching `pattern`.
 *  If no `pattern` was given - will fire call `iterator` for every single
 *  path found. After all iterations will call `callback` (if it was specified)
 *  with passing `error` as first arguemtn if there was an error.
 *
 *  ##### Iterator
 *
 *  All iterations are running within promise. So `callback` given to the `walk`
 *  will fire only after all `iterator` callbacks willnotify they finished their
 *  work:
 *
 *      var iterator = function (path, stats, callback) {
 *        // ... do something
 *        if (err) {
 *          // ... if error occured we can "stop" walker
 *          callback(err);
 *          return;
 *        }
 *        // ... if everything is good and finished notify walker we're done
 *        callback();
 *      };
 *
 *  Iterator is called with following arguments:
 *
 *  - `path` (String): Full path of the found element (e.g. `/foo/bar.txt`)
 *  - `stats` (fs.Stats): Stats object of found path
 *  - `callback` (Function): Callback function to call after path processing
 *
 *
 *  ##### Example
 *
 *      fstools.walk('/home/nodeca', function (path, stats, callback) {
 *        if (stats.isBlockDevice()) {
 *          callback(Error("WTF? Block devices are not expetcted in my room"));
 *          return;
 *        }
 *
 *        if (stats.isSocket()) {
 *          console.log("Finally I found my socket");
 *        }
 *
 *        callback();
 *      }, function (err) {
 *        if (err) {
 *          // shit happens!
 *          console.error(err);
 *          process.exit(1);
 *        }
 *
 *        console.log("Hooray! We're done!");
 *      });
 *
 *
 *  ##### Example (using pattern matching)
 *
 *      fstools.walk('/home/nodeca', '\.yml$', function (path, stats, callback) {
 *        fs.readFile(path, 'utf-8', funtion (err, str) {
 *          if (err) {
 *            callback(err);
 *            return;
 *          }
 *
 *          console.log(str);
 *          callback();
 *        });
 *      }, function (err) {
 *        if (err) {
 *          console.error(err);
 *        }
 *
 *        console.log('Done!');
 *      });
 **/
var walk = exports.walk = function walk(path, pattern, iterator, callback) {
  var match; // function that tells whenever iterator need to be called or not

  if (_.isFunction(pattern)) {
    // Scenario: FileWalker(path, iterator[, callback])
    callback = iterator;
    iterator = pattern;
    match = function () { return true; };
  } else {
    // Scenario: FileWalker(path, pattern, iterator[, callback])
    pattern = new RegExp(pattern);
    match = function (path) { return path.test(pattern); };
  }

  if (!_.isFunction(callback)) {
    // Scenario: FileWalker(path, pattern, iterator)
    //       or: FileWalker(path, iterator)
    callback = function () {};
  }

  // start walking
  walk_recursive(path, function(path, stats, callback) {
    // call iterator on
    if (match(path)) {
      iterator(path, stats, callback);
      return;
    }

    callback();
  }, callback);
};

/**
 *  FsTools.rm_rf(path, callback) -> void
 *  - path (String): Path to remove
 *  - callback (Function): Fired after path was removed
 *
 *  Removes given `path`. If it was a directory will remove it recursively,
 *  similar to UNIX' `rm -rf <path>`. After all will fire `callback(err)` with
 *  an error if there were any.
 *
 *  If given `path` was file - will proxy call to `fs.unlink`.
 *
 *
 *  ##### Example
 *
 *      fstools.rm_rf('/home/nodeca/trash', function (err) {
 *        if (err) {
 *          console.log("U can't touch that");
 *          console.err(err);
 *          process.exit(1);
 *        } else {
 *          console.log("It's Hammer time");
 *          process.exit(0);
 *        }
 *      });
 **/
var rm_rf = exports.rm_rf = function rm_rf(path, callback) {
  fs.stat(path, function (err, stats) {
    if (err) {
      callback(err);
      return;
    }

    if (!stats.isDirectory()) {
      fs.unlink(path, callback);
      return;
    }

    walk_flat(path, function (path, stats, callback) {
      if (stats.isDirectory()) {
        rm_rf(path, function (err) {
          if (err) {
            callback(err);
            return;
          }

          fs.rmdir(path, callback);
        });
        return;
      }

      fs.unlink(path, callback);
    }, callback);
  });
};

/**
 *  FsTools.mkdir_p(path, callback) -> void
 *  - path (String): Path to create
 *  - callback (Function): Fired after path was created
 *
 *  Creates given path, creating parents recursively if needed.
 *  Similar to UNIX' `mkdir -p <path>`. After all will fire `callback(err)` with
 *  an error if there were any.
 *
 *
 *  ##### Example
 *
 *      fstools.mkdir_p('/home/nodeca/media/xxx', function (err) {
 *        if (err) {
 *          console.log("Can't' create directory");
 *          console.err(err);
 *          process.exit(1);
 *        } else {
 *          console.log("We can now store some romantic movies here");
 *          process.exit(0);
 *        }
 *      });
 **/
var mkdir_p = exports.mkdir_p = function mkdir_p(path, callback) {
  path.exists(dir, function (exists) {
    var parent;

    if (exists) {
      callback(null);
      return;
    }

    parent = dirname(dir);

    mkdir_p(parent, function (err) {
      if (err) {
        callback(err);
        return;
      }

      fs.mkdir(dir, '0755', function (err) {
        // EEXIST is not error in our case
        // but a race condition :((
        if (err && 'EEXIST' === err.code) {
          callback(null);
          return;
        }

        // fallback to default behavior
        callback(err);
      });
    });
  });
};

/**
 *  FsTools.copy(src, dst, callback) -> void
 *  - src (String): Source file
 *  - dst (String): Detination file
 *  - callback (Function): Fired after path was copied
 *
 *  Copies `src` to `dst`, creates directory for given `dst` with
 *  [[FsTools.mkdir_p]] if needed. After all will fire `callback(err)` with
 *  an error if there were any.
 *
 *
 *  ##### Example
 *
 *      var src = '/home/nodeca/secrets.yml',
 *          dst = '/home/nodeca/very/deep/secrets/main.yml';
 *
 *      fstools.copy(src, dst, function (err) {
 *        if (err) {
 *          console.log("Failed copy " + src + " into " + dst);
 *          console.err(err);
 *          process.exit(1);
 *        } else {
 *          console.log("Fone!");
 *          process.exit(0);
 *        }
 *      });
 **/
var copy = exports.copy = function copy(src, dst, callback) {
  fs.readFile(src, function (err, buff) {
    if (err) {
      callback(err);
      return;
    }

    mkdir_p(dirname(dst), function (err) {
      if (err) {
        callback(err);
        return;
      }

      fs.writeFile(dst, buff, callback);
    });
  });
};

////////////////////////////////////////////////////////////////////////////////
// vim:ts=2:sw=2
////////////////////////////////////////////////////////////////////////////////
<commit_msg>Small fixes<commit_after>/**
 *  FsTools
 *
 *  Collection of FS related tools, that stdlib lack of.
 **/

'use strict';

// stdlib
var fs = require('fs'),
    path_join = require('path').join,
    path_exists = require('path').exists,
    dirname = require('path').dirname;

// 3rd-party
var Promise = require('simple-promise'),
    _ = require('underscore');

// INTERNAL HELPERS
////////////////////////////////////////////////////////////////////////////////

//  walk_flat(path, iterator, callback) -> void
//  - path (String): Path to iterate through
//  - iterator (Function): Will be fired on each element within `path`
//  - callback (Function): Will be fired once all files were processed
//
//  Walks through given `path` and calls `iterator(path, stats, callback)` for
//  each foun entry (regardless to it's type) and waits for all `callback`s
//  (passed to iterator) to be fired. After all callbacks were fired, fires
//  `callback` (given to walk_flat itself).
//
//  NOTICE: It walks through single dimension of file system - it won't go into
//          found sub-directories. See `walk_recursive` for this puprpose.
//
//  Example:
//
//    walk_flat('/home/nodeca', function (path, stats, callback) {
//      if ('/home/nodeca/secrets.yml' === path) {
//        callback(Error("There is secrets file."));
//        return;
//      }
//
//      if ('/home/nodeca/xxx' === path && stats.isDirectory()) {
//        callback(Error("Path contains xxx directory."));
//        return;
//      }
//
//      callback();
//    }, function (err) {
//      if (err) console.error(err);
//      console.log('Done');
//    });
var walk_flat = function walk_flat(path, iterator, callback) {
  fs.readdir(path, function (err, files) {
    var all;

    if (err) {
      callback(err);
      return;
    }

    all = new Promise.Joint(callback);

    _(files).chain().map(function(file) {
      return path_join(path, file);
    }).each(function (path) {
      var promise = all.promise();

      fs.stat(path, function (err, stats) {
        if (err) {
          all.reject(err);
          return;
        }

        iterator(path, stats, function (err) {
          if (err) {
            all.reject(err);
            return;
          }

          promise.resolve();
        });
      });
    });

    all.wait();
  });
};

//  walk_recursive(path, iterator, callback) -> void
//
//  Proxies call to `walk_flat`, but wraps `iterator` so that it will
//  recursively go deeper inside each found directoy instead of calling
//  iterator on it.
var walk_recursive = function walk_recursive(path, iterator, callback) {
  // walk through given path
  walk_flat(path, function (path, stats, callback) {
    // go deeper inside
    if (stats.isDirectory()) {
      walk_recursive(path, iterator, callback);
      return;
    }

    // call iterator if not directory
    iterator(path, stats, callback);
  }, callback);
};

// PUBLIC API
////////////////////////////////////////////////////////////////////////////////

/**
 *  FsTools.walk(path, pattern, iterator[, callback]) -> void
 *  FsTools.walk(path, iterator[, callback]) -> void
 *
 *  Walks throught all files withing `path` (including sub-dirs) and calls
 *  `iterator` on each found file (or block device etc.) matching `pattern`.
 *  If no `pattern` was given - will fire call `iterator` for every single
 *  path found. After all iterations will call `callback` (if it was specified)
 *  with passing `error` as first arguemtn if there was an error.
 *
 *  ##### Iterator
 *
 *  All iterations are running within promise. So `callback` given to the `walk`
 *  will fire only after all `iterator` callbacks willnotify they finished their
 *  work:
 *
 *      var iterator = function (path, stats, callback) {
 *        // ... do something
 *        if (err) {
 *          // ... if error occured we can "stop" walker
 *          callback(err);
 *          return;
 *        }
 *        // ... if everything is good and finished notify walker we're done
 *        callback();
 *      };
 *
 *  Iterator is called with following arguments:
 *
 *  - `path` (String): Full path of the found element (e.g. `/foo/bar.txt`)
 *  - `stats` (fs.Stats): Stats object of found path
 *  - `callback` (Function): Callback function to call after path processing
 *
 *
 *  ##### Example
 *
 *      fstools.walk('/home/nodeca', function (path, stats, callback) {
 *        if (stats.isBlockDevice()) {
 *          callback(Error("WTF? Block devices are not expetcted in my room"));
 *          return;
 *        }
 *
 *        if (stats.isSocket()) {
 *          console.log("Finally I found my socket");
 *        }
 *
 *        callback();
 *      }, function (err) {
 *        if (err) {
 *          // shit happens!
 *          console.error(err);
 *          process.exit(1);
 *        }
 *
 *        console.log("Hooray! We're done!");
 *      });
 *
 *
 *  ##### Example (using pattern matching)
 *
 *      fstools.walk('/home/nodeca', '\.yml$', function (path, stats, callback) {
 *        fs.readFile(path, 'utf-8', funtion (err, str) {
 *          if (err) {
 *            callback(err);
 *            return;
 *          }
 *
 *          console.log(str);
 *          callback();
 *        });
 *      }, function (err) {
 *        if (err) {
 *          console.error(err);
 *        }
 *
 *        console.log('Done!');
 *      });
 **/
var walk = exports.walk = function walk(path, pattern, iterator, callback) {
  var match; // function that tells whenever iterator need to be called or not

  if (_.isFunction(pattern)) {
    // Scenario: FileWalker(path, iterator[, callback])
    callback = iterator;
    iterator = pattern;
    match = function () { return true; };
  } else {
    // Scenario: FileWalker(path, pattern, iterator[, callback])
    pattern = new RegExp(pattern);
    match = function (path) { return path.test(pattern); };
  }

  if (!_.isFunction(callback)) {
    // Scenario: FileWalker(path, pattern, iterator)
    //       or: FileWalker(path, iterator)
    callback = function () {};
  }

  // start walking
  walk_recursive(path, function(path, stats, callback) {
    // call iterator on
    if (match(path)) {
      iterator(path, stats, callback);
      return;
    }

    callback();
  }, callback);
};

/**
 *  FsTools.rm_rf(path, callback) -> void
 *  - path (String): Path to remove
 *  - callback (Function): Fired after path was removed
 *
 *  Removes given `path`. If it was a directory will remove it recursively,
 *  similar to UNIX' `rm -rf <path>`. After all will fire `callback(err)` with
 *  an error if there were any.
 *
 *  If given `path` was file - will proxy call to `fs.unlink`.
 *
 *
 *  ##### Example
 *
 *      fstools.rm_rf('/home/nodeca/trash', function (err) {
 *        if (err) {
 *          console.log("U can't touch that");
 *          console.err(err);
 *          process.exit(1);
 *        } else {
 *          console.log("It's Hammer time");
 *          process.exit(0);
 *        }
 *      });
 **/
var rm_rf = exports.rm_rf = function rm_rf(path, callback) {
  fs.stat(path, function (err, stats) {
    if (err) {
      // file/dir not exists - no need to do anything
      if ('ENOENT' === err.code) {
        callback(null);
        return;
      }

      // unknown error - can't continue
      callback(err);
      return;
    }

    if (!stats.isDirectory()) {
      fs.unlink(path, callback);
      return;
    }

    walk_flat(path, function (path, stats, callback) {
      if (stats.isDirectory()) {
        rm_rf(path, function (err) {
          if (err) {
            callback(err);
            return;
          }

          fs.rmdir(path, callback);
        });
        return;
      }

      fs.unlink(path, callback);
    }, callback);
  });
};

/**
 *  FsTools.mkdir_p(path, callback) -> void
 *  - path (String): Path to create
 *  - callback (Function): Fired after path was created
 *
 *  Creates given path, creating parents recursively if needed.
 *  Similar to UNIX' `mkdir -p <path>`. After all will fire `callback(err)` with
 *  an error if there were any.
 *
 *
 *  ##### Example
 *
 *      fstools.mkdir_p('/home/nodeca/media/xxx', function (err) {
 *        if (err) {
 *          console.log("Can't' create directory");
 *          console.err(err);
 *          process.exit(1);
 *        } else {
 *          console.log("We can now store some romantic movies here");
 *          process.exit(0);
 *        }
 *      });
 **/
var mkdir_p = exports.mkdir_p = function mkdir_p(path, callback) {
  path_exists(path, function (exists) {
    var parent;

    if (exists) {
      callback(null);
      return;
    }

    parent = dirname(path);

    mkdir_p(parent, function (err) {
      if (err) {
        callback(err);
        return;
      }

      fs.mkdir(path, '0755', function (err) {
        // EEXIST is not error in our case
        // but a race condition :((
        if (err && 'EEXIST' === err.code) {
          callback(null);
          return;
        }

        // fallback to default behavior
        callback(err);
      });
    });
  });
};

/**
 *  FsTools.copy(src, dst, callback) -> void
 *  - src (String): Source file
 *  - dst (String): Detination file
 *  - callback (Function): Fired after path was copied
 *
 *  Copies `src` to `dst`, creates directory for given `dst` with
 *  [[FsTools.mkdir_p]] if needed. After all will fire `callback(err)` with
 *  an error if there were any.
 *
 *
 *  ##### Example
 *
 *      var src = '/home/nodeca/secrets.yml',
 *          dst = '/home/nodeca/very/deep/secrets/main.yml';
 *
 *      fstools.copy(src, dst, function (err) {
 *        if (err) {
 *          console.log("Failed copy " + src + " into " + dst);
 *          console.err(err);
 *          process.exit(1);
 *        } else {
 *          console.log("Fone!");
 *          process.exit(0);
 *        }
 *      });
 **/
var copy = exports.copy = function copy(src, dst, callback) {
  fs.readFile(src, function (err, buff) {
    if (err) {
      callback(err);
      return;
    }

    mkdir_p(dirname(dst), function (err) {
      if (err) {
        callback(err);
        return;
      }

      fs.writeFile(dst, buff, callback);
    });
  });
};

////////////////////////////////////////////////////////////////////////////////
// vim:ts=2:sw=2
////////////////////////////////////////////////////////////////////////////////
<|endoftext|>


<commit_before>var vm = require('vm');
var util = require('util');

var repl = require('repl');
var _ = require('lodash');

var Recoverable;

module.exports = {
  start: function (ctx) {
    var self = this;
    var config = _.clone(ctx.config);

    var replServer = repl.start(config);

    // Trick REPLServer into giving us a Recoverable instance. This is necessary in order
    // for us to build our own Recoverable instances, which is necessary for us to support
    // multi-line input. Unfortunately REPLServer does not otherwise expose Recoverable.
    replServer.eval('var bogus =', null, null, function (err) {
      Recoverable = err.constructor;
      replServer.eval = replServer._domain.bind(config.eval || loopbackAwareEval);
    });

    _.extend(replServer.context, ctx.handles);
    replServer.on('exit', process.exit);

    if (ctx.handles.cb === true) {
      replServer.context.result = undefined;
      replServer.context.cb = function (err, res) {
        if (err) console.error('Error: '+err);
        replServer.context.result = res;
        if (!config.quiet) {
          console.log(res);
        }
      };
    }

    replServer.defineCommand('usage', {
      help: 'Detailed Loopback Console usage information',
      action: function () {
        this.outputStream.write(self.usage(ctx, true));
        this.displayPrompt();
      }
    });

    replServer.defineCommand('models', {
      help: 'Display available Loopback models',
      action: function () {
        this.outputStream.write(_.keys(ctx.models).join(', ')+'\n');
        this.displayPrompt();
      }
    });

    return replServer;
  },

  usage: function (ctx, details) {
    var usage =
      '============================================\n' +
      'Loopback Console\n\n' +
      'Primary handles available:\n';
    _.each(ctx.handleInfo, function (v, k) {
      usage += '  -'+k+': '+v+'\n';
    });

    var customHandles = _.filter(_.keys(ctx.handles), function (k) { return !ctx.handleInfo[k] && !ctx.models[k]; });
    if (!_.isEmpty(ctx.models) || !_.isEmpty(ctx.customHandles)) {
      usage += '\nOther handles available:\n';
    }
    if (!_.isEmpty(ctx.models)) {
      usage += '  - Models: ' + _.keys(ctx.models).join(', ') + '\n';
    }
    if (!_.isEmpty(customHandles)) {
      usage += '  - Custom: ' + customHandles.join(',') + '\n';
    }

    if (details) {
      usage +=
        '\nExamples:\n'+
        '  loopback > myUser = User.findOne({ where: { userame: \'heath\' })\n' +
        '  loopback > myUser.updateAttribute(\'fullName\', \'Heath Morrison\')\n' +
        '  loopback > myUser.widgets.add({ ... })\n\n';
    }
    usage += '============================================\n\n';

    if (details) {

    }

    return usage;
  }
};

// Much of this is borrowed from the default REPLServer eval
function loopbackAwareEval(code, context, file, cb) {
  var err, result, script;
  // first, create the Script object to check the syntax
  try {
    script = vm.createScript(code, {
      filename: file,
      displayErrors: false
    });
  } catch (e) {
    if (isRecoverableError(e)) {
      err = new Recoverable(e);
    } else {
      err = e;
    }
  }

  if (!err) {
    try {
      result = script.runInThisContext({ displayErrors: false });
      if (typeof Promise !== 'undefined' && result instanceof Promise) {
        result.then(function (r) {
          _.each(context, function (v, k) {
            if (context[k] === result) {
              context[k] = r;
            }
          });
          cb(null, r);
        }).catch(cb);
        return;
      }
    } catch (e) {
      err = e;
      if (err && process.domain) {
        process.domain.emit('error', err);
        process.domain.exit();
        return;
      }
    }
  }

  cb(err, result);
}

function isRecoverableError(e) {
  return e &&
  e.name === 'SyntaxError' &&
  /^(Unexpected end of input|Unexpected token)/.test(e.message);
}
<commit_msg>Relaxed promise detection<commit_after>var vm = require('vm');

var repl = require('repl');
var _ = require('lodash');

var Recoverable;

module.exports = {
  start: function (ctx) {
    var self = this;
    var config = _.clone(ctx.config);

    var replServer = repl.start(config);

    // Trick REPLServer into giving us a Recoverable instance. This is necessary in order
    // for us to build our own Recoverable instances, which is necessary for us to support
    // multi-line input. Unfortunately REPLServer does not otherwise expose Recoverable.
    // Note: Recoverable is exported in Node > v6.2, but this remains to retain support for older
    // versions.
    replServer.eval('var bogus =', null, null, function (err) {
      Recoverable = err.constructor;
      replServer.eval = replServer._domain.bind(config.eval || loopbackAwareEval);
    });

    _.extend(replServer.context, ctx.handles);
    replServer.on('exit', process.exit);

    if (ctx.handles.cb === true) {
      replServer.context.result = undefined;
      replServer.context.cb = function (err, res) {
        if (err) console.error('Error: '+err);
        replServer.context.result = res;
        if (!config.quiet) {
          console.log(res);
        }
      };
    }

    replServer.defineCommand('usage', {
      help: 'Detailed Loopback Console usage information',
      action: function () {
        this.outputStream.write(self.usage(ctx, true));
        this.displayPrompt();
      }
    });

    replServer.defineCommand('models', {
      help: 'Display available Loopback models',
      action: function () {
        this.outputStream.write(_.keys(ctx.models).join(', ')+'\n');
        this.displayPrompt();
      }
    });

    return replServer;
  },

  usage: function (ctx, details) {
    var usage =
      '============================================\n' +
      'Loopback Console\n\n' +
      'Primary handles available:\n';
    _.each(ctx.handleInfo, function (v, k) {
      usage += '  -'+k+': '+v+'\n';
    });

    var customHandles = _.filter(_.keys(ctx.handles), function (k) { return !ctx.handleInfo[k] && !ctx.models[k]; });
    if (!_.isEmpty(ctx.models) || !_.isEmpty(ctx.customHandles)) {
      usage += '\nOther handles available:\n';
    }
    if (!_.isEmpty(ctx.models)) {
      usage += '  - Models: ' + _.keys(ctx.models).join(', ') + '\n';
    }
    if (!_.isEmpty(customHandles)) {
      usage += '  - Custom: ' + customHandles.join(',') + '\n';
    }

    if (details) {
      usage +=
        '\nExamples:\n'+
        '  loopback > myUser = User.findOne({ where: { userame: \'heath\' })\n' +
        '  loopback > myUser.updateAttribute(\'fullName\', \'Heath Morrison\')\n' +
        '  loopback > myUser.widgets.add({ ... })\n\n';
    }
    usage += '============================================\n\n';

    if (details) {

    }

    return usage;
  }
};

// Much of this is borrowed from the default REPLServer eval
function loopbackAwareEval(code, context, file, cb) {
  var err, result, script;
  // first, create the Script object to check the syntax
  try {
    script = vm.createScript(code, {
      filename: file,
      displayErrors: false
    });
  } catch (e) {
    if (isRecoverableError(e)) {
      err = new Recoverable(e);
    } else {
      err = e;
    }
  }

  if (!err) {
    try {
      result = script.runInThisContext({ displayErrors: false });
      if (result.then) {
        result.then(function (r) {
          _.each(context, function (v, k) {
            if (context[k] === result) {
              context[k] = r;
            }
          });
          cb(null, r);
        }).catch(cb);
        return;
      }
    } catch (e) {
      err = e;
      if (err && process.domain) {
        process.domain.emit('error', err);
        process.domain.exit();
        return;
      }
    }
  }

  cb(err, result);
}

function isRecoverableError(e) {
  return e &&
  e.name === 'SyntaxError' &&
  /^(Unexpected end of input|Unexpected token)/.test(e.message);
}
<|endoftext|>