Sfoglia il codice sorgente

增加用户管理

FuJian Wen 8 anni fa
parent
commit
2aa4385aeb
100 ha cambiato i file con 8196 aggiunte e 218 eliminazioni
  1. 34 34
      src/server/endpoints/chats.endpoint.js
  2. 1 1
      src/server/endpoints/groups.endpoint.js
  3. 2 2
      src/server/endpoints/session.endpoint.js
  4. 2 8
      src/server/endpoints/users.endpoint.js
  5. 1 1
      src/server/include/wlyy.endpoints.js
  6. 38 38
      src/server/models/group.js
  7. 1 1
      src/server/models/messages/messages.js
  8. 2 2
      src/server/models/search.js
  9. 1 1
      src/server/models/server/management.js
  10. 1 1
      src/server/models/sessions/participants.js
  11. 1 1
      src/server/models/sessions/sessions.js
  12. 1 1
      src/server/models/sessions/topics.js
  13. 1 1
      src/server/models/stats.js
  14. 93 93
      src/server/models/user/doctor.js
  15. 18 17
      src/server/models/user/patient.js
  16. 14 16
      src/server/models/user/users.js
  17. 64 0
      src/server/node_modules/anymatch/index.js
  18. 58 0
      src/server/node_modules/arr-diff/index.js
  19. 27 0
      src/server/node_modules/arr-flatten/index.js
  20. 28 0
      src/server/node_modules/array-unique/index.js
  21. 8 0
      src/server/node_modules/arrify/index.js
  22. 38 0
      src/server/node_modules/async-each/index.js
  23. 399 0
      src/server/node_modules/braces/index.js
  24. 509 0
      src/server/node_modules/chokidar/index.js
  25. 361 0
      src/server/node_modules/chokidar/lib/fsevents-handler.js
  26. 476 0
      src/server/node_modules/chokidar/lib/nodefs-handler.js
  27. 1110 0
      src/server/node_modules/commander/index.js
  28. 0 0
      src/server/node_modules/core-util-is/lib/util.js
  29. 0 0
      src/server/node_modules/core-util-is/test.js
  30. 163 0
      src/server/node_modules/expand-brackets/index.js
  31. 43 0
      src/server/node_modules/expand-range/index.js
  32. 178 0
      src/server/node_modules/extglob/index.js
  33. 10 0
      src/server/node_modules/filename-regex/index.js
  34. 408 0
      src/server/node_modules/fill-range/index.js
  35. 16 0
      src/server/node_modules/for-in/index.js
  36. 19 0
      src/server/node_modules/for-own/index.js
  37. 51 0
      src/server/node_modules/glob-base/index.js
  38. 10 0
      src/server/node_modules/glob-base/node_modules/glob-parent/index.js
  39. 28 0
      src/server/node_modules/glob-base/node_modules/glob-parent/test.js
  40. 14 0
      src/server/node_modules/glob-base/node_modules/is-glob/index.js
  41. 9 0
      src/server/node_modules/glob-parent/index.js
  42. 14 0
      src/server/node_modules/glob-parent/node_modules/is-glob/index.js
  43. 22 0
      src/server/node_modules/glob-parent/test.js
  44. 21 0
      src/server/node_modules/graceful-fs/fs.js
  45. 262 0
      src/server/node_modules/graceful-fs/graceful-fs.js
  46. 118 0
      src/server/node_modules/graceful-fs/legacy-streams.js
  47. 330 0
      src/server/node_modules/graceful-fs/polyfills.js
  48. 12 0
      src/server/node_modules/graceful-readlink/index.js
  49. 0 0
      src/server/node_modules/inherits/inherits.js
  50. 0 0
      src/server/node_modules/inherits/inherits_browser.js
  51. 12 0
      src/server/node_modules/is-binary-path/index.js
  52. 21 0
      src/server/node_modules/is-buffer/index.js
  53. 25 0
      src/server/node_modules/is-buffer/test/basic.js
  54. 15 0
      src/server/node_modules/is-dotfile/index.js
  55. 27 0
      src/server/node_modules/is-equal-shallow/index.js
  56. 13 0
      src/server/node_modules/is-extendable/index.js
  57. 11 0
      src/server/node_modules/is-extglob/index.js
  58. 11 0
      src/server/node_modules/is-glob/index.js
  59. 19 0
      src/server/node_modules/is-number/index.js
  60. 10 0
      src/server/node_modules/is-posix-bracket/index.js
  61. 13 0
      src/server/node_modules/is-primitive/index.js
  62. 0 0
      src/server/node_modules/isarray/index.js
  63. 0 0
      src/server/node_modules/isarray/test.js
  64. 14 0
      src/server/node_modules/isobject/index.js
  65. 116 0
      src/server/node_modules/kind-of/index.js
  66. 46 0
      src/server/node_modules/log4js/examples/example-connect-logger.js
  67. 45 0
      src/server/node_modules/log4js/examples/example-socket.js
  68. 58 0
      src/server/node_modules/log4js/examples/example.js
  69. 27 0
      src/server/node_modules/log4js/examples/flush-on-exit.js
  70. 19 0
      src/server/node_modules/log4js/examples/fromreadme.js
  71. 27 0
      src/server/node_modules/log4js/examples/log-rolling.js
  72. 24 0
      src/server/node_modules/log4js/examples/loggly-appender.js
  73. 39 0
      src/server/node_modules/log4js/examples/logstashUDP.js
  74. 37 0
      src/server/node_modules/log4js/examples/memory-test.js
  75. 11 0
      src/server/node_modules/log4js/examples/missing-log-dir.js
  76. 21 0
      src/server/node_modules/log4js/examples/patternLayout-tokens.js
  77. 43 0
      src/server/node_modules/log4js/examples/smtp-appender.js
  78. 20 0
      src/server/node_modules/log4js/lib/appenders/categoryFilter.js
  79. 129 0
      src/server/node_modules/log4js/lib/appenders/clustered.js
  80. 21 0
      src/server/node_modules/log4js/lib/appenders/console.js
  81. 72 0
      src/server/node_modules/log4js/lib/appenders/dateFile.js
  82. 96 0
      src/server/node_modules/log4js/lib/appenders/file.js
  83. 187 0
      src/server/node_modules/log4js/lib/appenders/fileSync.js
  84. 142 0
      src/server/node_modules/log4js/lib/appenders/gelf.js
  85. 23 0
      src/server/node_modules/log4js/lib/appenders/logLevelFilter.js
  86. 44 0
      src/server/node_modules/log4js/lib/appenders/loggly.js
  87. 50 0
      src/server/node_modules/log4js/lib/appenders/logstashUDP.js
  88. 134 0
      src/server/node_modules/log4js/lib/appenders/multiprocess.js
  89. 82 0
      src/server/node_modules/log4js/lib/appenders/smtp.js
  90. 200 0
      src/server/node_modules/log4js/lib/connect-logger.js
  91. 66 0
      src/server/node_modules/log4js/lib/date_format.js
  92. 15 0
      src/server/node_modules/log4js/lib/debug.js
  93. 324 0
      src/server/node_modules/log4js/lib/layouts.js
  94. 68 0
      src/server/node_modules/log4js/lib/levels.js
  95. 426 0
      src/server/node_modules/log4js/lib/log4js.js
  96. 102 0
      src/server/node_modules/log4js/lib/logger.js
  97. 90 0
      src/server/node_modules/log4js/lib/streams/BaseRollingFileStream.js
  98. 95 0
      src/server/node_modules/log4js/lib/streams/DateRollingFileStream.js
  99. 89 0
      src/server/node_modules/log4js/lib/streams/RollingFileStream.js
  100. 0 0
      src/server/node_modules/log4js/lib/streams/index.js

+ 34 - 34
src/server/endpoints/chats.endpoint.js

@ -10,8 +10,8 @@ let router = express.Router();
let http = require('http');
let log = require('../util/log.js');
let objectUtil = require("../util/objectUtil.js");
let controllerUtil = require('../util/controllerUtil');
let ObjectUtil = require("../util/object.util.js");
let ControllerUtil = require('../util/controller.util');
let Patient = require("../models/user/patient");
let Doctor = require('../models/user/doctor');
@ -48,19 +48,19 @@ const DEFAULT_PAGE_SIZE = require('../include/commons').DEFAULT_PAGE_SIZE;
router.post(APIv1.Chats.SM, function (req, res) {
    // 检查消息体及消息格式是否正确
    let message = req.body;
    if (!objectUtil.isJsonObject(message)) {
    if (!ObjectUtil.isJsonObject(message)) {
        throw {httpStatus: 406, message: 'Problems parsing JSON.'}
    }
    // 字段判断
    let testing = objectUtil.fieldsCheck(message, "to", "title", "summary", "contentType", "content");
    let testing = ObjectUtil.fieldsCheck(message, "to", "title", "summary", "contentType", "content");
    if (!testing.pass) {
        throw {httpStatus: 406, message: testing.message}
    }
    // 消息处理
    let doctor = new Doctor();
    controllerUtil.regModelEventHandler(doctor, res);
    ControllerUtil.regModelEventHandler(doctor, res);
    doctor.sendSystemMessage(message);
});
@ -87,12 +87,12 @@ router.post(APIv1.Chats.SM, function (req, res) {
router.post(APIv1.Chats.PM, function (req, res) {
    // 检查消息体及消息格式是否正确
    let message = req.body;
    if (!objectUtil.isJsonObject(message)) {
    if (!ObjectUtil.isJsonObject(message)) {
        throw {httpStatus: 406, message: 'Problems parsing JSON.'}
    }
    // 字段判断
    let testing = objectUtil.fieldsCheck(message, "from", "to", "contentType", "content");
    let testing = ObjectUtil.fieldsCheck(message, "from", "to", "contentType", "content");
    if (!testing.pass) {
        throw {httpStatus: 406, message: testing.message};
    }
@ -101,12 +101,12 @@ router.post(APIv1.Chats.PM, function (req, res) {
    Patient.isPatientCode(message.to,
        function () {
            let patient = new Patient();
            controllerUtil.regModelEventHandler(patient, res);
            ControllerUtil.regModelEventHandler(patient, res);
            patient.sendMessage(message);
        }, function () {
            let doctor = new Doctor();
            controllerUtil.regModelEventHandler(doctor, res);
            ControllerUtil.regModelEventHandler(doctor, res);
            doctor.sendMessage(message);
        });
@ -134,19 +134,19 @@ router.post(APIv1.Chats.GM, function (req, res) {
    // 检查消息体及消息格式是否正确
    let message = req.body;
    if (!objectUtil.isJsonObject(message)) {
    if (!ObjectUtil.isJsonObject(message)) {
        throw {httpStatus: 406, message: 'Problems parsing JSON.'};
    }
    // 字段判断
    let testing = objectUtil.fieldsCheck(message, 'from', 'at', 'group', 'groupType', 'contentType', 'content');
    let testing = ObjectUtil.fieldsCheck(message, 'from', 'at', 'group', 'groupType', 'contentType', 'content');
    if (!testing.pass) {
        throw {httpStatus: 406, message: testing.message}
    }
    // 消息处理
    let group = new Group();
    controllerUtil.regModelEventHandler(group, res);
    ControllerUtil.regModelEventHandler(group, res);
    group.sendMessage(message);
});
@ -168,7 +168,7 @@ router.get(APIv1.Chats.List, function (req, res) {
    }
    let doctor = new Doctor();
    controllerUtil.regModelEventHandler(doctor, res);
    ControllerUtil.regModelEventHandler(doctor, res);
    doctor.getChatList(userId);
});
@ -186,7 +186,7 @@ router.get(APIv1.Chats.ListWithPatient, function (req, res) {
    }
    let doctor = new Doctor();
    controllerUtil.regModelEventHandler(doctor, res);
    ControllerUtil.regModelEventHandler(doctor, res);
    doctor.getChatsListWithPatient(userId);
});
@ -204,7 +204,7 @@ router.get(APIv1.Chats.ListWithDoctor, function (req, res) {
    }
    let doctor = new Doctor();
    controllerUtil.regModelEventHandler(doctor, res);
    ControllerUtil.regModelEventHandler(doctor, res);
    doctor.getChatListWithDoctor(userId);
});
@ -217,7 +217,7 @@ router.get(APIv1.Chats.MsgAmount, function (req, res) {
    }
    let doctor = new Doctor();
    controllerUtil.regModelEventHandler(doctor, res);
    ControllerUtil.regModelEventHandler(doctor, res);
    doctor.getChatListMsgAmount(userId);
});
@ -245,7 +245,7 @@ router.get(APIv1.Chats.Recent, function (req, res) {
    }
    let doctor = new Doctor();
    controllerUtil.regModelEventHandler(doctor, res);
    ControllerUtil.regModelEventHandler(doctor, res);
    doctor.getRecentChatList(userId, days);
});
@ -283,7 +283,7 @@ router.get(APIv1.Chats.PM, function (req, res) {
    }
    let doctor = new Doctor();
    controllerUtil.regModelEventHandler(doctor, res);
    ControllerUtil.regModelEventHandler(doctor, res);
    doctor.getPrivateMessages(userId, peerId, contentType, msgStartId, msgEndId, count, closedInterval);
});
@ -307,7 +307,7 @@ router.get(APIv1.Chats.PMUnread, function (req, res) {
    }
    let doctor = new Doctor();
    controllerUtil.regModelEventHandler(doctor, res);
    ControllerUtil.regModelEventHandler(doctor, res);
    doctor.getUnreadPrivateMessages(userId, peerId);
});
@ -341,7 +341,7 @@ router.get(APIv1.Chats.GM, function (req, res) {
    if (req.query.message_start_id && req.query.message_end_id) count = 100000;
    let group = new Group();
    controllerUtil.regModelEventHandler(group, res);
    ControllerUtil.regModelEventHandler(group, res);
    group.getMessages(groupId, memberId, contentType, msgStartId, msgEndId, count);
});
@ -365,7 +365,7 @@ router.get(APIv1.Chats.GMUnread, function (req, res) {
    }
    let group = new Group();
    controllerUtil.regModelEventHandler(group, res);
    ControllerUtil.regModelEventHandler(group, res);
    group.getUnreadMessages(groupId, memberId);
});
@ -390,7 +390,7 @@ router.get(APIv1.Chats.GMUnreadCount, function (req, res) {
    }
    let group = new Group();
    controllerUtil.regModelEventHandler(group, res);
    ControllerUtil.regModelEventHandler(group, res);
    group.getUnreadMessageCount(memberId);
});
@ -412,7 +412,7 @@ router.get(APIv1.Chats.GMStats, function (req, res) {
    }
    let group = new Group();
    controllerUtil.regModelEventHandler(group, res);
    ControllerUtil.regModelEventHandler(group, res);
    group.getChatSummary(groupId, memberId);
});
@ -434,7 +434,7 @@ router.get(APIv1.Chats.PMStats, function (req, res) {
    }
    let doctor = new Doctor();
    controllerUtil.regModelEventHandler(doctor, res);
    ControllerUtil.regModelEventHandler(doctor, res);
    doctor.getChatSummary(userId, peerId);
});
@ -451,7 +451,7 @@ router.get(APIv1.Chats.PMUnreadCount, function (req, res) {
    let userId = req.query.user_id;
    let doctor = new Doctor();
    controllerUtil.regModelEventHandler(doctor, res);
    ControllerUtil.regModelEventHandler(doctor, res);
    doctor.getUnreadPrivateMessages(userId);
});
@ -472,7 +472,7 @@ router.get(APIv1.Chats.UnreadMsgCount, function (req, res) {
    }
    let doctor = new Doctor();
    controllerUtil.regModelEventHandler(doctor, res);
    ControllerUtil.regModelEventHandler(doctor, res);
    doctor.getAllUnreadMessageCount(userId);
});
@ -496,7 +496,7 @@ router.get(APIv1.Chats.SearchAboutPatient, function (req, res) {
    if (!userRole) throw {httpStatus: 406, message: "Missing fields: user_role."};
    if (!keyword) throw {httpStatus: 406, message: "Missing fields: keyword."};
    let search = new Search();
    controllerUtil.regModelEventHandler(search, res);
    ControllerUtil.regModelEventHandler(search, res);
    search.searchAboutPatient(userId, userRole, keyword);
});
/**
@ -514,7 +514,7 @@ router.get(APIv1.Chats.SearchAboutPatientList, function (req, res) {
    if (!keyword) throw {httpStatus: 406, message: "Missing fields: keyword."};
    if (!type) throw {httpStatus: 406, message: "Missing fields: type."};
    let search = new Search();
    controllerUtil.regModelEventHandler(search, res);
    ControllerUtil.regModelEventHandler(search, res);
    search.searchAboutPatientList(userId, keyword,groupId,type);
});
@ -532,7 +532,7 @@ router.get(APIv1.Chats.SearchAbountPatientMore, function (req, res) {
    if (!type) throw {httpStatus: 406, message: "Missing fields: type."};
    if (!userRole) throw {httpStatus: 406, message: "Missing fields: userRole."};
    let search = new Search();
    controllerUtil.regModelEventHandler(search, res);
    ControllerUtil.regModelEventHandler(search, res);
    search.searchAboutPatientAll(userId,userRole, keyword,type);
});
@ -554,7 +554,7 @@ router.get(APIv1.Chats.SearchAboutDoctor, function (req, res) {
    if (!keyword) throw {httpStatus: 406, message: "Missing fields: keyword."};
    let search = new Search();
    controllerUtil.regModelEventHandler(search, res);
    ControllerUtil.regModelEventHandler(search, res);
    search.searchAboutDoctor(userId, keyword);
});
@ -573,7 +573,7 @@ router.get(APIv1.Chats.SearchAboutDoctorList, function (req, res) {
    if (!keyword) throw {httpStatus: 406, message: "Missing fields: keyword."};
    if (!type) throw {httpStatus: 406, message: "Missing fields: type."};
    let search = new Search();
    controllerUtil.regModelEventHandler(search, res);
    ControllerUtil.regModelEventHandler(search, res);
    search.searchDoctorMore(userId, keyword,type);
});
@ -591,7 +591,7 @@ router.get(APIv1.Chats.SearchAbountDoctorContentDetail, function (req, res) {
    if (!type) throw {httpStatus: 406, message: "Missing fields: type."};
    if (!groupcode) throw {httpStatus: 406, message: "Missing fields: groupcode."};
    let search = new Search();
    controllerUtil.regModelEventHandler(search, res);
    ControllerUtil.regModelEventHandler(search, res);
    search.searchDoctorContentDetail(userId, keyword,groupcode,type);
});
@ -609,7 +609,7 @@ router.get(APIv1.Chats.Message, function (req, res) {
    let messageType = req.query.type;
    let doctor = new Doctor();
    controllerUtil.regModelEventHandler(doctor, res);
    ControllerUtil.regModelEventHandler(doctor, res);
    doctor.getMessage(messageId, messageType);
});
@ -632,7 +632,7 @@ router.get(APIv1.Chats.PMFinished, function (req, res) {
    }
    let doctor = new Doctor();
    controllerUtil.regModelEventHandler(doctor, res);
    ControllerUtil.regModelEventHandler(doctor, res);
    doctor.isConsultFinished(doctorId, patientId);
});

+ 1 - 1
src/server/endpoints/groups.endpoint.js

@ -9,7 +9,7 @@ let router = express.Router();
const APIv1 = require('../include/endpoints').APIv1;
const MODEL_EVENTS = require('../include/commons').MODEL_EVENTS;
//let groupRepo = require('../repository/group.repo.js');
//let GroupRepo = require('../repository/group.repo.js');
let Group = require('../models/group');
/**

+ 2 - 2
src/server/endpoints/session.endpoint.js

@ -13,9 +13,9 @@ let http = require('http');
let configFile = require('../include/commons').CONFIG_FILE;
let config = require('../resources/config/' + configFile);
let log = require("../util/log.js");
let objectUtil = require('../util/objectUtil');
let objectUtil = require('../util/object.util');
let UserStatus = require('../models/user.status');
let Users = require('../models/user/users');
const APIv1 = require('../include/endpoints').APIv1;
const MODEL_EVENTS = require('../include/commons').MODEL_EVENTS;

+ 2 - 8
src/server/endpoints/users.endpoint.js

@ -10,7 +10,7 @@ let http = require('http');
let configFile = require('../include/commons').CONFIG_FILE;
let config = require('../resources/config/' + configFile);
let log = require("../util/log.js");
let objectUtil = require('../util/objectUtil');
let objectUtil = require('../util/object.util');
let Users = require('../models/user/users');
@ -51,15 +51,9 @@ router.get(APIv1.Users.Login, function (req, res) {
    }
    let users = new Users();
    users.on(MODEL_EVENTS.OK, function (message) {
        res.status(200).send(message);
    });
    users.login(userId, function (err, result) {
    users.on(MODEL_EVENTS.Error, function (message) {
        res.status(500).send(message);
    });
    users.login(userId, token, clientId, platform);
});
/**

+ 1 - 1
src/server/include/wlyy.endpoints.js

@ -6,7 +6,7 @@
 */
"use strict";
exports.WLYY_ENPOINTS = {
exports.WLYY_ENDPOINTS = {
    Doctor: {
        MessageCount: {
            Path: '/wlyy/doctor/message/messages',

+ 38 - 38
src/server/models/group.js

@ -5,18 +5,18 @@
let BaseModel = require('./base.model');
let log = require("../util/log.js");
let modelUtil = require('../util/modelUtil');
let ModelUtil = require('../util/model.util');
let getui = require('getui');
let Patient = new require("../models/user/patient");
let Doctor = new require('../models/user/doctor');
let groupRepo = require('../repository/mysql/group.repo');
let gmRepo = require('../repository/mysql/group.msg.repo');
let statsRepo = require("../repository/mysql/stats.msg.repo");
let objectUtil = require("../util/objectUtil.js");
let GroupRepo = require('../repository/mysql/group.repo');
let GroupMsgRepo = require('../repository/mysql/group.msg.repo');
let StatsRepo = require("../repository/mysql/stats.msg.repo");
let ObjectUtil = require("../util/object.util.js");
const GROUP_TYPE = require('../include/commons').GROUP_TYPE;
const GROUP_TYPES = require('../include/commons').GROUP_TYPE;
const MAX_INT = require('../include/commons').MAX_INT;
class GroupMessage extends BaseModel {
@ -31,36 +31,36 @@ class GroupMessage extends BaseModel {
     */
    sendMessage(message) {
        let self = this;
        groupRepo.isGroupMember(message.group, message.groupType, message.from, function (err, result) {
        GroupRepo.isGroupMember(message.group, message.groupType, message.from, function (err, result) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, 'Check group member failed', err);
                ModelUtil.emitDbError(self.eventEmitter, 'Check group member failed', err);
                return;
            }
            if (result.length == 0) {
                modelUtil.emitDataNotFound(self.eventEmitter, 'Member with id "' + message.from + '" is not in group "' + message.group + '"');
                ModelUtil.emitDataNotFound(self.eventEmitter, 'Member with id "' + message.from + '" is not in group "' + message.group + '"');
                return;
            }
            // 保存群组消息
            gmRepo.save(message.from, message.group, message.at, message.contentType, message.content, function (err, insertedRow) {
            GroupMsgRepo.save(message.from, message.group, message.at, message.contentType, message.content, function (err, insertedRow) {
                if (err) {
                    modelUtil.emitDbError(self.eventEmitter, 'Save group message failed', err);
                    ModelUtil.emitDbError(self.eventEmitter, 'Save group message failed', err);
                    return;
                }
                gmRepo.findOneMessage(insertedRow.insertId, function (err, groupMsg) {
                GroupMsgRepo.findOneMessage(insertedRow.insertId, function (err, groupMsg) {
                    if (err) {
                        modelUtil.emitDbError(self.eventEmitter, 'Save group message success, but return this message failed', err);
                        ModelUtil.emitDbError(self.eventEmitter, 'Save group message success, but return this message failed', err);
                        return;
                    }
                    // 关闭网络连接后执行后续操作
                    let feedback = Doctor.fillMessages(groupMsg);
                    modelUtil.emitData(self.eventEmitter, feedback);
                    ModelUtil.emitData(self.eventEmitter, feedback);
                    // 推送通知消息给群组成员
                    groupRepo.getMembers(message.group, message.groupType, function (err, members) {
                    GroupRepo.getMembers(message.group, message.groupType, function (err, members) {
                        if (err) {
                            log.error('Get group members failed: ', err);
                            return;
@ -68,7 +68,7 @@ class GroupMessage extends BaseModel {
                        if (members.length == 0) {
                            log.warn('No members in group ', message.group,
                                message.groupType === GROUP_TYPE.AdminTeam ? " of admin team." : "of discussion group.");
                                message.groupType === GROUP_TYPES.AdminTeam ? " of admin team." : "of discussion group.");
                            return;
                        }
@ -104,7 +104,7 @@ class GroupMessage extends BaseModel {
                                        // 更新用户组内消息摘要
                                        let at = message.at == userId ? 1 : 0;
                                        statsRepo.updateGroupChatSummary(userId,
                                        StatsRepo.updateGroupChatSummary(userId,
                                            message.group,
                                            message.from,
                                            at,
@ -121,7 +121,7 @@ class GroupMessage extends BaseModel {
                });
                // 更新组内统计信息
                statsRepo.updateGroupChatSummary(message.from, message.group, message.from, 0, message.contentType, message.content, false, function (err, result) {
                StatsRepo.updateGroupChatSummary(message.from, message.group, message.from, 0, message.contentType, message.content, false, function (err, result) {
                    if (err) log.error(err);
                });
            });
@ -133,18 +133,18 @@ class GroupMessage extends BaseModel {
     */
    getMessages(groupId, memberId, contentType, msgStartId, msgEndId, count) {
        let self = this;
        gmRepo.findAllMessages(groupId, !contentType ? "1,2,3,5,6" : contentType, msgStartId, msgEndId, count, function (err, rows) {
        GroupMsgRepo.findAllMessages(groupId, !contentType ? "1,2,3,5,6" : contentType, msgStartId, msgEndId, count, function (err, rows) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, 'Get group message failed', err);
                ModelUtil.emitDbError(self.eventEmitter, 'Get group message failed', err);
                return;
            }
            // 先给客户端返回数据
            let messages = Doctor.fillMessages(rows);
            modelUtil.emitData(self.eventEmitter, messages);
            ModelUtil.emitData(self.eventEmitter, messages);
            // 清空统计信息
            statsRepo.clearGroupChatSummary(memberId, groupId, function (err, result) {
            StatsRepo.clearGroupChatSummary(memberId, groupId, function (err, result) {
                if (err) console.log(err);
            });
        });
@ -156,27 +156,27 @@ class GroupMessage extends BaseModel {
     */
    getUnreadMessages(groupId, memberId) {
        let self = this;
        statsRepo.getGroupChatSummary(memberId, groupId, function (err, summary) {
        StatsRepo.getGroupChatSummary(memberId, groupId, function (err, summary) {
                if (err) {
                    modelUtil.emitDbError(self.eventEmitter, "Get unread group messages failed", err);
                    ModelUtil.emitDbError(self.eventEmitter, "Get unread group messages failed", err);
                    return;
                }
                let messages = {startId: 0, count: 0, records: []};
                if (summary.length == 0 || summary[0].new_msg_count === 0) {
                    modelUtil.emitData(messages);
                    ModelUtil.emitData(messages);
                    return;
                }
                messages.count = summary[0].new_msg_count;
                gmRepo.findUnread(groupId, MAX_INT, messages.count, function (err, rows) {
                GroupMsgRepo.findUnread(groupId, MAX_INT, messages.count, function (err, rows) {
                    if (err) {
                        modelUtil.emitDbError(self.eventEmitter, "Get unread group messages failed", err);
                        ModelUtil.emitDbError(self.eventEmitter, "Get unread group messages failed", err);
                        return;
                    }
                    let feedback = Doctor.fillMessages(rows);
                    modelUtil.emitData(feedback);
                    ModelUtil.emitData(feedback);
                });
            }
        )
@ -190,9 +190,9 @@ class GroupMessage extends BaseModel {
     */
    getUnreadMessageCount(memberId) {
        let self = this;
        statsRepo.getGroupChatAllUnReadCount(memberId, function (err, result) {
        StatsRepo.getGroupChatAllUnReadCount(memberId, function (err, result) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, 'Get all unread messages failed', err);
                ModelUtil.emitDbError(self.eventEmitter, 'Get all unread messages failed', err);
                return;
            }
@ -208,7 +208,7 @@ class GroupMessage extends BaseModel {
                }
            }
            modelUtil.emitData(self.eventEmitter, data);
            ModelUtil.emitData(self.eventEmitter, data);
        });
    }
@ -220,9 +220,9 @@ class GroupMessage extends BaseModel {
     */
    getChatSummary(groupId, memberId) {
        let self = this;
        statsRepo.getGroupChatSummary(memberId, groupId, function (err, result) {
        StatsRepo.getGroupChatSummary(memberId, groupId, function (err, result) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, 'Get group stats failed', err);
                ModelUtil.emitDbError(self.eventEmitter, 'Get group stats failed', err);
                return;
            }
@ -245,10 +245,10 @@ class GroupMessage extends BaseModel {
                data.lastContentType = row.last_content_type;
                data.lastContent = row.lastContent;
                data.newMessageCount = row.new_msg_count;
                data.timestamp = objectUtil.timestampToLong(row.timestamp)
                data.timestamp = ObjectUtil.timestampToLong(row.timestamp)
            }
            modelUtil.emitData(self.eventEmitter, data);
            ModelUtil.emitData(self.eventEmitter, data);
        });
    }
@ -260,9 +260,9 @@ class GroupMessage extends BaseModel {
    getMemberAvatars(groups) {
        let self = this;
        let avatars = [];
        groupRepo.getMembersAvatar(groups, function (err, members) {
        GroupRepo.getMembersAvatar(groups, function (err, members) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, "Get group member's avatar list failed", err);
                ModelUtil.emitDbError(self.eventEmitter, "Get group member's avatar list failed", err);
                return;
            }
@ -288,7 +288,7 @@ class GroupMessage extends BaseModel {
                });
            }
            modelUtil.emitData(self.eventEmitter, avatars);
            ModelUtil.emitData(self.eventEmitter, avatars);
        });
    }
}

+ 1 - 1
src/server/models/messages/messages.js

@ -6,7 +6,7 @@
let RedisClient = require('../../repository/redis/redis.client.js');
let redisClient = RedisClient.redisClient();
let BaseModel = require('./../base.model.js');
let modelUtil = require('../../util/modelUtil');
let modelUtil = require('../../util/model.util');
var imDb = require('../../repository/mysql/db/im.db');
let log = require('../../util/log.js');
const RedisKey = require('../../include/commons').REDIS_KEYS;

+ 2 - 2
src/server/models/search.js

@ -12,8 +12,8 @@
let BaseModel = require('./base.model');
let searchRepo = require('../repository/mysql/search.repo');
let modelUtil = require("../util/modelUtil");
let objectUtil = require('../util/objectUtil');
let modelUtil = require("../util/model.util");
let objectUtil = require('../util/object.util');
class Search extends BaseModel {
    constructor() {

+ 1 - 1
src/server/models/server/management.js

@ -13,7 +13,7 @@ let wlyyRepo = require('../../repository/mysql/db/im.db');
let imRepo = require('../../repository/mysql/db/im.db');
let BaseModel = require('../base.model');
let modeUtil = require("../../util/modelUtil");
let modeUtil = require("../../util/model.util");
class Management extends BaseModel {
    constructor() {

+ 1 - 1
src/server/models/sessions/participants.js

@ -6,7 +6,7 @@
let RedisClient = require('../../repository/redis/redis.client.js');
let redisClient = RedisClient.redisClient();
let BaseModel = require('./../base.model.js');
let modelUtil = require('../../util/modelUtil');
let modelUtil = require('../../util/model.util');
const RedisKey = require('../../include/commons').RedisKey;

+ 1 - 1
src/server/models/sessions/sessions.js

@ -7,7 +7,7 @@ let RedisClient = require('../../repository/redis/redis.client.js');
let redisClient = RedisClient.redisClient();
let redis = redisClient.connection;
let BaseModel = require('./../base.model.js');
let modelUtil = require('../../util/modelUtil');
let modelUtil = require('../../util/model.util');
let Messages = require('../messages/messages');
const RedisKeys = require('../../include/commons').REDIS_KEYS;
let mongoose = require('mongoose');

+ 1 - 1
src/server/models/sessions/topics.js

@ -6,7 +6,7 @@
let RedisClient = require('../../repository/redis/redis.client.js');
let redisClient = RedisClient.redisClient();
let BaseModel = require('./../base.model.js');
let modelUtil = require('../../util/modelUtil');
let modelUtil = require('../../util/model.util');
const RedisKey = require('../../include/commons').RedisKey;

+ 1 - 1
src/server/models/stats.js

@ -6,7 +6,7 @@
let BaseModel = require('./base.model');
let statsRepo = require("../repository/mysql/stats.msg.repo.js");
let log = require("../util/log.js");
let modelUtil = require('../util/modelUtil');
let modelUtil = require('../util/model.util');
class StatsMessage extends BaseModel{
    constructor(){

+ 93 - 93
src/server/models/user/doctor.js

@ -8,14 +8,14 @@ let getui = require('getui');
let RedisModel = require('./../redis.model');
let Schedule = require("./../schedule/schedule.js");
let doctorRepo = require('../../repository/mysql/doctor.repo.js');
let gmRepo = require('../../repository/mysql/group.msg.repo');
let pmRepo = require('../../repository/mysql/private.msg.repo');
let nmRepo = require("../../repository/mysql/notify.msg.repo");
let smRepo = require("../../repository/mysql/system.msg.repo.js");
let statsRepo = require("../../repository/mysql/stats.msg.repo");
let objectUtil = require("../../util/object.util.js");
let modelUtil = require('../../util/model.util');
let DoctorRepo = require('../../repository/mysql/doctor.repo.js');
let GroupMsgRepo = require('../../repository/mysql/group.msg.repo');
let PrivateMsgRepo = require('../../repository/mysql/private.msg.repo');
let NotifyMsgRepo = require("../../repository/mysql/notify.msg.repo");
let SystemMsgRepo = require("../../repository/mysql/system.msg.repo.js");
let StatsRepo = require("../../repository/mysql/stats.msg.repo");
let ObjectUtil = require("../../util/object.util.js");
let ModelUtil = require('../../util/model.util');
const CONTENT_TYPES = require('../../include/commons').CONTENT_TYPE;
const PLATFORMS = require('../../include/commons').PLATFORM;
@ -41,32 +41,32 @@ class Doctor extends RedisModel {
        let self = this;
        let tempContent = message.contentType === CONTENT_TYPES.Article ? JSON.stringify(message.content) : message.content;
        pmRepo.save(message.to, message.from, message.contentType, tempContent, function (err, result) {
        PrivateMsgRepo.save(message.to, message.from, message.contentType, tempContent, function (err, result) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, 'Save private message failed', err);
                ModelUtil.emitDbError(self.eventEmitter, 'Save private message failed', err);
                return;
            }
            // 返回新插入的消息数据,并推送
            pmRepo.findOneMessage(result.insertId, function (err, msg) {
            PrivateMsgRepo.findOneMessage(result.insertId, function (err, msg) {
                if (err) {
                    modelUtil.emitDbError(self.eventEmitter, 'Save private message success, but return last message failed', err);
                    ModelUtil.emitDbError(self.eventEmitter, 'Save private message success, but return last message failed', err);
                    return;
                }
                // 先结束网络连接,再推送给客户端
                modelUtil.emitData(self.eventEmitter, Doctor.fillMessages(msg));
                ModelUtil.emitData(self.eventEmitter, Doctor.fillMessages(msg));
                Doctor.pushMessage(message, 'p2p_msg');
            });
            // 更新自身的聊天统计信息
            statsRepo.updatePrivateChatSummary(message.from, message.to, message.from, message.contentType, message.content, function (err, result) {
            StatsRepo.updatePrivateChatSummary(message.from, message.to, message.from, message.contentType, message.content, function (err, result) {
                if (err) log.error(err);
            });
            // 更新对端的聊天统计信息
            statsRepo.updatePrivateChatSummary(message.to, message.from, message.from, message.contentType, message.content, function (err, result) {
            StatsRepo.updatePrivateChatSummary(message.to, message.from, message.from, message.contentType, message.content, function (err, result) {
                if (err) log.error(err);
            });
        });
@ -79,19 +79,19 @@ class Doctor extends RedisModel {
     */
    sendSystemMessage(message) {
        let self = this;
        smRepo.save(message.to,
        SystemMsgRepo.save(message.to,
            message.contentType,
            message.title,
            message.summary,
            message.content,
            function (err, result) {
                if (err) {
                    modelUtil.emitDbError(self.eventEmitter, "Save system message failed", err);
                    ModelUtil.emitDbError(self.eventEmitter, "Save system message failed", err);
                    return;
                }
                // 先结束网络连接,再推送给客户端
                modelUtil.emitData(self.eventEmitter, {});
                ModelUtil.emitData(self.eventEmitter, {});
                Doctor.pushMessage(message, 'system_msg');
            });
@ -104,7 +104,7 @@ class Doctor extends RedisModel {
     * @param channel
     */
    static pushMessage(message, channel){
        doctorRepo.getUserStatus(message.to, function (err, result) {
        DoctorRepo.getUserStatus(message.to, function (err, result) {
            if (err) {
                log.error('Lookup notify message receiver failed: ' + message.to);
                return;
@ -136,7 +136,7 @@ class Doctor extends RedisModel {
            }
            // 保存通知消息到数据库中,并根据用户在线状态推送此消息
            nmRepo.save(message.to, message.contentType, title, content, JSON.stringify(notifyMessage), isOnline, delay, function (err, result) {
            NotifyMsgRepo.save(message.to, message.contentType, title, content, JSON.stringify(notifyMessage), isOnline, delay, function (err, result) {
                if (err) {
                    log.error('Save notify message failed, ', err);
                    return;
@ -194,9 +194,9 @@ class Doctor extends RedisModel {
     */
    getRecentChatList(userId, days) {
        let self = this;
        statsRepo.getRecentChats(userId, days, function (err, rows) {
        StatsRepo.getRecentChats(userId, days, function (err, rows) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, 'Get recent chat objects failed', err);
                ModelUtil.emitDbError(self.eventEmitter, 'Get recent chat objects failed', err);
                return;
            }
@ -229,7 +229,7 @@ class Doctor extends RedisModel {
                }
            }
            modelUtil.emitData(self.eventEmitter, data);
            ModelUtil.emitData(self.eventEmitter, data);
        });
    }
@ -242,9 +242,9 @@ class Doctor extends RedisModel {
        let self = this;
        // 与患者的私信
        pmRepo.findAllP2PWithPatient(userId, function (err, patients) {
        PrivateMsgRepo.findAllP2PWithPatient(userId, function (err, patients) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, 'Get chat list with patient failed', err);
                ModelUtil.emitDbError(self.eventEmitter, 'Get chat list with patient failed', err);
                return;
            }
@ -260,14 +260,14 @@ class Doctor extends RedisModel {
                    newMessageCount: patient.new_msg_count,
                    lastContentType: patient.last_content_type,
                    lastContent: patient.last_content,
                    timestamp: objectUtil.timestampToLong(patient.timestamp)
                    timestamp: ObjectUtil.timestampToLong(patient.timestamp)
                });
            }
            // 含有患者的群
            gmRepo.findAllGroupsWithPatient(userId, function (err, groups) {
            GroupMsgRepo.findAllGroupsWithPatient(userId, function (err, groups) {
                if (err) {
                    modelUtil.emitDbError(self.eventEmitter, 'Get group list with patient failed', err);
                    ModelUtil.emitDbError(self.eventEmitter, 'Get group list with patient failed', err);
                    return;
                }
@ -284,14 +284,14 @@ class Doctor extends RedisModel {
                        newMessageCount: group.new_msg_count,
                        lastContentType: group.last_content_type,
                        lastContent: group.last_content,
                        timestamp: objectUtil.timestampToLong(group.timestamp)
                        timestamp: ObjectUtil.timestampToLong(group.timestamp)
                    });
                }
                // 医生间的私聊
                pmRepo.findAllP2PWithDoctor(userId, function (err, doctors) {
                PrivateMsgRepo.findAllP2PWithDoctor(userId, function (err, doctors) {
                    if (err) {
                        modelUtil.emitDbError(self.eventEmitter, 'Get chat list with doctor failed', err);
                        ModelUtil.emitDbError(self.eventEmitter, 'Get chat list with doctor failed', err);
                        return;
                    }
@ -305,14 +305,14 @@ class Doctor extends RedisModel {
                            newMessageCount: doctor.new_msg_count,
                            lastContentType: doctor.last_content_type,
                            lastContent: doctor.last_content,
                            timestamp: objectUtil.timestampToLong(doctor.timestamp)
                            timestamp: ObjectUtil.timestampToLong(doctor.timestamp)
                        });
                    }
                    // 获取医生间的组
                    gmRepo.findAllGroupsWithDoctor(userId, function (err, groups) {
                    GroupMsgRepo.findAllGroupsWithDoctor(userId, function (err, groups) {
                        if (err) {
                            modelUtil.emitDbError(self.eventEmitter, 'Get group list with doctor failed', err);
                            ModelUtil.emitDbError(self.eventEmitter, 'Get group list with doctor failed', err);
                            return;
                        }
@ -325,11 +325,11 @@ class Doctor extends RedisModel {
                                newMessageCount: group.new_msg_count,
                                lastContentType: group.last_content_type,
                                lastContent: group.last_content,
                                timestamp: objectUtil.timestampToLong(group.timestamp)
                                timestamp: ObjectUtil.timestampToLong(group.timestamp)
                            });
                        }
                        modelUtil.emitData(self.eventEmitter, chats);
                        ModelUtil.emitData(self.eventEmitter, chats);
                    });
                });
            })
@ -342,9 +342,9 @@ class Doctor extends RedisModel {
    getChatsListWithPatient(userId) {
        let self = this;
        pmRepo.findAllP2PWithPatient(userId, function (err, patients) {
        PrivateMsgRepo.findAllP2PWithPatient(userId, function (err, patients) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, 'Get chat list with patient failed', err);
                ModelUtil.emitDbError(self.eventEmitter, 'Get chat list with patient failed', err);
                return;
            }
@ -360,13 +360,13 @@ class Doctor extends RedisModel {
                    newMessageCount: patient.new_msg_count,
                    lastContentType: patient.last_content_type,
                    lastContent: patient.last_content,
                    timestamp: objectUtil.timestampToLong(patient.timestamp)
                    timestamp: ObjectUtil.timestampToLong(patient.timestamp)
                });
            }
            gmRepo.findAllGroupsWithPatient(userId, function (err, groups) {
            GroupMsgRepo.findAllGroupsWithPatient(userId, function (err, groups) {
                if (err) {
                    modelUtil.emitDbError(self.eventEmitter, 'Get group list with patient failed', err);
                    ModelUtil.emitDbError(self.eventEmitter, 'Get group list with patient failed', err);
                    return;
                }
@ -383,11 +383,11 @@ class Doctor extends RedisModel {
                        newMessageCount: group.new_msg_count,
                        lastContentType: group.last_content_type,
                        lastContent: group.last_content,
                        timestamp: objectUtil.timestampToLong(group.timestamp)
                        timestamp: ObjectUtil.timestampToLong(group.timestamp)
                    });
                }
                modelUtil.emitData(self.eventEmitter, chats);
                ModelUtil.emitData(self.eventEmitter, chats);
            })
        });
    }
@ -401,9 +401,9 @@ class Doctor extends RedisModel {
        let self = this;
        // 先获取医生间的私聊
        pmRepo.findAllP2PWithDoctor(userId, function (err, doctors) {
        PrivateMsgRepo.findAllP2PWithDoctor(userId, function (err, doctors) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, 'Get chat list with doctor failed', err);
                ModelUtil.emitDbError(self.eventEmitter, 'Get chat list with doctor failed', err);
                return;
            }
@ -418,14 +418,14 @@ class Doctor extends RedisModel {
                    newMessageCount: doctor.new_msg_count,
                    lastContentType: doctor.last_content_type,
                    lastContent: doctor.last_content,
                    timestamp: objectUtil.timestampToLong(doctor.timestamp)
                    timestamp: ObjectUtil.timestampToLong(doctor.timestamp)
                });
            }
            // 再获取医生间的组
            gmRepo.findAllGroupsWithDoctor(userId, function (err, groups) {
            GroupMsgRepo.findAllGroupsWithDoctor(userId, function (err, groups) {
                if (err) {
                    modelUtil.emitDbError(self.eventEmitter, 'Get group list with doctor failed', err);
                    ModelUtil.emitDbError(self.eventEmitter, 'Get group list with doctor failed', err);
                    return;
                }
@ -438,11 +438,11 @@ class Doctor extends RedisModel {
                        newMessageCount: group.new_msg_count,
                        lastContentType: group.last_content_type,
                        lastContent: group.last_content,
                        timestamp: objectUtil.timestampToLong(group.timestamp)
                        timestamp: ObjectUtil.timestampToLong(group.timestamp)
                    });
                }
                modelUtil.emitData(self.eventEmitter, chats);
                ModelUtil.emitData(self.eventEmitter, chats);
            });
        });
    }
@ -456,9 +456,9 @@ class Doctor extends RedisModel {
        let self = this;
        let chats = {doctor: {}, patient: {}};
        // 先获取医生间的私聊
        pmRepo.findAllP2PWithDoctor(userId, function (err, doctors) {
        PrivateMsgRepo.findAllP2PWithDoctor(userId, function (err, doctors) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, 'Get chat list with doctor failed', err);
                ModelUtil.emitDbError(self.eventEmitter, 'Get chat list with doctor failed', err);
                return;
            }
            var amount = 0;
@ -469,9 +469,9 @@ class Doctor extends RedisModel {
                amount = doctor.new_msg_count+amount;
            }
            // 再获取医生间的组
            gmRepo.findAllGroupsWithDoctor(userId, function (err, groups) {
            GroupMsgRepo.findAllGroupsWithDoctor(userId, function (err, groups) {
                if (err) {
                    modelUtil.emitDbError(self.eventEmitter, 'Get group list with doctor failed', err);
                    ModelUtil.emitDbError(self.eventEmitter, 'Get group list with doctor failed', err);
                    return;
                }
@ -484,9 +484,9 @@ class Doctor extends RedisModel {
                chats.doctor = amount;
                var patientAmount =0;
                //获取患者记录数量
                pmRepo.findAllP2PWithPatient(userId, function (err, patients) {
                PrivateMsgRepo.findAllP2PWithPatient(userId, function (err, patients) {
                    if (err) {
                        modelUtil.emitDbError(self.eventEmitter, 'Get chat list with patient failed', err);
                        ModelUtil.emitDbError(self.eventEmitter, 'Get chat list with patient failed', err);
                        return;
                    }
                    for (let i = 0; i < patients.length; i++) {
@ -497,9 +497,9 @@ class Doctor extends RedisModel {
                    }
                    //获取患者记录数量
                    gmRepo.findAllGroupsWithPatient(userId, function (err, groups) {
                    GroupMsgRepo.findAllGroupsWithPatient(userId, function (err, groups) {
                        if (err) {
                            modelUtil.emitDbError(self.eventEmitter, 'Get group list with patient failed', err);
                            ModelUtil.emitDbError(self.eventEmitter, 'Get group list with patient failed', err);
                            return;
                        }
                        for (let i = 0; i < groups.length; i++) {
@ -511,7 +511,7 @@ class Doctor extends RedisModel {
                            patientAmount = patientAmount+ group.new_msg_count;
                        }
                        chats.patient = patientAmount;
                        modelUtil.emitData(self.eventEmitter, chats);
                        ModelUtil.emitData(self.eventEmitter, chats);
                    });
                });
            });
@ -532,17 +532,17 @@ class Doctor extends RedisModel {
    getPrivateMessages(userId, peerId, contentType, msgStartId, msgEndId, count, closedInterval) {
        let self = this;
        pmRepo.findAllMessages(userId, peerId, contentType === undefined ? "0,1,2,3,4,5,6" : contentType, msgStartId, msgEndId, count, closedInterval, function (err, rows) {
        PrivateMsgRepo.findAllMessages(userId, peerId, contentType === undefined ? "0,1,2,3,4,5,6" : contentType, msgStartId, msgEndId, count, closedInterval, function (err, rows) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, 'Get private message failed', err);
                ModelUtil.emitDbError(self.eventEmitter, 'Get private message failed', err);
                return;
            }
            let messages = Doctor.fillMessages(rows);
            modelUtil.emitData(self.eventEmitter, messages);
            ModelUtil.emitData(self.eventEmitter, messages);
            // 清空统计信息
            statsRepo.clearPrivateChatSummary(userId, peerId, function (err, result) {
            StatsRepo.clearPrivateChatSummary(userId, peerId, function (err, result) {
                if (err) log.error(err);
            });
        });
@ -557,9 +557,9 @@ class Doctor extends RedisModel {
    getUnreadMessageCount(userId, peerId) {
        let self = this;
        statsRepo.getPrivateChatAllUnReadCount(userId, function (err, result) {
        StatsRepo.getPrivateChatAllUnReadCount(userId, function (err, result) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, "Get unread private message count failed", err);
                ModelUtil.emitDbError(self.eventEmitter, "Get unread private message count failed", err);
                return;
            }
@ -568,7 +568,7 @@ class Doctor extends RedisModel {
                data.newMessageCount += result[i].new_msg_count;
            }
            modelUtil.emitData(self.eventEmitter, data);
            ModelUtil.emitData(self.eventEmitter, data);
        });
    }
@ -580,9 +580,9 @@ class Doctor extends RedisModel {
    getAllUnreadMessageCount(userId) {
        let self = this;
        statsRepo.getChatAllUnReadCount(userId, function (err, result) {
        StatsRepo.getChatAllUnReadCount(userId, function (err, result) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, "Get all unread message count failed", err);
                ModelUtil.emitDbError(self.eventEmitter, "Get all unread message count failed", err);
                return;
            }
@ -591,7 +591,7 @@ class Doctor extends RedisModel {
                data.newMessageCount += result[index].new_msg_count;
            }
            modelUtil.emitData(self.eventEmitter, data);
            ModelUtil.emitData(self.eventEmitter, data);
        });
    }
@ -603,26 +603,26 @@ class Doctor extends RedisModel {
     */
    getUnreadPrivateMessages(userId, peerId) {
        let self = this;
        statsRepo.getPrivateChatSummary(userId, peerId, function (err, summary) {
        StatsRepo.getPrivateChatSummary(userId, peerId, function (err, summary) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, 'Get unread private messages failed', err);
                ModelUtil.emitDbError(self.eventEmitter, 'Get unread private messages failed', err);
                return;
            }
            // 没有未读消息,直接返回
            if (summary.length == 0 || summary[0].new_msg_count === 0) {
                modelUtil.emitData(self.eventEmitter, {startId: 0, count: 0, records: []});
                ModelUtil.emitData(self.eventEmitter, {startId: 0, count: 0, records: []});
                return;
            }
            pmRepo.findUnread(peerId, userId, MAX_INT, summary[0].new_msg_count, function (err, rows) {
            PrivateMsgRepo.findUnread(peerId, userId, MAX_INT, summary[0].new_msg_count, function (err, rows) {
                if (err) {
                    modelUtil.emitDbError(self.eventEmitter, "Get unread private messages failed", err);
                    ModelUtil.emitDbError(self.eventEmitter, "Get unread private messages failed", err);
                    return;
                }
                let messages = Doctor.fillMessages(rows);
                modelUtil.emitData(self.eventEmitter, messages);
                ModelUtil.emitData(self.eventEmitter, messages);
            });
        });
    }
@ -635,9 +635,9 @@ class Doctor extends RedisModel {
     */
    getChatSummary(userId, peerId) {
        let self = this;
        statsRepo.getPrivateChatSummary(userId, peerId, function (err, result) {
        StatsRepo.getPrivateChatSummary(userId, peerId, function (err, result) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, "Get private messages statistic failed", err);
                ModelUtil.emitDbError(self.eventEmitter, "Get private messages statistic failed", err);
                return;
            }
@ -658,10 +658,10 @@ class Doctor extends RedisModel {
                data.lastContentType = row.last_content_type;
                data.lastContent = row.last_content;
                data.newMessageCount = row.new_msg_count;
                data.timestamp = objectUtil.timestampToLong(row.timestamp)
                data.timestamp = ObjectUtil.timestampToLong(row.timestamp)
            }
            modelUtil.emitData(self.eventEmitter, data);
            ModelUtil.emitData(self.eventEmitter, data);
        });
    }
@ -670,47 +670,47 @@ class Doctor extends RedisModel {
        if (messageType == 1) {
            // 私信
            pmRepo.findOneMessage(messageId, function (err, result) {
            PrivateMsgRepo.findOneMessage(messageId, function (err, result) {
                if (err) {
                    modelUtil.emitDbError(self.eventEmitter, "Get message failed", err);
                    ModelUtil.emitDbError(self.eventEmitter, "Get message failed", err);
                    return;
                }
                if (result.length == 0) {
                    modelUtil.emitDataNotFound(self.eventEmitter, "Message not found.");
                    ModelUtil.emitDataNotFound(self.eventEmitter, "Message not found.");
                    return;
                }
                modelUtil.emitData(self.eventEmitter, {
                ModelUtil.emitData(self.eventEmitter, {
                    id: result[0].msg_id,
                    from: result[0].from_uid,
                    to: result[0].to_uid,
                    contentType: result[0].type,
                    content: result[0].content,
                    timestamp: objectUtil.timestampToLong(result[0].timestamp)
                    timestamp: ObjectUtil.timestampToLong(result[0].timestamp)
                });
            })
        } else {
            // 群信
            gmRepo.findOneMessage(messageId, function (err, result) {
            GroupMsgRepo.findOneMessage(messageId, function (err, result) {
                if (err) {
                    modelUtil.emitDbError(self.eventEmitter, "Get message failed", err);
                    ModelUtil.emitDbError(self.eventEmitter, "Get message failed", err);
                    return;
                }
                if (result.length == 0) {
                    modelUtil.emitDataNotFound(self.eventEmitter, "Message not found.");
                    ModelUtil.emitDataNotFound(self.eventEmitter, "Message not found.");
                    return;
                }
                modelUtil.emitData(self.eventEmitter, {
                ModelUtil.emitData(self.eventEmitter, {
                    id: result[0].msg_id,
                    from: result[0].from_uid,
                    at: result[0].at_uid,
                    groupId: result[0].to_gid,
                    contentType: result[0].type,
                    content: result[0].content,
                    timestamp: objectUtil.timestampToLong(result[0].timestamp)
                    timestamp: ObjectUtil.timestampToLong(result[0].timestamp)
                });
            });
        }
@ -722,9 +722,9 @@ class Doctor extends RedisModel {
    isConsultFinished(doctorId, patientId) {
        let self = this;
        pmRepo.isCurrentSessionFinished(doctorId, patientId, function (err, result) {
        PrivateMsgRepo.isCurrentSessionFinished(doctorId, patientId, function (err, result) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, "Get session finish status failed: ", err);
                ModelUtil.emitDbError(self.eventEmitter, "Get session finish status failed: ", err);
                return;
            }
@ -738,7 +738,7 @@ class Doctor extends RedisModel {
                }
            }
            modelUtil.emitData(self.eventEmitter, data);
            ModelUtil.emitData(self.eventEmitter, data);
        })
    }
@ -758,7 +758,7 @@ class Doctor extends RedisModel {
                from: row.from_uid,
                contentType: row.type,
                content: row.content,
                timestamp: objectUtil.timestampToLong(row.timestamp)
                timestamp: ObjectUtil.timestampToLong(row.timestamp)
            };
            if (row.to_uid !== undefined) record.to = row.to_uid;

+ 18 - 17
src/server/models/user/patient.js

@ -9,18 +9,19 @@ let log = require("../../util/log.js");
let RedisModel = require('../redis.model');
let objectUtil = require("../../util/objectUtil.js");
let modelUtil = require('../../util/modelUtil');
let wechatUtil = require('../../util/wechatUtil');
let clientCache = require('../socket.io/client.cache').clientCache();
let ObjectUtil = require("../../util/object.util.js");
let ModelUtil = require('../../util/model.util');
let WechatClient = require('../../models/wechat.client/wechat.client');
let Doctor = require('../../models/user/doctor');
let DoctorRepo = require('../../repository/mysql/doctor.repo');
let GroupRepo = require('../../repository/mysql/group.repo');
let PatientRepo = require('../../repository/mysql/patient.repo');
let StatsRepo = require("../../repository/mysql/stats.msg.repo");
let PmRepo = require('../../repository/mysql/private.msg.repo');
let clientCache = require('../socket.io/client.cache').clientCache();
const CONTENT_TYPES = require('../../include/commons').CONTENT_TYPE;
class Patient extends RedisModel {
@ -48,18 +49,18 @@ class Patient extends RedisModel {
        PmRepo.save(message.to, message.from, message.contentType, tempContent, function (err, result) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, 'Save private message failed', err);
                ModelUtil.emitDbError(self.eventEmitter, 'Save private message failed', err);
                return;
            }
            // 结束网络连接,后续操作继续执行
            PmRepo.findOnePatientMessage(result.insertId, function (err, msg) {
                if (err) {
                    modelUtil.emitDbError(self.eventEmitter, 'Save private message success, but return last message failed', err);
                    ModelUtil.emitDbError(self.eventEmitter, 'Save private message success, but return last message failed', err);
                    return;
                }
                modelUtil.emitData(self.eventEmitter, Doctor.fillMessages(msg));
                ModelUtil.emitData(self.eventEmitter, Doctor.fillMessages(msg));
                // 通过Web Socket推送给患者
                let patientClient = clientCache.findById(message.to);
@ -70,7 +71,7 @@ class Patient extends RedisModel {
                    return;
                }
                let row = msg[0];
                row.timestamp = objectUtil.timestampToLong(row.timestamp);
                row.timestamp = ObjectUtil.timestampToLong(row.timestamp);
                patientClient.socketServer.sockets.emit('message', row);
            });
@ -103,7 +104,7 @@ class Patient extends RedisModel {
        }
        GroupRepo.getOnGroupMsg(message.msgId, function (err, result) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, "get group msg info failed", err);
                ModelUtil.emitDbError(self.eventEmitter, "get group msg info failed", err);
            }
            var msg = result ? result[0] : "";
@ -160,13 +161,13 @@ class Patient extends RedisModel {
            };
            // 发送模板消息
            wechatUtil.sendWxTemplateMessage(msg);
            WechatClient.sendWxTemplateMessage(msg);
        }
        // 查询居民openid
        PatientRepo.getPatientOpenid(message.to, function (err, result) {
            if (err) {
                modelUtil.emitDbError(self.eventEmitter, "get patient openid failed", err);
                ModelUtil.emitDbError(self.eventEmitter, "get patient openid failed", err);
                return;
            }
@ -176,7 +177,7 @@ class Patient extends RedisModel {
                // 查询医生信息
                DoctorRepo.findOne(message.from, function (err, result) {
                    if (err) {
                        modelUtil.emitDbError(self.eventEmitter, "get doctor info failed", err);
                        ModelUtil.emitDbError(self.eventEmitter, "get doctor info failed", err);
                        return;
                    }
                    if (result && result.length > 0) {
@ -185,7 +186,7 @@ class Patient extends RedisModel {
                        if (message.group) {
                            GroupRepo.getGroupConsultInfo(message.group, function (err, result) {
                                if (err) {
                                    modelUtil.emitDbError(self.eventEmitter, "get patient and doctor consult info failed", err);
                                    ModelUtil.emitDbError(self.eventEmitter, "get patient and doctor consult info failed", err);
                                    return;
                                }
@ -199,7 +200,7 @@ class Patient extends RedisModel {
                            // 查询医生与居民对应的咨询信息
                            PatientRepo.getPatientDoctorConsult(message.to, message.from, function (err, result) {
                                if (err) {
                                    modelUtil.emitDbError(self.eventEmitter, "get patient and doctor consult info failed", err);
                                    ModelUtil.emitDbError(self.eventEmitter, "get patient and doctor consult info failed", err);
                                    return;
                                }
@ -211,11 +212,11 @@ class Patient extends RedisModel {
                            });
                        }
                    } else {
                        modelUtil.emitDbError(self.eventEmitter, "can not find doctor info", err);
                        ModelUtil.emitDbError(self.eventEmitter, "can not find doctor info", err);
                    }
                });
            } else {
                modelUtil.logError("patient does not bind wechat", err);
                ModelUtil.logError("patient does not bind wechat", err);
            }
        });
    };

+ 14 - 16
src/server/models/user/users.js

@ -12,19 +12,15 @@ let RedisModel = require('../redis.model');
let Doctor = require('./doctor');
let Patient = require('./patient');
let ImDb = require('../../repository/mysql/db/im.db');
let DoctorRepo = require('../../repository/mysql/doctor.repo');
let PatientRepo = require('../../repository/mysql/patient.repo');
let AppStatusRepo = require('../../repository/mysql/app.status.repo');
let RedisClient = require('../../repository/redis/redis.client');
let redisConn = RedisClient.redisClient().connection;
let async = require('async');
let bearcat = require('bearcat');
let log = require('../../util/log');
var imDb = require('../../repository/mysql/db/im.db');
let users = null;
class Users extends RedisModel {
    constructor() {
@ -125,6 +121,16 @@ class Users extends RedisModel {
            });
    }
    /**
     * 取得用户微信端状态。
     *
     * @param userId
     * @param outCallback
     */
    getWechatStatus(userId, outCallback){
        let self = this;
    }
    /**
     * 用户登录。
     *
@ -137,7 +143,7 @@ class Users extends RedisModel {
            if (err) {
                ModelUtil.emitDbError(self.eventEmitter, 'Error occurs when user login and delete token', err);
            } else {
                doctorRepo.login(userId, token, clientId, platform,
                DoctorRepo.login(userId, token, clientId, platform,
                    function (err, result) {
                        if (err) {
                            ModelUtil.emitDbError(self.eventEmitter, 'Error occurs when user login and delete token', err);
@ -152,7 +158,7 @@ class Users extends RedisModel {
    logout(userId, outCallback){
        let self = this;
        doctorRepo.logout(userId,
        DoctorRepo.logout(userId,
            function (err, result) {
                if (err) {
                    ModelUtil.emitDbError(self.eventEmitter, 'Logout failed', err);
@ -174,7 +180,7 @@ class Users extends RedisModel {
                function (callback) {
                    var sql = "select case when count(*) > 0 then true else false end 'is_patient' from patients where id = ?";
                    imDb.execQuery({
                    ImDb.execQuery({
                        "sql": sql,
                        "args": [userId],
                        "handler": function (err, res) {
@ -200,14 +206,6 @@ class Users extends RedisModel {
                callback(null, res !== 0);
            });
    }
    static instance(){
        if(users === null){
            users = new Users();
        }
        return users;
    }
}
let Promises = require('bluebird');

+ 64 - 0
src/server/node_modules/anymatch/index.js

@ -0,0 +1,64 @@
'use strict';
var arrify = require('arrify');
var micromatch = require('micromatch');
var path = require('path');
var anymatch = function(criteria, value, returnIndex, startIndex, endIndex) {
  criteria = arrify(criteria);
  value = arrify(value);
  if (arguments.length === 1) {
    return anymatch.bind(null, criteria.map(function(criterion) {
      return typeof criterion === 'string' && criterion[0] !== '!' ?
        micromatch.matcher(criterion) : criterion;
    }));
  }
  startIndex = startIndex || 0;
  var string = value[0];
  var altString;
  var matched = false;
  var matchIndex = -1;
  function testCriteria (criterion, index) {
    var result;
    switch (toString.call(criterion)) {
    case '[object String]':
      result = string === criterion || altString && altString === criterion;
      result = result || micromatch.isMatch(string, criterion);
      break;
    case '[object RegExp]':
      result = criterion.test(string) || altString && criterion.test(altString);
      break;
    case '[object Function]':
      result = criterion.apply(null, value);
      break;
    default:
      result = false;
    }
    if (result) {
      matchIndex = index + startIndex;
    }
    return result;
  }
  var crit = criteria;
  var negGlobs = crit.reduce(function(arr, criterion, index) {
    if (typeof criterion === 'string' && criterion[0] === '!') {
      if (crit === criteria) {
        // make a copy before modifying
        crit = crit.slice();
      }
      crit[index] = null;
      arr.push(criterion.substr(1));
    }
    return arr;
  }, []);
  if (!negGlobs.length || !micromatch.any(string, negGlobs)) {
    if (path.sep === '\\' && typeof string === 'string') {
      altString = string.split('\\').join('/');
      altString = altString === string ? null : altString;
    }
    matched = crit.slice(startIndex, endIndex).some(testCriteria);
  }
  return returnIndex === true ? matchIndex : matched;
};
module.exports = anymatch;

+ 58 - 0
src/server/node_modules/arr-diff/index.js

@ -0,0 +1,58 @@
/*!
 * arr-diff <https://github.com/jonschlinkert/arr-diff>
 *
 * Copyright (c) 2014 Jon Schlinkert, contributors.
 * Licensed under the MIT License
 */
'use strict';
var flatten = require('arr-flatten');
var slice = [].slice;
/**
 * Return the difference between the first array and
 * additional arrays.
 *
 * ```js
 * var diff = require('{%= name %}');
 *
 * var a = ['a', 'b', 'c', 'd'];
 * var b = ['b', 'c'];
 *
 * console.log(diff(a, b))
 * //=> ['a', 'd']
 * ```
 *
 * @param  {Array} `a`
 * @param  {Array} `b`
 * @return {Array}
 * @api public
 */
function diff(arr, arrays) {
  var argsLen = arguments.length;
  var len = arr.length, i = -1;
  var res = [], arrays;
  if (argsLen === 1) {
    return arr;
  }
  if (argsLen > 2) {
    arrays = flatten(slice.call(arguments, 1));
  }
  while (++i < len) {
    if (!~arrays.indexOf(arr[i])) {
      res.push(arr[i]);
    }
  }
  return res;
}
/**
 * Expose `diff`
 */
module.exports = diff;

+ 27 - 0
src/server/node_modules/arr-flatten/index.js

@ -0,0 +1,27 @@
/*!
 * arr-flatten <https://github.com/jonschlinkert/arr-flatten>
 *
 * Copyright (c) 2014-2015, Jon Schlinkert.
 * Licensed under the MIT License.
 */
'use strict';
module.exports = function flatten(arr) {
  return flat(arr, []);
};
function flat(arr, res) {
  var len = arr.length;
  var i = -1;
  while (len--) {
    var cur = arr[++i];
    if (Array.isArray(cur)) {
      flat(cur, res);
    } else {
      res.push(cur);
    }
  }
  return res;
}

+ 28 - 0
src/server/node_modules/array-unique/index.js

@ -0,0 +1,28 @@
/*!
 * array-unique <https://github.com/jonschlinkert/array-unique>
 *
 * Copyright (c) 2014-2015, Jon Schlinkert.
 * Licensed under the MIT License.
 */
'use strict';
module.exports = function unique(arr) {
  if (!Array.isArray(arr)) {
    throw new TypeError('array-unique expects an array.');
  }
  var len = arr.length;
  var i = -1;
  while (i++ < len) {
    var j = i + 1;
    for (; j < arr.length; ++j) {
      if (arr[i] === arr[j]) {
        arr.splice(j--, 1);
      }
    }
  }
  return arr;
};

+ 8 - 0
src/server/node_modules/arrify/index.js

@ -0,0 +1,8 @@
'use strict';
module.exports = function (val) {
	if (val === null || val === undefined) {
		return [];
	}
	return Array.isArray(val) ? val : [val];
};

+ 38 - 0
src/server/node_modules/async-each/index.js

@ -0,0 +1,38 @@
// async-each MIT license (by Paul Miller from http://paulmillr.com).
(function(globals) {
  'use strict';
  var each = function(items, next, callback) {
    if (!Array.isArray(items)) throw new TypeError('each() expects array as first argument');
    if (typeof next !== 'function') throw new TypeError('each() expects function as second argument');
    if (typeof callback !== 'function') callback = Function.prototype; // no-op
    if (items.length === 0) return callback(undefined, items);
    var transformed = new Array(items.length);
    var count = 0;
    var returned = false;
    items.forEach(function(item, index) {
      next(item, function(error, transformedItem) {
        if (returned) return;
        if (error) {
          returned = true;
          return callback(error);
        }
        transformed[index] = transformedItem;
        count += 1;
        if (count === items.length) return callback(undefined, transformed);
      });
    });
  };
  if (typeof define !== 'undefined' && define.amd) {
    define([], function() {
      return each;
    }); // RequireJS
  } else if (typeof module !== 'undefined' && module.exports) {
    module.exports = each; // CommonJS
  } else {
    globals.asyncEach = each; // <script>
  }
})(this);

+ 399 - 0
src/server/node_modules/braces/index.js

@ -0,0 +1,399 @@
/*!
 * braces <https://github.com/jonschlinkert/braces>
 *
 * Copyright (c) 2014-2015, Jon Schlinkert.
 * Licensed under the MIT license.
 */
'use strict';
/**
 * Module dependencies
 */
var expand = require('expand-range');
var repeat = require('repeat-element');
var tokens = require('preserve');
/**
 * Expose `braces`
 */
module.exports = function(str, options) {
  if (typeof str !== 'string') {
    throw new Error('braces expects a string');
  }
  return braces(str, options);
};
/**
 * Expand `{foo,bar}` or `{1..5}` braces in the
 * given `string`.
 *
 * @param  {String} `str`
 * @param  {Array} `arr`
 * @param  {Object} `options`
 * @return {Array}
 */
function braces(str, arr, options) {
  if (str === '') {
    return [];
  }
  if (!Array.isArray(arr)) {
    options = arr;
    arr = [];
  }
  var opts = options || {};
  arr = arr || [];
  if (typeof opts.nodupes === 'undefined') {
    opts.nodupes = true;
  }
  var fn = opts.fn;
  var es6;
  if (typeof opts === 'function') {
    fn = opts;
    opts = {};
  }
  if (!(patternRe instanceof RegExp)) {
    patternRe = patternRegex();
  }
  var matches = str.match(patternRe) || [];
  var m = matches[0];
  switch(m) {
    case '\\,':
      return escapeCommas(str, arr, opts);
    case '\\.':
      return escapeDots(str, arr, opts);
    case '\/.':
      return escapePaths(str, arr, opts);
    case ' ':
      return splitWhitespace(str);
    case '{,}':
      return exponential(str, opts, braces);
    case '{}':
      return emptyBraces(str, arr, opts);
    case '\\{':
    case '\\}':
      return escapeBraces(str, arr, opts);
    case '${':
      if (!/\{[^{]+\{/.test(str)) {
        return arr.concat(str);
      } else {
        es6 = true;
        str = tokens.before(str, es6Regex());
      }
  }
  if (!(braceRe instanceof RegExp)) {
    braceRe = braceRegex();
  }
  var match = braceRe.exec(str);
  if (match == null) {
    return [str];
  }
  var outter = match[1];
  var inner = match[2];
  if (inner === '') { return [str]; }
  var segs, segsLength;
  if (inner.indexOf('..') !== -1) {
    segs = expand(inner, opts, fn) || inner.split(',');
    segsLength = segs.length;
  } else if (inner[0] === '"' || inner[0] === '\'') {
    return arr.concat(str.split(/['"]/).join(''));
  } else {
    segs = inner.split(',');
    if (opts.makeRe) {
      return braces(str.replace(outter, wrap(segs, '|')), opts);
    }
    segsLength = segs.length;
    if (segsLength === 1 && opts.bash) {
      segs[0] = wrap(segs[0], '\\');
    }
  }
  var len = segs.length;
  var i = 0, val;
  while (len--) {
    var path = segs[i++];
    if (/(\.[^.\/])/.test(path)) {
      if (segsLength > 1) {
        return segs;
      } else {
        return [str];
      }
    }
    val = splice(str, outter, path);
    if (/\{[^{}]+?\}/.test(val)) {
      arr = braces(val, arr, opts);
    } else if (val !== '') {
      if (opts.nodupes && arr.indexOf(val) !== -1) { continue; }
      arr.push(es6 ? tokens.after(val) : val);
    }
  }
  if (opts.strict) { return filter(arr, filterEmpty); }
  return arr;
}
/**
 * Expand exponential ranges
 *
 *   `a{,}{,}` => ['a', 'a', 'a', 'a']
 */
function exponential(str, options, fn) {
  if (typeof options === 'function') {
    fn = options;
    options = null;
  }
  var opts = options || {};
  var esc = '__ESC_EXP__';
  var exp = 0;
  var res;
  var parts = str.split('{,}');
  if (opts.nodupes) {
    return fn(parts.join(''), opts);
  }
  exp = parts.length - 1;
  res = fn(parts.join(esc), opts);
  var len = res.length;
  var arr = [];
  var i = 0;
  while (len--) {
    var ele = res[i++];
    var idx = ele.indexOf(esc);
    if (idx === -1) {
      arr.push(ele);
    } else {
      ele = ele.split('__ESC_EXP__').join('');
      if (!!ele && opts.nodupes !== false) {
        arr.push(ele);
      } else {
        var num = Math.pow(2, exp);
        arr.push.apply(arr, repeat(ele, num));
      }
    }
  }
  return arr;
}
/**
 * Wrap a value with parens, brackets or braces,
 * based on the given character/separator.
 *
 * @param  {String|Array} `val`
 * @param  {String} `ch`
 * @return {String}
 */
function wrap(val, ch) {
  if (ch === '|') {
    return '(' + val.join(ch) + ')';
  }
  if (ch === ',') {
    return '{' + val.join(ch) + '}';
  }
  if (ch === '-') {
    return '[' + val.join(ch) + ']';
  }
  if (ch === '\\') {
    return '\\{' + val + '\\}';
  }
}
/**
 * Handle empty braces: `{}`
 */
function emptyBraces(str, arr, opts) {
  return braces(str.split('{}').join('\\{\\}'), arr, opts);
}
/**
 * Filter out empty-ish values
 */
function filterEmpty(ele) {
  return !!ele && ele !== '\\';
}
/**
 * Handle patterns with whitespace
 */
function splitWhitespace(str) {
  var segs = str.split(' ');
  var len = segs.length;
  var res = [];
  var i = 0;
  while (len--) {
    res.push.apply(res, braces(segs[i++]));
  }
  return res;
}
/**
 * Handle escaped braces: `\\{foo,bar}`
 */
function escapeBraces(str, arr, opts) {
  if (!/\{[^{]+\{/.test(str)) {
    return arr.concat(str.split('\\').join(''));
  } else {
    str = str.split('\\{').join('__LT_BRACE__');
    str = str.split('\\}').join('__RT_BRACE__');
    return map(braces(str, arr, opts), function(ele) {
      ele = ele.split('__LT_BRACE__').join('{');
      return ele.split('__RT_BRACE__').join('}');
    });
  }
}
/**
 * Handle escaped dots: `{1\\.2}`
 */
function escapeDots(str, arr, opts) {
  if (!/[^\\]\..+\\\./.test(str)) {
    return arr.concat(str.split('\\').join(''));
  } else {
    str = str.split('\\.').join('__ESC_DOT__');
    return map(braces(str, arr, opts), function(ele) {
      return ele.split('__ESC_DOT__').join('.');
    });
  }
}
/**
 * Handle escaped dots: `{1\\.2}`
 */
function escapePaths(str, arr, opts) {
  str = str.split('\/.').join('__ESC_PATH__');
  return map(braces(str, arr, opts), function(ele) {
    return ele.split('__ESC_PATH__').join('\/.');
  });
}
/**
 * Handle escaped commas: `{a\\,b}`
 */
function escapeCommas(str, arr, opts) {
  if (!/\w,/.test(str)) {
    return arr.concat(str.split('\\').join(''));
  } else {
    str = str.split('\\,').join('__ESC_COMMA__');
    return map(braces(str, arr, opts), function(ele) {
      return ele.split('__ESC_COMMA__').join(',');
    });
  }
}
/**
 * Regex for common patterns
 */
function patternRegex() {
  return /\${|( (?=[{,}])|(?=[{,}]) )|{}|{,}|\\,(?=.*[{}])|\/\.(?=.*[{}])|\\\.(?={)|\\{|\\}/;
}
/**
 * Braces regex.
 */
function braceRegex() {
  return /.*(\\?\{([^}]+)\})/;
}
/**
 * es6 delimiter regex.
 */
function es6Regex() {
  return /\$\{([^}]+)\}/;
}
var braceRe;
var patternRe;
/**
 * Faster alternative to `String.replace()` when the
 * index of the token to be replaces can't be supplied
 */
function splice(str, token, replacement) {
  var i = str.indexOf(token);
  return str.substr(0, i) + replacement
    + str.substr(i + token.length);
}
/**
 * Fast array map
 */
function map(arr, fn) {
  if (arr == null) {
    return [];
  }
  var len = arr.length;
  var res = new Array(len);
  var i = -1;
  while (++i < len) {
    res[i] = fn(arr[i], i, arr);
  }
  return res;
}
/**
 * Fast array filter
 */
function filter(arr, cb) {
  if (arr == null) return [];
  if (typeof cb !== 'function') {
    throw new TypeError('braces: filter expects a callback function.');
  }
  var len = arr.length;
  var res = arr.slice();
  var i = 0;
  while (len--) {
    if (!cb(arr[len], i++)) {
      res.splice(len, 1);
    }
  }
  return res;
}

+ 509 - 0
src/server/node_modules/chokidar/index.js

@ -0,0 +1,509 @@
'use strict';
var EventEmitter = require('events').EventEmitter;
var fs = require('fs');
var sysPath = require('path');
var each = require('async-each');
var anymatch = require('anymatch');
var globparent = require('glob-parent');
var isglob = require('is-glob');
var arrify = require('arrify');
var isAbsolute = require('path-is-absolute');
var NodeFsHandler = require('./lib/nodefs-handler');
var FsEventsHandler = require('./lib/fsevents-handler');
// Public: Main class.
// Watches files & directories for changes.
//
// * _opts - object, chokidar options hash
//
// Emitted events:
// `add`, `addDir`, `change`, `unlink`, `unlinkDir`, `all`, `error`
//
// Examples
//
//  var watcher = new FSWatcher()
//    .add(directories)
//    .on('add', function(path) {console.log('File', path, 'was added');})
//    .on('change', function(path) {console.log('File', path, 'was changed');})
//    .on('unlink', function(path) {console.log('File', path, 'was removed');})
//    .on('all', function(event, path) {console.log(path, ' emitted ', event);})
//
function FSWatcher(_opts) {
  var opts = {};
  // in case _opts that is passed in is a frozen object
  if (_opts) for (var opt in _opts) opts[opt] = _opts[opt];
  this._watched = Object.create(null);
  this._closers = Object.create(null);
  this._ignoredPaths = Object.create(null);
  Object.defineProperty(this, '_globIgnored', {
    get: function() { return Object.keys(this._ignoredPaths); }
  });
  this.closed = false;
  this._throttled = Object.create(null);
  this._symlinkPaths = Object.create(null);
  function undef(key) {
    return opts[key] === undefined;
  }
  // Set up default options.
  if (undef('persistent')) opts.persistent = true;
  if (undef('ignoreInitial')) opts.ignoreInitial = false;
  if (undef('ignorePermissionErrors')) opts.ignorePermissionErrors = false;
  if (undef('interval')) opts.interval = 100;
  if (undef('binaryInterval')) opts.binaryInterval = 300;
  this.enableBinaryInterval = opts.binaryInterval !== opts.interval;
  // Enable fsevents on OS X when polling isn't explicitly enabled.
  if (undef('useFsEvents')) opts.useFsEvents = !opts.usePolling;
  // If we can't use fsevents, ensure the options reflect it's disabled.
  if (!FsEventsHandler.canUse()) opts.useFsEvents = false;
  // Use polling on Mac if not using fsevents.
  // Other platforms use non-polling fs.watch.
  if (undef('usePolling') && !opts.useFsEvents) {
    opts.usePolling = process.platform === 'darwin';
  }
  // Editor atomic write normalization enabled by default with fs.watch
  if (undef('atomic')) opts.atomic = !opts.usePolling && !opts.useFsEvents;
  if (opts.atomic) this._pendingUnlinks = Object.create(null);
  if (undef('followSymlinks')) opts.followSymlinks = true;
  this._isntIgnored = function(path, stat) {
    return !this._isIgnored(path, stat);
  }.bind(this);
  var readyCalls = 0;
  this._emitReady = function() {
    if (++readyCalls >= this._readyCount) {
      this._emitReady = Function.prototype;
      // use process.nextTick to allow time for listener to be bound
      process.nextTick(this.emit.bind(this, 'ready'));
    }
  }.bind(this);
  this.options = opts;
  // You’re frozen when your heart’s not open.
  Object.freeze(opts);
}
FSWatcher.prototype = Object.create(EventEmitter.prototype);
// Common helpers
// --------------
// Private method: Normalize and emit events
//
// * event     - string, type of event
// * path      - string, file or directory path
// * val[1..3] - arguments to be passed with event
//
// Returns the error if defined, otherwise the value of the
// FSWatcher instance's `closed` flag
FSWatcher.prototype._emit = function(event, path, val1, val2, val3) {
  if (this.options.cwd) path = sysPath.relative(this.options.cwd, path);
  var args = [event, path];
  if (val3 !== undefined) args.push(val1, val2, val3);
  else if (val2 !== undefined) args.push(val1, val2);
  else if (val1 !== undefined) args.push(val1);
  if (this.options.atomic) {
    if (event === 'unlink') {
      this._pendingUnlinks[path] = args;
      setTimeout(function() {
        Object.keys(this._pendingUnlinks).forEach(function(path) {
          this.emit.apply(this, this._pendingUnlinks[path]);
          this.emit.apply(this, ['all'].concat(this._pendingUnlinks[path]));
          delete this._pendingUnlinks[path];
        }.bind(this));
      }.bind(this), 100);
      return this;
    } else if (event === 'add' && this._pendingUnlinks[path]) {
      event = args[0] = 'change';
      delete this._pendingUnlinks[path];
    }
  }
  if (event === 'change') {
    if (!this._throttle('change', path, 50)) return this;
  }
  var emitEvent = function() {
    this.emit.apply(this, args);
    if (event !== 'error') this.emit.apply(this, ['all'].concat(args));
  }.bind(this);
  if (
    this.options.alwaysStat && val1 === undefined &&
    (event === 'add' || event === 'addDir' || event === 'change')
  ) {
    fs.stat(path, function(error, stats) {
      // Suppress event when fs.stat fails, to avoid sending undefined 'stat'
      if (error || !stats) return;
      args.push(stats);
      emitEvent();
    });
  } else {
    emitEvent();
  }
  return this;
};
// Private method: Common handler for errors
//
// * error  - object, Error instance
//
// Returns the error if defined, otherwise the value of the
// FSWatcher instance's `closed` flag
FSWatcher.prototype._handleError = function(error) {
  var code = error && error.code;
  var ipe = this.options.ignorePermissionErrors;
  if (error &&
    code !== 'ENOENT' &&
    code !== 'ENOTDIR' &&
    (!ipe || (code !== 'EPERM' && code !== 'EACCES'))
  ) this.emit('error', error);
  return error || this.closed;
};
// Private method: Helper utility for throttling
//
// * action  - string, type of action being throttled
// * path    - string, path being acted upon
// * timeout - int, duration of time to suppress duplicate actions
//
// Returns throttle tracking object or false if action should be suppressed
FSWatcher.prototype._throttle = function(action, path, timeout) {
  if (!(action in this._throttled)) {
    this._throttled[action] = Object.create(null);
  }
  var throttled = this._throttled[action];
  if (path in throttled) return false;
  function clear() {
    delete throttled[path];
    clearTimeout(timeoutObject);
  }
  var timeoutObject = setTimeout(clear, timeout);
  throttled[path] = {timeoutObject: timeoutObject, clear: clear};
  return throttled[path];
};
// Private method: Determines whether user has asked to ignore this path
//
// * path  - string, path to file or directory
// * stats - object, result of fs.stat
//
// Returns boolean
FSWatcher.prototype._isIgnored = function(path, stats) {
  if (
    this.options.atomic &&
    /\..*\.(sw[px])$|\~$|\.subl.*\.tmp/.test(path)
  ) return true;
  if (!this._userIgnored) {
    var cwd = this.options.cwd;
    var ignored = this.options.ignored;
    if (cwd && ignored) {
      ignored = arrify(ignored).map(function (path) {
        if (typeof path !== 'string') return path;
        return isAbsolute(path) ? path : sysPath.join(cwd, path);
      });
    }
    this._userIgnored = anymatch(this._globIgnored
      .concat(ignored)
      .concat(arrify(ignored)
        .filter(function(path) {
          return typeof path === 'string' && !isglob(path);
        }).map(function(path) {
          return path + '/**/*';
        })
      )
    );
  }
  return this._userIgnored([path, stats]);
};
// Private method: Provides a set of common helpers and properties relating to
// symlink and glob handling
//
// * path - string, file, directory, or glob pattern being watched
// * depth - int, at any depth > 0, this isn't a glob
//
// Returns object containing helpers for this path
FSWatcher.prototype._getWatchHelpers = function(path, depth) {
  path = path.replace(/^\.[\/\\]/, '');
  var watchPath = depth ? path : globparent(path);
  var hasGlob = watchPath !== path;
  var globFilter = hasGlob ? anymatch(path) : false;
  var entryPath = function(entry) {
    return sysPath.join(watchPath, sysPath.relative(watchPath, entry.fullPath));
  }
  var filterPath = function(entry) {
    return (!hasGlob || globFilter(entryPath(entry))) &&
      this._isntIgnored(entryPath(entry), entry.stat) &&
      (this.options.ignorePermissionErrors ||
        this._hasReadPermissions(entry.stat));
  }.bind(this);
  var getDirParts = function(path) {
    if (!hasGlob) return false;
    var parts = sysPath.relative(watchPath, path).split(/[\/\\]/);
    return parts;
  }
  var dirParts = getDirParts(path);
  if (dirParts && dirParts.length > 1) dirParts.pop();
  var filterDir = function(entry) {
    if (hasGlob) {
      var entryParts = getDirParts(entry.fullPath);
      var globstar = false;
      var unmatchedGlob = !dirParts.every(function(part, i) {
        if (part === '**') globstar = true;
        return globstar || !entryParts[i] || anymatch(part, entryParts[i]);
      });
    }
    return !unmatchedGlob && this._isntIgnored(entryPath(entry), entry.stat);
  }.bind(this);
  return {
    followSymlinks: this.options.followSymlinks,
    statMethod: this.options.followSymlinks ? 'stat' : 'lstat',
    path: path,
    watchPath: watchPath,
    entryPath: entryPath,
    hasGlob: hasGlob,
    globFilter: globFilter,
    filterPath: filterPath,
    filterDir: filterDir
  };
}
// Directory helpers
// -----------------
// Private method: Provides directory tracking objects
//
// * directory - string, path of the directory
//
// Returns the directory's tracking object
FSWatcher.prototype._getWatchedDir = function(directory) {
  var dir = sysPath.resolve(directory);
  var watcherRemove = this._remove.bind(this);
  if (!(dir in this._watched)) this._watched[dir] = {
    _items: Object.create(null),
    add: function(item) {this._items[item] = true;},
    remove: function(item) {
      delete this._items[item];
      if (!this.children().length) {
        fs.readdir(dir, function(err) {
          if (err) watcherRemove(sysPath.dirname(dir), sysPath.basename(dir));
        });
      }
    },
    has: function(item) {return item in this._items;},
    children: function() {return Object.keys(this._items);}
  };
  return this._watched[dir];
};
// File helpers
// ------------
// Private method: Check for read permissions
// Based on this answer on SO: http://stackoverflow.com/a/11781404/1358405
//
// * stats - object, result of fs.stat
//
// Returns boolean
FSWatcher.prototype._hasReadPermissions = function(stats) {
  return Boolean(4 & parseInt(((stats && stats.mode) & 0x1ff).toString(8)[0], 10));
};
// Private method: Handles emitting unlink events for
// files and directories, and via recursion, for
// files and directories within directories that are unlinked
//
// * directory - string, directory within which the following item is located
// * item      - string, base path of item/directory
//
// Returns nothing
FSWatcher.prototype._remove = function(directory, item) {
  // if what is being deleted is a directory, get that directory's paths
  // for recursive deleting and cleaning of watched object
  // if it is not a directory, nestedDirectoryChildren will be empty array
  var path = sysPath.join(directory, item);
  var fullPath = sysPath.resolve(path);
  var isDirectory = this._watched[path] || this._watched[fullPath];
  // prevent duplicate handling in case of arriving here nearly simultaneously
  // via multiple paths (such as _handleFile and _handleDir)
  if (!this._throttle('remove', path, 100)) return;
  // if the only watched file is removed, watch for its return
  var watchedDirs = Object.keys(this._watched);
  if (!isDirectory && !this.options.useFsEvents && watchedDirs.length === 1) {
    this.add(directory, item, true);
  }
  // This will create a new entry in the watched object in either case
  // so we got to do the directory check beforehand
  var nestedDirectoryChildren = this._getWatchedDir(path).children();
  // Recursively remove children directories / files.
  nestedDirectoryChildren.forEach(function(nestedItem) {
    this._remove(path, nestedItem);
  }, this);
  // Check if item was on the watched list and remove it
  var parent = this._getWatchedDir(directory);
  var wasTracked = parent.has(item);
  parent.remove(item);
  // The Entry will either be a directory that just got removed
  // or a bogus entry to a file, in either case we have to remove it
  delete this._watched[path];
  delete this._watched[fullPath];
  var eventName = isDirectory ? 'unlinkDir' : 'unlink';
  if (wasTracked && !this._isIgnored(path)) this._emit(eventName, path);
};
// Public method: Adds paths to be watched on an existing FSWatcher instance
// * paths     - string or array of strings, file/directory paths and/or globs
// * _origAdd  - private boolean, for handling non-existent paths to be watched
// * _internal - private boolean, indicates a non-user add
// Returns an instance of FSWatcher for chaining.
FSWatcher.prototype.add = function(paths, _origAdd, _internal) {
  var cwd = this.options.cwd;
  this.closed = false;
  paths = arrify(paths);
  if (cwd) paths = paths.map(function(path) {
    if (isAbsolute(path)) {
      return path;
    } else if (path[0] === '!') {
      return '!' + sysPath.join(cwd, path.substring(1));
    } else {
      return sysPath.join(cwd, path);
    }
  });
  // set aside negated glob strings
  paths = paths.filter(function(path) {
    if (path[0] === '!') this._ignoredPaths[path.substring(1)] = true;
    else {
      // if a path is being added that was previously ignored, stop ignoring it
      delete this._ignoredPaths[path];
      delete this._ignoredPaths[path + '/**/*'];
      // reset the cached userIgnored anymatch fn
      // to make ignoredPaths changes effective
      this._userIgnored = null;
      return true;
    }
  }, this);
  if (this.options.useFsEvents && FsEventsHandler.canUse()) {
    if (!this._readyCount) this._readyCount = paths.length;
    if (this.options.persistent) this._readyCount *= 2;
    paths.forEach(this._addToFsEvents, this);
  } else {
    if (!this._readyCount) this._readyCount = 0;
    this._readyCount += paths.length;
    each(paths, function(path, next) {
      this._addToNodeFs(path, !_internal, 0, 0, _origAdd, function(err, res) {
        if (res) this._emitReady();
        next(err, res);
      }.bind(this));
    }.bind(this), function(error, results) {
      results.forEach(function(item) {
        if (!item) return;
        this.add(sysPath.dirname(item), sysPath.basename(_origAdd || item));
      }, this);
    }.bind(this));
  }
  return this;
};
// Public method: Close watchers or start ignoring events from specified paths.
// * paths     - string or array of strings, file/directory paths and/or globs
// Returns instance of FSWatcher for chaining.
FSWatcher.prototype.unwatch = function(paths) {
  if (this.closed) return this;
  paths = arrify(paths);
  paths.forEach(function(path) {
    if (this._closers[path]) {
      this._closers[path]();
      delete this._closers[path];
      this._getWatchedDir(sysPath.dirname(path)).remove(sysPath.basename(path));
    } else {
      //convert to absolute path
      path = sysPath.resolve(path);
      
      this._ignoredPaths[path] = true;
      if (path in this._watched) {
        this._ignoredPaths[path + '/**/*'] = true;
      }
      // reset the cached userIgnored anymatch fn
      // to make ignoredPaths changes effective
      this._userIgnored = null;
    }
  }, this);
  return this;
};
// Public method: Close watchers and remove all listeners from watched paths.
// Returns instance of FSWatcher for chaining.
FSWatcher.prototype.close = function() {
  if (this.closed) return this;
  this.closed = true;
  Object.keys(this._closers).forEach(function(watchPath) {
    this._closers[watchPath]();
    delete this._closers[watchPath];
  }, this);
  this._watched = Object.create(null);
  this.removeAllListeners();
  return this;
};
// Attach watch handler prototype methods
function importHandler(handler) {
  Object.keys(handler.prototype).forEach(function(method) {
    FSWatcher.prototype[method] = handler.prototype[method];
  });
}
importHandler(NodeFsHandler);
if (FsEventsHandler.canUse()) importHandler(FsEventsHandler);
// Export FSWatcher class
exports.FSWatcher = FSWatcher;
// Public function: Instantiates watcher with paths to be tracked.
// * paths     - string or array of strings, file/directory paths and/or globs
// * options   - object, chokidar options
// Returns an instance of FSWatcher for chaining.
exports.watch = function(paths, options) {
  return new FSWatcher(options).add(paths);
};

+ 361 - 0
src/server/node_modules/chokidar/lib/fsevents-handler.js

@ -0,0 +1,361 @@
'use strict';
var fs = require('fs');
var sysPath = require('path');
var readdirp = require('readdirp');
var fsevents;
try { fsevents = require('fsevents'); } catch (error) {}
// fsevents instance helper functions
// object to hold per-process fsevents instances
// (may be shared across chokidar FSWatcher instances)
var FSEventsWatchers = Object.create(null);
// Private function: Instantiates the fsevents interface
// * path       - string, path to be watched
// * callback   - function, called when fsevents is bound and ready
// Returns new fsevents instance
function createFSEventsInstance(path, callback) {
  return (new fsevents(path)).on('fsevent', callback).start();
}
// Private function: Instantiates the fsevents interface or binds listeners
// to an existing one covering the same file tree
// * path       - string, path to be watched
// * realPath   - string, real path (in case of symlinks)
// * listener   - function, called when fsevents emits events
// * rawEmitter - function, passes data to listeners of the 'raw' event
// Returns close function
function setFSEventsListener(path, realPath, listener, rawEmitter) {
  var watchPath = sysPath.extname(path) ? sysPath.dirname(path) : path;
  var watchContainer;
  var resolvedPath = sysPath.resolve(path);
  var hasSymlink = resolvedPath !== realPath;
  function filteredListener(fullPath, flags, info) {
    if (hasSymlink) fullPath = fullPath.replace(realPath, resolvedPath);
    if (
      fullPath === resolvedPath ||
      !fullPath.indexOf(resolvedPath + sysPath.sep)
    ) listener(fullPath, flags, info);
  }
  // check if there is already a watcher on a parent path
  // modifies `watchPath` to the parent path when it finds a match
  function watchedParent() {
    return Object.keys(FSEventsWatchers).some(function(watchedPath) {
      // condition is met when indexOf returns 0
      if (!realPath.indexOf(sysPath.resolve(watchedPath) + sysPath.sep)) {
        watchPath = watchedPath;
        return true;
      }
    });
  }
  if (watchPath in FSEventsWatchers || watchedParent()) {
    watchContainer = FSEventsWatchers[watchPath];
    watchContainer.listeners.push(filteredListener);
  } else {
    watchContainer = FSEventsWatchers[watchPath] = {
      listeners: [filteredListener],
      rawEmitters: [rawEmitter],
      watcher: createFSEventsInstance(watchPath, function(fullPath, flags) {
        var info = fsevents.getInfo(fullPath, flags);
        watchContainer.listeners.forEach(function(listener) {
          listener(fullPath, flags, info);
        });
        watchContainer.rawEmitters.forEach(function(emitter) {
          emitter(info.event, fullPath, info);
        });
      })
    };
  }
  var listenerIndex = watchContainer.listeners.length - 1;
  // removes this instance's listeners and closes the underlying fsevents
  // instance if there are no more listeners left
  return function close() {
    delete watchContainer.listeners[listenerIndex];
    delete watchContainer.rawEmitters[listenerIndex];
    if (!Object.keys(watchContainer.listeners).length) {
      watchContainer.watcher.stop();
      delete FSEventsWatchers[watchPath];
    }
  }
}
// returns boolean indicating whether fsevents can be used
function canUse() {
  return fsevents && Object.keys(FSEventsWatchers).length < 128;
}
// determines subdirectory traversal levels from root to path
function depth(path, root) {
  var i = 0;
  while (!path.indexOf(root) && (path = sysPath.dirname(path)) !== root) i++;
  return i;
}
// fake constructor for attaching fsevents-specific prototype methods that
// will be copied to FSWatcher's prototype
function FsEventsHandler() {}
// Private method: Handle symlinks encountered during directory scan
// * wathPath   - string, file/dir path to be watched with fsevents
// * realPath   - string, real path (in case of symlinks)
// * transform  - function, path transformer
// * globFilter - function, path filter in case a glob pattern was provided
// Returns close function for the watcher instance
FsEventsHandler.prototype._watchWithFsEvents =
function(watchPath, realPath, transform, globFilter) {
  if (this._isIgnored(watchPath)) return;
  var watchCallback = function(fullPath, flags, info) {
    if (
      this.options.depth !== undefined &&
      depth(fullPath, realPath) > this.options.depth
    ) return;
    var path = transform(sysPath.join(
      watchPath, sysPath.relative(watchPath, fullPath)
    ));
    if (globFilter && !globFilter(path)) return;
    // ensure directories are tracked
    var parent = sysPath.dirname(path);
    var item = sysPath.basename(path);
    var watchedDir = this._getWatchedDir(
      info.type === 'directory' ? path : parent
    );
    var checkIgnored = function(stats) {
      if (this._isIgnored(path, stats)) {
        this._ignoredPaths[path] = true;
        if (stats && stats.isDirectory()) {
          this._ignoredPaths[path + '/**/*'] = true;
        }
        return true;
      } else {
        delete this._ignoredPaths[path];
        delete this._ignoredPaths[path + '/**/*'];
      }
    }.bind(this);
    var handleEvent = function(event) {
      if (checkIgnored()) return;
      if (event === 'unlink') {
        // suppress unlink events on never before seen files
        if (info.type === 'directory' || watchedDir.has(item)) {
          this._remove(parent, item);
        }
      } else {
        if (event === 'add') {
          // track new directories
          if (info.type === 'directory') this._getWatchedDir(path);
          if (info.type === 'symlink' && this.options.followSymlinks) {
            // push symlinks back to the top of the stack to get handled
            var curDepth = this.options.depth === undefined ?
              undefined : depth(fullPath, realPath) + 1;
            return this._addToFsEvents(path, false, true, curDepth);
          } else {
            // track new paths
            // (other than symlinks being followed, which will be tracked soon)
            this._getWatchedDir(parent).add(item);
          }
        }
        var eventName = info.type === 'directory' ? event + 'Dir' : event;
        this._emit(eventName, path);
      }
    }.bind(this);
    function addOrChange() {
      handleEvent(watchedDir.has(item) ? 'change' : 'add');
    }
    function checkFd() {
      fs.open(path, 'r', function(error, fd) {
        if (fd) fs.close(fd);
        error && error.code !== 'EACCES' ?
          handleEvent('unlink') : addOrChange();
      });
    }
    // correct for wrong events emitted
    var wrongEventFlags = [
      69888, 70400, 71424, 72704, 73472, 131328, 131840, 262912
    ];
    if (wrongEventFlags.indexOf(flags) !== -1 || info.event === 'unknown') {
      if (typeof this.options.ignored === 'function') {
        fs.stat(path, function(error, stats) {
          if (checkIgnored(stats)) return;
          stats ? addOrChange() : handleEvent('unlink');
        });
      } else {
        checkFd();
      }
    } else {
      switch (info.event) {
      case 'created':
      case 'modified':
        return addOrChange();
      case 'deleted':
      case 'moved':
        return checkFd();
      }
    }
  }.bind(this);
  var closer = setFSEventsListener(
    watchPath,
    realPath,
    watchCallback,
    this.emit.bind(this, 'raw')
  );
  this._emitReady();
  return closer;
};
// Private method: Handle symlinks encountered during directory scan
// * linkPath   - string, path to symlink
// * fullPath   - string, absolute path to the symlink
// * transform  - function, pre-existing path transformer
// * curDepth   - int, level of subdirectories traversed to where symlink is
// Returns nothing
FsEventsHandler.prototype._fsEventsSymlink =
function(linkPath, fullPath, transform, curDepth) {
  // don't follow the same symlink more than once
  if (this._symlinkPaths[fullPath]) return;
  else this._symlinkPaths[fullPath] = true;
  this._readyCount++;
  fs.realpath(linkPath, function(error, linkTarget) {
    if (this._handleError(error) || this._isIgnored(linkTarget)) {
      return this._emitReady();
    }
    this._readyCount++;
    // add the linkTarget for watching with a wrapper for transform
    // that causes emitted paths to incorporate the link's path
    this._addToFsEvents(linkTarget || linkPath, function(path) {
      var dotSlash = '.' + sysPath.sep;
      var aliasedPath = linkPath;
      if (linkTarget && linkTarget !== dotSlash) {
        aliasedPath = path.replace(linkTarget, linkPath);
      } else if (path !== dotSlash) {
        aliasedPath = sysPath.join(linkPath, path);
      }
      return transform(aliasedPath);
    }, false, curDepth);
  }.bind(this));
};
// Private method: Handle added path with fsevents
// * path       - string, file/directory path or glob pattern
// * transform  - function, converts working path to what the user expects
// * forceAdd   - boolean, ensure add is emitted
// * priorDepth - int, level of subdirectories already traversed
// Returns nothing
FsEventsHandler.prototype._addToFsEvents =
function(path, transform, forceAdd, priorDepth) {
  // applies transform if provided, otherwise returns same value
  var processPath = typeof transform === 'function' ?
    transform : function(val) { return val; };
  var emitAdd = function(newPath, stats) {
    var pp = processPath(newPath);
    var isDir = stats.isDirectory();
    var dirObj = this._getWatchedDir(sysPath.dirname(pp));
    var base = sysPath.basename(pp);
    // ensure empty dirs get tracked
    if (isDir) this._getWatchedDir(pp);
    if (dirObj.has(base)) return;
    dirObj.add(base);
    if (!this.options.ignoreInitial || forceAdd === true) {
      this._emit(isDir ? 'addDir' : 'add', pp, stats);
    }
  }.bind(this);
  var wh = this._getWatchHelpers(path);
  // evaluate what is at the path we're being asked to watch
  fs[wh.statMethod](wh.watchPath, function(error, stats) {
    if (this._handleError(error) || this._isIgnored(wh.watchPath, stats)) {
      this._emitReady();
      return this._emitReady();
    }
    if (stats.isDirectory()) {
      // emit addDir unless this is a glob parent
      if (!wh.globFilter) emitAdd(processPath(path), stats);
      // don't recurse further if it would exceed depth setting
      if (priorDepth && priorDepth > this.options.depth) return;
      // scan the contents of the dir
      readdirp({
        root: wh.watchPath,
        entryType: 'all',
        fileFilter: wh.filterPath,
        directoryFilter: wh.filterDir,
        lstat: true,
        depth: this.options.depth - (priorDepth || 0)
      }).on('data', function(entry) {
        // need to check filterPath on dirs b/c filterDir is less restrictive
        if (entry.stat.isDirectory() && !wh.filterPath(entry)) return;
        var joinedPath = sysPath.join(wh.watchPath, entry.path);
        var fullPath = entry.fullPath;
        if (wh.followSymlinks && entry.stat.isSymbolicLink()) {
          // preserve the current depth here since it can't be derived from
          // real paths past the symlink
          var curDepth = this.options.depth === undefined ?
            undefined : depth(joinedPath, sysPath.resolve(wh.watchPath)) + 1;
          this._fsEventsSymlink(joinedPath, fullPath, processPath, curDepth);
        } else {
          emitAdd(joinedPath, entry.stat);
        }
      }.bind(this)).on('end', this._emitReady);
    } else {
      emitAdd(wh.watchPath, stats);
      this._emitReady();
    }
  }.bind(this));
  if (this.options.persistent) {
    var initWatch = function(error, realPath) {
      var closer = this._watchWithFsEvents(
        wh.watchPath,
        sysPath.resolve(realPath || wh.watchPath),
        processPath,
        wh.globFilter
      );
      if (closer) this._closers[path] = closer;
    }.bind(this);
    if (typeof transform === 'function') {
      // realpath has already been resolved
      initWatch();
    } else {
      fs.realpath(wh.watchPath, initWatch);
    }
  }
};
module.exports = FsEventsHandler;
module.exports.canUse = canUse;

+ 476 - 0
src/server/node_modules/chokidar/lib/nodefs-handler.js

@ -0,0 +1,476 @@
'use strict';
var fs = require('fs');
var sysPath = require('path');
var readdirp = require('readdirp');
var isBinaryPath = require('is-binary-path');
// fs.watch helpers
// object to hold per-process fs.watch instances
// (may be shared across chokidar FSWatcher instances)
var FsWatchInstances = Object.create(null);
// Private function: Instantiates the fs.watch interface
// * path       - string, path to be watched
// * options    - object, options to be passed to fs.watch
// * listener   - function, main event handler
// * errHandler - function, handler which emits info about errors
// * emitRaw    - function, handler which emits raw event data
// Returns new fsevents instance
function createFsWatchInstance(path, options, listener, errHandler, emitRaw) {
  var handleEvent = function(rawEvent, evPath) {
    listener(path);
    emitRaw(rawEvent, evPath, {watchedPath: path});
    // emit based on events occuring for files from a directory's watcher in
    // case the file's watcher misses it (and rely on throttling to de-dupe)
    if (evPath && path !== evPath) {
      fsWatchBroadcast(
        sysPath.resolve(path, evPath), 'listeners', sysPath.join(path, evPath)
      );
    }
  };
  try {
    return fs.watch(path, options, handleEvent);
  } catch (error) {
    errHandler(error);
  }
}
// Private function: Helper for passing fs.watch event data to a
// collection of listeners
// * fullPath   - string, absolute path bound to the fs.watch instance
// * type       - string, listener type
// * val[1..3]  - arguments to be passed to listeners
// Returns nothing
function fsWatchBroadcast(fullPath, type, val1, val2, val3) {
  if (!FsWatchInstances[fullPath]) return;
  FsWatchInstances[fullPath][type].forEach(function(listener) {
    listener(val1, val2, val3);
  });
}
// Private function: Instantiates the fs.watch interface or binds listeners
// to an existing one covering the same file system entry
// * path       - string, path to be watched
// * fullPath   - string, absolute path
// * options    - object, options to be passed to fs.watch
// * handlers   - object, container for event listener functions
// Returns close function
function setFsWatchListener(path, fullPath, options, handlers) {
  var listener = handlers.listener;
  var errHandler = handlers.errHandler;
  var rawEmitter = handlers.rawEmitter;
  var container = FsWatchInstances[fullPath];
  var watcher;
  if (!options.persistent) {
    watcher = createFsWatchInstance(
      path, options, listener, errHandler, rawEmitter
    );
    return watcher.close.bind(watcher);
  }
  if (!container) {
    watcher = createFsWatchInstance(
      path,
      options,
      fsWatchBroadcast.bind(null, fullPath, 'listeners'),
      errHandler, // no need to use broadcast here
      fsWatchBroadcast.bind(null, fullPath, 'rawEmitters')
    );
    if (!watcher) return;
    var broadcastErr = fsWatchBroadcast.bind(null, fullPath, 'errHandlers');
    watcher.on('error', function(error) {
      // Workaround for https://github.com/joyent/node/issues/4337
      if (process.platform === 'win32' && error.code === 'EPERM') {
        fs.open(path, 'r', function(err, fd) {
          if (fd) fs.close(fd);
          if (!err) broadcastErr(error);
        });
      } else {
        broadcastErr(error);
      }
    });
    container = FsWatchInstances[fullPath] = {
      listeners: [listener],
      errHandlers: [errHandler],
      rawEmitters: [rawEmitter],
      watcher: watcher
    };
  } else {
    container.listeners.push(listener);
    container.errHandlers.push(errHandler);
    container.rawEmitters.push(rawEmitter);
  }
  var listenerIndex = container.listeners.length - 1;
  // removes this instance's listeners and closes the underlying fs.watch
  // instance if there are no more listeners left
  return function close() {
    delete container.listeners[listenerIndex];
    delete container.errHandlers[listenerIndex];
    delete container.rawEmitters[listenerIndex];
    if (!Object.keys(container.listeners).length) {
      container.watcher.close();
      delete FsWatchInstances[fullPath];
    }
  };
}
// fs.watchFile helpers
// object to hold per-process fs.watchFile instances
// (may be shared across chokidar FSWatcher instances)
var FsWatchFileInstances = Object.create(null);
// Private function: Instantiates the fs.watchFile interface or binds listeners
// to an existing one covering the same file system entry
// * path       - string, path to be watched
// * fullPath   - string, absolute path
// * options    - object, options to be passed to fs.watchFile
// * handlers   - object, container for event listener functions
// Returns close function
function setFsWatchFileListener(path, fullPath, options, handlers) {
  var listener = handlers.listener;
  var rawEmitter = handlers.rawEmitter;
  var container = FsWatchFileInstances[fullPath];
  var listeners = [];
  var rawEmitters = [];
  if (
    container && (
      container.options.persistent < options.persistent ||
      container.options.interval > options.interval
    )
  ) {
    // "Upgrade" the watcher to persistence or a quicker interval.
    // This creates some unlikely edge case issues if the user mixes
    // settings in a very weird way, but solving for those cases
    // doesn't seem worthwhile for the added complexity.
    listeners = container.listeners;
    rawEmitters = container.rawEmitters;
    fs.unwatchFile(fullPath);
    container = false;
  }
  if (!container) {
    listeners.push(listener);
    rawEmitters.push(rawEmitter);
    container = FsWatchFileInstances[fullPath] = {
      listeners: listeners,
      rawEmitters: rawEmitters,
      options: options,
      watcher: fs.watchFile(fullPath, options, function(curr, prev) {
        container.rawEmitters.forEach(function(rawEmitter) {
          rawEmitter('change', fullPath, {curr: curr, prev: prev});
        });
        var currmtime = curr.mtime.getTime();
        if (curr.size !== prev.size || currmtime > prev.mtime.getTime() || currmtime === 0) {
          container.listeners.forEach(function(listener) {
            listener(path, curr);
          });
        }
      })
    };
  } else {
    container.listeners.push(listener);
    container.rawEmitters.push(rawEmitter);
  }
  var listenerIndex = container.listeners.length - 1;
  // removes this instance's listeners and closes the underlying fs.watchFile
  // instance if there are no more listeners left
  return function close() {
    delete container.listeners[listenerIndex];
    delete container.rawEmitters[listenerIndex];
    if (!Object.keys(container.listeners).length) {
      fs.unwatchFile(fullPath);
      delete FsWatchFileInstances[fullPath];
    }
  }
}
// fake constructor for attaching nodefs-specific prototype methods that
// will be copied to FSWatcher's prototype
function NodeFsHandler() {}
// Private method: Watch file for changes with fs.watchFile or fs.watch.
// * path     - string, path to file or directory.
// * listener - function, to be executed on fs change.
// Returns close function for the watcher instance
NodeFsHandler.prototype._watchWithNodeFs =
function(path, listener) {
  var directory = sysPath.dirname(path);
  var basename = sysPath.basename(path);
  var parent = this._getWatchedDir(directory);
  parent.add(basename);
  var absolutePath = sysPath.resolve(path);
  var options = {persistent: this.options.persistent};
  if (!listener) listener = Function.prototype; // empty function
  var closer;
  if (this.options.usePolling) {
    options.interval = this.enableBinaryInterval && isBinaryPath(basename) ?
      this.options.binaryInterval : this.options.interval;
    closer = setFsWatchFileListener(path, absolutePath, options, {
      listener: listener,
      rawEmitter: this.emit.bind(this, 'raw')
    });
  } else {
    closer = setFsWatchListener(path, absolutePath, options, {
      listener: listener,
      errHandler: this._handleError.bind(this),
      rawEmitter: this.emit.bind(this, 'raw')
    });
  }
  return closer;
};
// Private method: Watch a file and emit add event if warranted
// * file       - string, the file's path
// * stats      - object, result of fs.stat
// * initialAdd - boolean, was the file added at watch instantiation?
// * callback   - function, called when done processing as a newly seen file
// Returns close function for the watcher instance
NodeFsHandler.prototype._handleFile =
function(file, stats, initialAdd, callback) {
  var dirname = sysPath.dirname(file);
  var basename = sysPath.basename(file);
  var parent = this._getWatchedDir(dirname);
  // if the file is already being watched, do nothing
  if (parent.has(basename)) return callback();
  // kick off the watcher
  var closer = this._watchWithNodeFs(file, function(path, newStats) {
    if (!this._throttle('watch', file, 5)) return;
    if (!newStats || newStats && newStats.mtime.getTime() === 0) {
      fs.stat(file, function(error, newStats) {
        // Fix issues where mtime is null but file is still present
        if (error) {
          this._remove(dirname, basename);
        } else {
          this._emit('change', file, newStats);
        }
      }.bind(this));
    // add is about to be emitted if file not already tracked in parent
    } else if (parent.has(basename)) {
      this._emit('change', file, newStats);
    }
  }.bind(this));
  // emit an add event if we're supposed to
  if (!(initialAdd && this.options.ignoreInitial)) {
    if (!this._throttle('add', file, 0)) return;
    this._emit('add', file, stats);
  }
  if (callback) callback();
  return closer;
};
// Private method: Handle symlinks encountered while reading a dir
// * entry      - object, entry object returned by readdirp
// * directory  - string, path of the directory being read
// * path       - string, path of this item
// * item       - string, basename of this item
// Returns true if no more processing is needed for this entry.
NodeFsHandler.prototype._handleSymlink =
function(entry, directory, path, item) {
  var full = entry.fullPath;
  var dir = this._getWatchedDir(directory);
  if (!this.options.followSymlinks) {
    // watch symlink directly (don't follow) and detect changes
    this._readyCount++;
    fs.realpath(path, function(error, linkPath) {
      if (dir.has(item)) {
        if (this._symlinkPaths[full] !== linkPath) {
          this._symlinkPaths[full] = linkPath;
          this._emit('change', path, entry.stat);
        }
      } else {
        dir.add(item);
        this._symlinkPaths[full] = linkPath;
        this._emit('add', path, entry.stat);
      }
      this._emitReady();
    }.bind(this));
    return true;
  }
  // don't follow the same symlink more than once
  if (this._symlinkPaths[full]) return true;
  else this._symlinkPaths[full] = true;
}
// Private method: Read directory to add / remove files from `@watched` list
// and re-read it on change.
// * dir        - string, fs path.
// * stats      - object, result of fs.stat
// * initialAdd - boolean, was the file added at watch instantiation?
// * depth      - int, depth relative to user-supplied path
// * target     - string, child path actually targeted for watch
// * wh         - object, common watch helpers for this path
// * callback   - function, called when dir scan is complete
// Returns close function for the watcher instance
NodeFsHandler.prototype._handleDir =
function(dir, stats, initialAdd, depth, target, wh, callback) {
  if (!(initialAdd && this.options.ignoreInitial) && !target && !wh.hasGlob) {
    this._emit('addDir', dir, stats);
  }
  // ensure dir is tracked
  this._getWatchedDir(sysPath.dirname(dir)).add(sysPath.basename(dir));
  this._getWatchedDir(dir);
  var read = function(directory, initialAdd, done) {
    // Normalize the directory name on Windows
    directory = sysPath.join(directory, '');
    if (!wh.hasGlob) {
      var throttler = this._throttle('readdir', directory, 1000);
      if (!throttler) return;
    }
    var previous = this._getWatchedDir(wh.path);
    var current = [];
    readdirp({
      root: directory,
      entryType: 'all',
      fileFilter: wh.filterPath,
      directoryFilter: wh.filterDir,
      depth: 0,
      lstat: true
    }).on('data', function(entry) {
      var item = entry.path;
      var path = sysPath.join(directory, item);
      current.push(item);
      if (entry.stat.isSymbolicLink() &&
        this._handleSymlink(entry, directory, path, item)) return;
      // Files that present in current directory snapshot
      // but absent in previous are added to watch list and
      // emit `add` event.
      if (item === target || !target && !previous.has(item)) {
        this._readyCount++;
        // ensure relativeness of path is preserved in case of watcher reuse
        path = sysPath.join(dir, sysPath.relative(dir, path));
        this._addToNodeFs(path, initialAdd, wh, depth + 1);
      }
    }.bind(this)).on('end', function() {
      if (throttler) throttler.clear();
      if (done) done();
      // Files that absent in current directory snapshot
      // but present in previous emit `remove` event
      // and are removed from @watched[directory].
      previous.children().filter(function(item) {
        return item !== directory &&
          current.indexOf(item) === -1 &&
          // in case of intersecting globs;
          // a path may have been filtered out of this readdir, but
          // shouldn't be removed because it matches a different glob
          (!wh.hasGlob || wh.filterPath({
            fullPath: sysPath.resolve(directory, item)
          }));
      }).forEach(function(item) {
        this._remove(directory, item);
      }, this);
    }.bind(this)).on('error', this._handleError.bind(this));
  }.bind(this);
  if (this.options.depth == null || depth <= this.options.depth) {
    if (!target) read(dir, initialAdd, callback);
    var closer = this._watchWithNodeFs(dir, function(dirPath, stats) {
      // if current directory is removed, do nothing
      if (stats && stats.mtime.getTime() === 0) return;
      read(dirPath, false);
    });
  } else {
    callback();
  }
  return closer;
};
// Private method: Handle added file, directory, or glob pattern.
// Delegates call to _handleFile / _handleDir after checks.
// * path       - string, path to file or directory.
// * initialAdd - boolean, was the file added at watch instantiation?
// * depth      - int, depth relative to user-supplied path
// * target     - string, child path actually targeted for watch
// * callback   - function, indicates whether the path was found or not
// Returns nothing
NodeFsHandler.prototype._addToNodeFs =
function(path, initialAdd, priorWh, depth, target, callback) {
  if (!callback) callback = Function.prototype;
  var ready = this._emitReady;
  if (this._isIgnored(path) || this.closed) {
    ready();
    return callback(null, false);
  }
  var wh = this._getWatchHelpers(path, depth);
  if (!wh.hasGlob && priorWh) {
    wh.hasGlob = priorWh.hasGlob;
    wh.filterPath = priorWh.filterPath;
    wh.filterDir = priorWh.filterDir;
  }
  // evaluate what is at the path we're being asked to watch
  fs[wh.statMethod](wh.watchPath, function(error, stats) {
    if (this._handleError(error)) return callback(null, path);
    if (this._isIgnored(wh.watchPath, stats)) {
      ready();
      return callback(null, false);
    }
    var initDir = function(dir, target) {
      return this._handleDir(dir, stats, initialAdd, depth, target, wh, ready);
    }.bind(this);
    var closer;
    if (stats.isDirectory()) {
      closer = initDir(wh.watchPath, target);
    } else if (stats.isSymbolicLink()) {
      var parent = sysPath.dirname(wh.watchPath);
      this._getWatchedDir(parent).add(wh.watchPath);
      this._emit('add', wh.watchPath, stats);
      closer = initDir(parent, path);
      // preserve this symlink's target path
      fs.realpath(path, function(error, targetPath) {
        this._symlinkPaths[sysPath.resolve(path)] = targetPath;
        ready();
      }.bind(this));
    } else {
      closer = this._handleFile(wh.watchPath, stats, initialAdd, ready);
    }
    if (closer) this._closers[path] = closer;
    callback(null, false);
  }.bind(this));
};
module.exports = NodeFsHandler;

+ 1110 - 0
src/server/node_modules/commander/index.js

@ -0,0 +1,1110 @@
/**
 * Module dependencies.
 */
var EventEmitter = require('events').EventEmitter;
var spawn = require('child_process').spawn;
var readlink = require('graceful-readlink').readlinkSync;
var path = require('path');
var dirname = path.dirname;
var basename = path.basename;
var fs = require('fs');
/**
 * Expose the root command.
 */
exports = module.exports = new Command();
/**
 * Expose `Command`.
 */
exports.Command = Command;
/**
 * Expose `Option`.
 */
exports.Option = Option;
/**
 * Initialize a new `Option` with the given `flags` and `description`.
 *
 * @param {String} flags
 * @param {String} description
 * @api public
 */
function Option(flags, description) {
  this.flags = flags;
  this.required = ~flags.indexOf('<');
  this.optional = ~flags.indexOf('[');
  this.bool = !~flags.indexOf('-no-');
  flags = flags.split(/[ ,|]+/);
  if (flags.length > 1 && !/^[[<]/.test(flags[1])) this.short = flags.shift();
  this.long = flags.shift();
  this.description = description || '';
}
/**
 * Return option name.
 *
 * @return {String}
 * @api private
 */
Option.prototype.name = function() {
  return this.long
    .replace('--', '')
    .replace('no-', '');
};
/**
 * Check if `arg` matches the short or long flag.
 *
 * @param {String} arg
 * @return {Boolean}
 * @api private
 */
Option.prototype.is = function(arg) {
  return arg == this.short || arg == this.long;
};
/**
 * Initialize a new `Command`.
 *
 * @param {String} name
 * @api public
 */
function Command(name) {
  this.commands = [];
  this.options = [];
  this._execs = {};
  this._allowUnknownOption = false;
  this._args = [];
  this._name = name || '';
}
/**
 * Inherit from `EventEmitter.prototype`.
 */
Command.prototype.__proto__ = EventEmitter.prototype;
/**
 * Add command `name`.
 *
 * The `.action()` callback is invoked when the
 * command `name` is specified via __ARGV__,
 * and the remaining arguments are applied to the
 * function for access.
 *
 * When the `name` is "*" an un-matched command
 * will be passed as the first arg, followed by
 * the rest of __ARGV__ remaining.
 *
 * Examples:
 *
 *      program
 *        .version('0.0.1')
 *        .option('-C, --chdir <path>', 'change the working directory')
 *        .option('-c, --config <path>', 'set config path. defaults to ./deploy.conf')
 *        .option('-T, --no-tests', 'ignore test hook')
 *
 *      program
 *        .command('setup')
 *        .description('run remote setup commands')
 *        .action(function() {
 *          console.log('setup');
 *        });
 *
 *      program
 *        .command('exec <cmd>')
 *        .description('run the given remote command')
 *        .action(function(cmd) {
 *          console.log('exec "%s"', cmd);
 *        });
 *
 *      program
 *        .command('teardown <dir> [otherDirs...]')
 *        .description('run teardown commands')
 *        .action(function(dir, otherDirs) {
 *          console.log('dir "%s"', dir);
 *          if (otherDirs) {
 *            otherDirs.forEach(function (oDir) {
 *              console.log('dir "%s"', oDir);
 *            });
 *          }
 *        });
 *
 *      program
 *        .command('*')
 *        .description('deploy the given env')
 *        .action(function(env) {
 *          console.log('deploying "%s"', env);
 *        });
 *
 *      program.parse(process.argv);
  *
 * @param {String} name
 * @param {String} [desc] for git-style sub-commands
 * @return {Command} the new command
 * @api public
 */
Command.prototype.command = function(name, desc, opts) {
  opts = opts || {};
  var args = name.split(/ +/);
  var cmd = new Command(args.shift());
  if (desc) {
    cmd.description(desc);
    this.executables = true;
    this._execs[cmd._name] = true;
    if (opts.isDefault) this.defaultExecutable = cmd._name;
  }
  cmd._noHelp = !!opts.noHelp;
  this.commands.push(cmd);
  cmd.parseExpectedArgs(args);
  cmd.parent = this;
  if (desc) return this;
  return cmd;
};
/**
 * Define argument syntax for the top-level command.
 *
 * @api public
 */
Command.prototype.arguments = function (desc) {
  return this.parseExpectedArgs(desc.split(/ +/));
};
/**
 * Add an implicit `help [cmd]` subcommand
 * which invokes `--help` for the given command.
 *
 * @api private
 */
Command.prototype.addImplicitHelpCommand = function() {
  this.command('help [cmd]', 'display help for [cmd]');
};
/**
 * Parse expected `args`.
 *
 * For example `["[type]"]` becomes `[{ required: false, name: 'type' }]`.
 *
 * @param {Array} args
 * @return {Command} for chaining
 * @api public
 */
Command.prototype.parseExpectedArgs = function(args) {
  if (!args.length) return;
  var self = this;
  args.forEach(function(arg) {
    var argDetails = {
      required: false,
      name: '',
      variadic: false
    };
    switch (arg[0]) {
      case '<':
        argDetails.required = true;
        argDetails.name = arg.slice(1, -1);
        break;
      case '[':
        argDetails.name = arg.slice(1, -1);
        break;
    }
    if (argDetails.name.length > 3 && argDetails.name.slice(-3) === '...') {
      argDetails.variadic = true;
      argDetails.name = argDetails.name.slice(0, -3);
    }
    if (argDetails.name) {
      self._args.push(argDetails);
    }
  });
  return this;
};
/**
 * Register callback `fn` for the command.
 *
 * Examples:
 *
 *      program
 *        .command('help')
 *        .description('display verbose help')
 *        .action(function() {
 *           // output help here
 *        });
 *
 * @param {Function} fn
 * @return {Command} for chaining
 * @api public
 */
Command.prototype.action = function(fn) {
  var self = this;
  var listener = function(args, unknown) {
    // Parse any so-far unknown options
    args = args || [];
    unknown = unknown || [];
    var parsed = self.parseOptions(unknown);
    // Output help if necessary
    outputHelpIfNecessary(self, parsed.unknown);
    // If there are still any unknown options, then we simply
    // die, unless someone asked for help, in which case we give it
    // to them, and then we die.
    if (parsed.unknown.length > 0) {
      self.unknownOption(parsed.unknown[0]);
    }
    // Leftover arguments need to be pushed back. Fixes issue #56
    if (parsed.args.length) args = parsed.args.concat(args);
    self._args.forEach(function(arg, i) {
      if (arg.required && null == args[i]) {
        self.missingArgument(arg.name);
      } else if (arg.variadic) {
        if (i !== self._args.length - 1) {
          self.variadicArgNotLast(arg.name);
        }
        args[i] = args.splice(i);
      }
    });
    // Always append ourselves to the end of the arguments,
    // to make sure we match the number of arguments the user
    // expects
    if (self._args.length) {
      args[self._args.length] = self;
    } else {
      args.push(self);
    }
    fn.apply(self, args);
  };
  var parent = this.parent || this;
  var name = parent === this ? '*' : this._name;
  parent.on(name, listener);
  if (this._alias) parent.on(this._alias, listener);
  return this;
};
/**
 * Define option with `flags`, `description` and optional
 * coercion `fn`.
 *
 * The `flags` string should contain both the short and long flags,
 * separated by comma, a pipe or space. The following are all valid
 * all will output this way when `--help` is used.
 *
 *    "-p, --pepper"
 *    "-p|--pepper"
 *    "-p --pepper"
 *
 * Examples:
 *
 *     // simple boolean defaulting to false
 *     program.option('-p, --pepper', 'add pepper');
 *
 *     --pepper
 *     program.pepper
 *     // => Boolean
 *
 *     // simple boolean defaulting to true
 *     program.option('-C, --no-cheese', 'remove cheese');
 *
 *     program.cheese
 *     // => true
 *
 *     --no-cheese
 *     program.cheese
 *     // => false
 *
 *     // required argument
 *     program.option('-C, --chdir <path>', 'change the working directory');
 *
 *     --chdir /tmp
 *     program.chdir
 *     // => "/tmp"
 *
 *     // optional argument
 *     program.option('-c, --cheese [type]', 'add cheese [marble]');
 *
 * @param {String} flags
 * @param {String} description
 * @param {Function|Mixed} fn or default
 * @param {Mixed} defaultValue
 * @return {Command} for chaining
 * @api public
 */
Command.prototype.option = function(flags, description, fn, defaultValue) {
  var self = this
    , option = new Option(flags, description)
    , oname = option.name()
    , name = camelcase(oname);
  // default as 3rd arg
  if (typeof fn != 'function') {
    if (fn instanceof RegExp) {
      var regex = fn;
      fn = function(val, def) {
        var m = regex.exec(val);
        return m ? m[0] : def;
      }
    }
    else {
      defaultValue = fn;
      fn = null;
    }
  }
  // preassign default value only for --no-*, [optional], or <required>
  if (false == option.bool || option.optional || option.required) {
    // when --no-* we make sure default is true
    if (false == option.bool) defaultValue = true;
    // preassign only if we have a default
    if (undefined !== defaultValue) self[name] = defaultValue;
  }
  // register the option
  this.options.push(option);
  // when it's passed assign the value
  // and conditionally invoke the callback
  this.on(oname, function(val) {
    // coercion
    if (null !== val && fn) val = fn(val, undefined === self[name]
      ? defaultValue
      : self[name]);
    // unassigned or bool
    if ('boolean' == typeof self[name] || 'undefined' == typeof self[name]) {
      // if no value, bool true, and we have a default, then use it!
      if (null == val) {
        self[name] = option.bool
          ? defaultValue || true
          : false;
      } else {
        self[name] = val;
      }
    } else if (null !== val) {
      // reassign
      self[name] = val;
    }
  });
  return this;
};
/**
 * Allow unknown options on the command line.
 *
 * @param {Boolean} arg if `true` or omitted, no error will be thrown
 * for unknown options.
 * @api public
 */
Command.prototype.allowUnknownOption = function(arg) {
    this._allowUnknownOption = arguments.length === 0 || arg;
    return this;
};
/**
 * Parse `argv`, settings options and invoking commands when defined.
 *
 * @param {Array} argv
 * @return {Command} for chaining
 * @api public
 */
Command.prototype.parse = function(argv) {
  // implicit help
  if (this.executables) this.addImplicitHelpCommand();
  // store raw args
  this.rawArgs = argv;
  // guess name
  this._name = this._name || basename(argv[1], '.js');
  // github-style sub-commands with no sub-command
  if (this.executables && argv.length < 3 && !this.defaultExecutable) {
    // this user needs help
    argv.push('--help');
  }
  // process argv
  var parsed = this.parseOptions(this.normalize(argv.slice(2)));
  var args = this.args = parsed.args;
  var result = this.parseArgs(this.args, parsed.unknown);
  // executable sub-commands
  var name = result.args[0];
  if (this._execs[name] && typeof this._execs[name] != "function") {
    return this.executeSubCommand(argv, args, parsed.unknown);
  } else if (this.defaultExecutable) {
    // use the default subcommand
    args.unshift(name = this.defaultExecutable);
    return this.executeSubCommand(argv, args, parsed.unknown);
  }
  return result;
};
/**
 * Execute a sub-command executable.
 *
 * @param {Array} argv
 * @param {Array} args
 * @param {Array} unknown
 * @api private
 */
Command.prototype.executeSubCommand = function(argv, args, unknown) {
  args = args.concat(unknown);
  if (!args.length) this.help();
  if ('help' == args[0] && 1 == args.length) this.help();
  // <cmd> --help
  if ('help' == args[0]) {
    args[0] = args[1];
    args[1] = '--help';
  }
  // executable
  var f = argv[1];
  // name of the subcommand, link `pm-install`
  var bin = basename(f, '.js') + '-' + args[0];
  // In case of globally installed, get the base dir where executable
  //  subcommand file should be located at
  var baseDir
    , link = readlink(f);
  // when symbolink is relative path
  if (link !== f && link.charAt(0) !== '/') {
    link = path.join(dirname(f), link)
  }
  baseDir = dirname(link);
  // prefer local `./<bin>` to bin in the $PATH
  var localBin = path.join(baseDir, bin);
  // whether bin file is a js script with explicit `.js` extension
  var isExplicitJS = false;
  if (exists(localBin + '.js')) {
    bin = localBin + '.js';
    isExplicitJS = true;
  } else if (exists(localBin)) {
    bin = localBin;
  }
  args = args.slice(1);
  var proc;
  if (process.platform !== 'win32') {
    if (isExplicitJS) {
      args.unshift(localBin);
      // add executable arguments to spawn
      args = (process.execArgv || []).concat(args);
      proc = spawn('node', args, { stdio: 'inherit', customFds: [0, 1, 2] });
    } else {
      proc = spawn(bin, args, { stdio: 'inherit', customFds: [0, 1, 2] });
    }
  } else {
    args.unshift(localBin);
    proc = spawn(process.execPath, args, { stdio: 'inherit'});
  }
  proc.on('close', process.exit.bind(process));
  proc.on('error', function(err) {
    if (err.code == "ENOENT") {
      console.error('\n  %s(1) does not exist, try --help\n', bin);
    } else if (err.code == "EACCES") {
      console.error('\n  %s(1) not executable. try chmod or run with root\n', bin);
    }
    process.exit(1);
  });
  // Store the reference to the child process
  this.runningCommand = proc;
};
/**
 * Normalize `args`, splitting joined short flags. For example
 * the arg "-abc" is equivalent to "-a -b -c".
 * This also normalizes equal sign and splits "--abc=def" into "--abc def".
 *
 * @param {Array} args
 * @return {Array}
 * @api private
 */
Command.prototype.normalize = function(args) {
  var ret = []
    , arg
    , lastOpt
    , index;
  for (var i = 0, len = args.length; i < len; ++i) {
    arg = args[i];
    if (i > 0) {
      lastOpt = this.optionFor(args[i-1]);
    }
    if (arg === '--') {
      // Honor option terminator
      ret = ret.concat(args.slice(i));
      break;
    } else if (lastOpt && lastOpt.required) {
      ret.push(arg);
    } else if (arg.length > 1 && '-' == arg[0] && '-' != arg[1]) {
      arg.slice(1).split('').forEach(function(c) {
        ret.push('-' + c);
      });
    } else if (/^--/.test(arg) && ~(index = arg.indexOf('='))) {
      ret.push(arg.slice(0, index), arg.slice(index + 1));
    } else {
      ret.push(arg);
    }
  }
  return ret;
};
/**
 * Parse command `args`.
 *
 * When listener(s) are available those
 * callbacks are invoked, otherwise the "*"
 * event is emitted and those actions are invoked.
 *
 * @param {Array} args
 * @return {Command} for chaining
 * @api private
 */
Command.prototype.parseArgs = function(args, unknown) {
  var name;
  if (args.length) {
    name = args[0];
    if (this.listeners(name).length) {
      this.emit(args.shift(), args, unknown);
    } else {
      this.emit('*', args);
    }
  } else {
    outputHelpIfNecessary(this, unknown);
    // If there were no args and we have unknown options,
    // then they are extraneous and we need to error.
    if (unknown.length > 0) {
      this.unknownOption(unknown[0]);
    }
  }
  return this;
};
/**
 * Return an option matching `arg` if any.
 *
 * @param {String} arg
 * @return {Option}
 * @api private
 */
Command.prototype.optionFor = function(arg) {
  for (var i = 0, len = this.options.length; i < len; ++i) {
    if (this.options[i].is(arg)) {
      return this.options[i];
    }
  }
};
/**
 * Parse options from `argv` returning `argv`
 * void of these options.
 *
 * @param {Array} argv
 * @return {Array}
 * @api public
 */
Command.prototype.parseOptions = function(argv) {
  var args = []
    , len = argv.length
    , literal
    , option
    , arg;
  var unknownOptions = [];
  // parse options
  for (var i = 0; i < len; ++i) {
    arg = argv[i];
    // literal args after --
    if ('--' == arg) {
      literal = true;
      continue;
    }
    if (literal) {
      args.push(arg);
      continue;
    }
    // find matching Option
    option = this.optionFor(arg);
    // option is defined
    if (option) {
      // requires arg
      if (option.required) {
        arg = argv[++i];
        if (null == arg) return this.optionMissingArgument(option);
        this.emit(option.name(), arg);
      // optional arg
      } else if (option.optional) {
        arg = argv[i+1];
        if (null == arg || ('-' == arg[0] && '-' != arg)) {
          arg = null;
        } else {
          ++i;
        }
        this.emit(option.name(), arg);
      // bool
      } else {
        this.emit(option.name());
      }
      continue;
    }
    // looks like an option
    if (arg.length > 1 && '-' == arg[0]) {
      unknownOptions.push(arg);
      // If the next argument looks like it might be
      // an argument for this option, we pass it on.
      // If it isn't, then it'll simply be ignored
      if (argv[i+1] && '-' != argv[i+1][0]) {
        unknownOptions.push(argv[++i]);
      }
      continue;
    }
    // arg
    args.push(arg);
  }
  return { args: args, unknown: unknownOptions };
};
/**
 * Return an object containing options as key-value pairs
 *
 * @return {Object}
 * @api public
 */
Command.prototype.opts = function() {
  var result = {}
    , len = this.options.length;
  for (var i = 0 ; i < len; i++) {
    var key = camelcase(this.options[i].name());
    result[key] = key === 'version' ? this._version : this[key];
  }
  return result;
};
/**
 * Argument `name` is missing.
 *
 * @param {String} name
 * @api private
 */
Command.prototype.missingArgument = function(name) {
  console.error();
  console.error("  error: missing required argument `%s'", name);
  console.error();
  process.exit(1);
};
/**
 * `Option` is missing an argument, but received `flag` or nothing.
 *
 * @param {String} option
 * @param {String} flag
 * @api private
 */
Command.prototype.optionMissingArgument = function(option, flag) {
  console.error();
  if (flag) {
    console.error("  error: option `%s' argument missing, got `%s'", option.flags, flag);
  } else {
    console.error("  error: option `%s' argument missing", option.flags);
  }
  console.error();
  process.exit(1);
};
/**
 * Unknown option `flag`.
 *
 * @param {String} flag
 * @api private
 */
Command.prototype.unknownOption = function(flag) {
  if (this._allowUnknownOption) return;
  console.error();
  console.error("  error: unknown option `%s'", flag);
  console.error();
  process.exit(1);
};
/**
 * Variadic argument with `name` is not the last argument as required.
 *
 * @param {String} name
 * @api private
 */
Command.prototype.variadicArgNotLast = function(name) {
  console.error();
  console.error("  error: variadic arguments must be last `%s'", name);
  console.error();
  process.exit(1);
};
/**
 * Set the program version to `str`.
 *
 * This method auto-registers the "-V, --version" flag
 * which will print the version number when passed.
 *
 * @param {String} str
 * @param {String} flags
 * @return {Command} for chaining
 * @api public
 */
Command.prototype.version = function(str, flags) {
  if (0 == arguments.length) return this._version;
  this._version = str;
  flags = flags || '-V, --version';
  this.option(flags, 'output the version number');
  this.on('version', function() {
    process.stdout.write(str + '\n');
    process.exit(0);
  });
  return this;
};
/**
 * Set the description to `str`.
 *
 * @param {String} str
 * @return {String|Command}
 * @api public
 */
Command.prototype.description = function(str) {
  if (0 === arguments.length) return this._description;
  this._description = str;
  return this;
};
/**
 * Set an alias for the command
 *
 * @param {String} alias
 * @return {String|Command}
 * @api public
 */
Command.prototype.alias = function(alias) {
  if (0 == arguments.length) return this._alias;
  this._alias = alias;
  return this;
};
/**
 * Set / get the command usage `str`.
 *
 * @param {String} str
 * @return {String|Command}
 * @api public
 */
Command.prototype.usage = function(str) {
  var args = this._args.map(function(arg) {
    return humanReadableArgName(arg);
  });
  var usage = '[options]'
    + (this.commands.length ? ' [command]' : '')
    + (this._args.length ? ' ' + args.join(' ') : '');
  if (0 == arguments.length) return this._usage || usage;
  this._usage = str;
  return this;
};
/**
 * Get the name of the command
 *
 * @param {String} name
 * @return {String|Command}
 * @api public
 */
Command.prototype.name = function() {
  return this._name;
};
/**
 * Return the largest option length.
 *
 * @return {Number}
 * @api private
 */
Command.prototype.largestOptionLength = function() {
  return this.options.reduce(function(max, option) {
    return Math.max(max, option.flags.length);
  }, 0);
};
/**
 * Return help for options.
 *
 * @return {String}
 * @api private
 */
Command.prototype.optionHelp = function() {
  var width = this.largestOptionLength();
  // Prepend the help information
  return [pad('-h, --help', width) + '  ' + 'output usage information']
      .concat(this.options.map(function(option) {
        return pad(option.flags, width) + '  ' + option.description;
      }))
      .join('\n');
};
/**
 * Return command help documentation.
 *
 * @return {String}
 * @api private
 */
Command.prototype.commandHelp = function() {
  if (!this.commands.length) return '';
  var commands = this.commands.filter(function(cmd) {
    return !cmd._noHelp;
  }).map(function(cmd) {
    var args = cmd._args.map(function(arg) {
      return humanReadableArgName(arg);
    }).join(' ');
    return [
      cmd._name
        + (cmd._alias ? '|' + cmd._alias : '')
        + (cmd.options.length ? ' [options]' : '')
        + ' ' + args
      , cmd.description()
    ];
  });
  var width = commands.reduce(function(max, command) {
    return Math.max(max, command[0].length);
  }, 0);
  return [
    ''
    , '  Commands:'
    , ''
    , commands.map(function(cmd) {
      var desc = cmd[1] ? '  ' + cmd[1] : '';
      return pad(cmd[0], width) + desc;
    }).join('\n').replace(/^/gm, '    ')
    , ''
  ].join('\n');
};
/**
 * Return program help documentation.
 *
 * @return {String}
 * @api private
 */
Command.prototype.helpInformation = function() {
  var desc = [];
  if (this._description) {
    desc = [
      '  ' + this._description
      , ''
    ];
  }
  var cmdName = this._name;
  if (this._alias) {
    cmdName = cmdName + '|' + this._alias;
  }
  var usage = [
    ''
    ,'  Usage: ' + cmdName + ' ' + this.usage()
    , ''
  ];
  var cmds = [];
  var commandHelp = this.commandHelp();
  if (commandHelp) cmds = [commandHelp];
  var options = [
    '  Options:'
    , ''
    , '' + this.optionHelp().replace(/^/gm, '    ')
    , ''
    , ''
  ];
  return usage
    .concat(cmds)
    .concat(desc)
    .concat(options)
    .join('\n');
};
/**
 * Output help information for this command
 *
 * @api public
 */
Command.prototype.outputHelp = function(cb) {
  if (!cb) {
    cb = function(passthru) {
      return passthru;
    }
  }
  process.stdout.write(cb(this.helpInformation()));
  this.emit('--help');
};
/**
 * Output help information and exit.
 *
 * @api public
 */
Command.prototype.help = function(cb) {
  this.outputHelp(cb);
  process.exit();
};
/**
 * Camel-case the given `flag`
 *
 * @param {String} flag
 * @return {String}
 * @api private
 */
function camelcase(flag) {
  return flag.split('-').reduce(function(str, word) {
    return str + word[0].toUpperCase() + word.slice(1);
  });
}
/**
 * Pad `str` to `width`.
 *
 * @param {String} str
 * @param {Number} width
 * @return {String}
 * @api private
 */
function pad(str, width) {
  var len = Math.max(0, width - str.length);
  return str + Array(len + 1).join(' ');
}
/**
 * Output help information if necessary
 *
 * @param {Command} command to output help for
 * @param {Array} array of options to search for -h or --help
 * @api private
 */
function outputHelpIfNecessary(cmd, options) {
  options = options || [];
  for (var i = 0; i < options.length; i++) {
    if (options[i] == '--help' || options[i] == '-h') {
      cmd.outputHelp();
      process.exit(0);
    }
  }
}
/**
 * Takes an argument an returns its human readable equivalent for help usage.
 *
 * @param {Object} arg
 * @return {String}
 * @api private
 */
function humanReadableArgName(arg) {
  var nameOutput = arg.name + (arg.variadic === true ? '...' : '');
  return arg.required
    ? '<' + nameOutput + '>'
    : '[' + nameOutput + ']'
}
// for versions before node v0.8 when there weren't `fs.existsSync`
function exists(file) {
  try {
    if (fs.statSync(file).isFile()) {
      return true;
    }
  } catch (e) {
    return false;
  }
}

test/server/node_modules/mongoose/node_modules/mongodb/node_modules/readable-stream/node_modules/core-util-is/lib/util.js → src/server/node_modules/core-util-is/lib/util.js


test/server/node_modules/mongoose/node_modules/mongodb/node_modules/readable-stream/node_modules/core-util-is/test.js → src/server/node_modules/core-util-is/test.js


+ 163 - 0
src/server/node_modules/expand-brackets/index.js

@ -0,0 +1,163 @@
/*!
 * expand-brackets <https://github.com/jonschlinkert/expand-brackets>
 *
 * Copyright (c) 2015 Jon Schlinkert.
 * Licensed under the MIT license.
 */
'use strict';
var isPosixBracket = require('is-posix-bracket');
/**
 * POSIX character classes
 */
var POSIX = {
  alnum: 'a-zA-Z0-9',
  alpha: 'a-zA-Z',
  blank: ' \\t',
  cntrl: '\\x00-\\x1F\\x7F',
  digit: '0-9',
  graph: '\\x21-\\x7E',
  lower: 'a-z',
  print: '\\x20-\\x7E',
  punct: '-!"#$%&\'()\\*+,./:;<=>?@[\\]^_`{|}~',
  space: ' \\t\\r\\n\\v\\f',
  upper: 'A-Z',
  word:  'A-Za-z0-9_',
  xdigit: 'A-Fa-f0-9',
};
/**
 * Expose `brackets`
 */
module.exports = brackets;
function brackets(str) {
  if (!isPosixBracket(str)) {
    return str;
  }
  var negated = false;
  if (str.indexOf('[^') !== -1) {
    negated = true;
    str = str.split('[^').join('[');
  }
  if (str.indexOf('[!') !== -1) {
    negated = true;
    str = str.split('[!').join('[');
  }
  var a = str.split('[');
  var b = str.split(']');
  var imbalanced = a.length !== b.length;
  var parts = str.split(/(?::\]\[:|\[?\[:|:\]\]?)/);
  var len = parts.length, i = 0;
  var end = '', beg = '';
  var res = [];
  // start at the end (innermost) first
  while (len--) {
    var inner = parts[i++];
    if (inner === '^[!' || inner === '[!') {
      inner = '';
      negated = true;
    }
    var prefix = negated ? '^' : '';
    var ch = POSIX[inner];
    if (ch) {
      res.push('[' + prefix + ch + ']');
    } else if (inner) {
      if (/^\[?\w-\w\]?$/.test(inner)) {
        if (i === parts.length) {
          res.push('[' + prefix + inner);
        } else if (i === 1) {
          res.push(prefix + inner + ']');
        } else {
          res.push(prefix + inner);
        }
      } else {
        if (i === 1) {
          beg += inner;
        } else if (i === parts.length) {
          end += inner;
        } else {
          res.push('[' + prefix + inner + ']');
        }
      }
    }
  }
  var result = res.join('|');
  var rlen = res.length || 1;
  if (rlen > 1) {
    result = '(?:' + result + ')';
    rlen = 1;
  }
  if (beg) {
    rlen++;
    if (beg.charAt(0) === '[') {
      if (imbalanced) {
        beg = '\\[' + beg.slice(1);
      } else {
        beg += ']';
      }
    }
    result = beg + result;
  }
  if (end) {
    rlen++;
    if (end.slice(-1) === ']') {
      if (imbalanced) {
        end = end.slice(0, end.length - 1) + '\\]';
      } else {
        end = '[' + end;
      }
    }
    result += end;
  }
  if (rlen > 1) {
    result = result.split('][').join(']|[');
    if (result.indexOf('|') !== -1 && !/\(\?/.test(result)) {
      result = '(?:' + result + ')';
    }
  }
  result = result.replace(/\[+=|=\]+/g, '\\b');
  return result;
}
brackets.makeRe = function(pattern) {
  try {
    return new RegExp(brackets(pattern));
  } catch (err) {}
};
brackets.isMatch = function(str, pattern) {
  try {
    return brackets.makeRe(pattern).test(str);
  } catch (err) {
    return false;
  }
};
brackets.match = function(arr, pattern) {
  var len = arr.length, i = 0;
  var res = arr.slice();
  var re = brackets.makeRe(pattern);
  while (i < len) {
    var ele = arr[i++];
    if (!re.test(ele)) {
      continue;
    }
    res.splice(i, 1);
  }
  return res;
};

+ 43 - 0
src/server/node_modules/expand-range/index.js

@ -0,0 +1,43 @@
/*!
 * expand-range <https://github.com/jonschlinkert/expand-range>
 *
 * Copyright (c) 2014-2015, Jon Schlinkert.
 * Licensed under the MIT license.
 */
'use strict';
var fill = require('fill-range');
module.exports = function expandRange(str, options, fn) {
  if (typeof str !== 'string') {
    throw new TypeError('expand-range expects a string.');
  }
  if (typeof options === 'function') {
    fn = options;
    options = {};
  }
  if (typeof options === 'boolean') {
    options = {};
    options.makeRe = true;
  }
  // create arguments to pass to fill-range
  var opts = options || {};
  var args = str.split('..');
  var len = args.length;
  if (len > 3) { return str; }
  // if only one argument, it can't expand so return it
  if (len === 1) { return args; }
  // if `true`, tell fill-range to regexify the string
  if (typeof fn === 'boolean' && fn === true) {
    opts.makeRe = true;
  }
  args.push(opts);
  return fill.apply(null, args.concat(fn));
};

+ 178 - 0
src/server/node_modules/extglob/index.js

@ -0,0 +1,178 @@
/*!
 * extglob <https://github.com/jonschlinkert/extglob>
 *
 * Copyright (c) 2015, Jon Schlinkert.
 * Licensed under the MIT License.
 */
'use strict';
/**
 * Module dependencies
 */
var isExtglob = require('is-extglob');
var re, cache = {};
/**
 * Expose `extglob`
 */
module.exports = extglob;
/**
 * Convert the given extglob `string` to a regex-compatible
 * string.
 *
 * ```js
 * var extglob = require('extglob');
 * extglob('!(a?(b))');
 * //=> '(?!a(?:b)?)[^/]*?'
 * ```
 *
 * @param {String} `str` The string to convert.
 * @param {Object} `options`
 *   @option {Boolean} [options] `esc` If `false` special characters will not be escaped. Defaults to `true`.
 *   @option {Boolean} [options] `regex` If `true` a regular expression is returned instead of a string.
 * @return {String}
 * @api public
 */
function extglob(str, opts) {
  opts = opts || {};
  var o = {}, i = 0;
  // fix common character reversals
  // '*!(.js)' => '*.!(js)'
  str = str.replace(/!\(([^\w*()])/g, '$1!(');
  // support file extension negation
  str = str.replace(/([*\/])\.!\([*]\)/g, function (m, ch) {
    if (ch === '/') {
      return escape('\\/[^.]+');
    }
    return escape('[^.]+');
  });
  // create a unique key for caching by
  // combining the string and options
  var key = str
    + String(!!opts.regex)
    + String(!!opts.contains)
    + String(!!opts.escape);
  if (cache.hasOwnProperty(key)) {
    return cache[key];
  }
  if (!(re instanceof RegExp)) {
    re = regex();
  }
  opts.negate = false;
  var m;
  while (m = re.exec(str)) {
    var prefix = m[1];
    var inner = m[3];
    if (prefix === '!') {
      opts.negate = true;
    }
    var id = '__EXTGLOB_' + (i++) + '__';
    // use the prefix of the _last_ (outtermost) pattern
    o[id] = wrap(inner, prefix, opts.escape);
    str = str.split(m[0]).join(id);
  }
  var keys = Object.keys(o);
  var len = keys.length;
  // we have to loop again to allow us to convert
  // patterns in reverse order (starting with the
  // innermost/last pattern first)
  while (len--) {
    var prop = keys[len];
    str = str.split(prop).join(o[prop]);
  }
  var result = opts.regex
    ? toRegex(str, opts.contains, opts.negate)
    : str;
  result = result.split('.').join('\\.');
  // cache the result and return it
  return (cache[key] = result);
}
/**
 * Convert `string` to a regex string.
 *
 * @param  {String} `str`
 * @param  {String} `prefix` Character that determines how to wrap the string.
 * @param  {Boolean} `esc` If `false` special characters will not be escaped. Defaults to `true`.
 * @return {String}
 */
function wrap(inner, prefix, esc) {
  if (esc) inner = escape(inner);
  switch (prefix) {
    case '!':
      return '(?!' + inner + ')[^/]' + (esc ? '%%%~' : '*?');
    case '@':
      return '(?:' + inner + ')';
    case '+':
      return '(?:' + inner + ')+';
    case '*':
      return '(?:' + inner + ')' + (esc ? '%%' : '*')
    case '?':
      return '(?:' + inner + '|)';
    default:
      return inner;
  }
}
function escape(str) {
  str = str.split('*').join('[^/]%%%~');
  str = str.split('.').join('\\.');
  return str;
}
/**
 * extglob regex.
 */
function regex() {
  return /(\\?[@?!+*$]\\?)(\(([^()]*?)\))/;
}
/**
 * Negation regex
 */
function negate(str) {
  return '(?!^' + str + ').*$';
}
/**
 * Create the regex to do the matching. If
 * the leading character in the `pattern` is `!`
 * a negation regex is returned.
 *
 * @param {String} `pattern`
 * @param {Boolean} `contains` Allow loose matching.
 * @param {Boolean} `isNegated` True if the pattern is a negation pattern.
 */
function toRegex(pattern, contains, isNegated) {
  var prefix = contains ? '^' : '';
  var after = contains ? '$' : '';
  pattern = ('(?:' + pattern + ')' + after);
  if (isNegated) {
    pattern = prefix + negate(pattern);
  }
  return new RegExp(prefix + pattern);
}

+ 10 - 0
src/server/node_modules/filename-regex/index.js

@ -0,0 +1,10 @@
/*!
 * filename-regex <https://github.com/regexps/filename-regex>
 *
 * Copyright (c) 2014-2015, Jon Schlinkert
 * Licensed under the MIT license.
 */
module.exports = function filenameRegex() {
  return /([^\\\/]+)$/;
};

+ 408 - 0
src/server/node_modules/fill-range/index.js

@ -0,0 +1,408 @@
/*!
 * fill-range <https://github.com/jonschlinkert/fill-range>
 *
 * Copyright (c) 2014-2015, Jon Schlinkert.
 * Licensed under the MIT License.
 */
'use strict';
var isObject = require('isobject');
var isNumber = require('is-number');
var randomize = require('randomatic');
var repeatStr = require('repeat-string');
var repeat = require('repeat-element');
/**
 * Expose `fillRange`
 */
module.exports = fillRange;
/**
 * Return a range of numbers or letters.
 *
 * @param  {String} `a` Start of the range
 * @param  {String} `b` End of the range
 * @param  {String} `step` Increment or decrement to use.
 * @param  {Function} `fn` Custom function to modify each element in the range.
 * @return {Array}
 */
function fillRange(a, b, step, options, fn) {
  if (a == null || b == null) {
    throw new Error('fill-range expects the first and second args to be strings.');
  }
  if (typeof step === 'function') {
    fn = step; options = {}; step = null;
  }
  if (typeof options === 'function') {
    fn = options; options = {};
  }
  if (isObject(step)) {
    options = step; step = '';
  }
  var expand, regex = false, sep = '';
  var opts = options || {};
  if (typeof opts.silent === 'undefined') {
    opts.silent = true;
  }
  step = step || opts.step;
  // store a ref to unmodified arg
  var origA = a, origB = b;
  b = (b.toString() === '-0') ? 0 : b;
  if (opts.optimize || opts.makeRe) {
    step = step ? (step += '~') : step;
    expand = true;
    regex = true;
    sep = '~';
  }
  // handle special step characters
  if (typeof step === 'string') {
    var match = stepRe().exec(step);
    if (match) {
      var i = match.index;
      var m = match[0];
      // repeat string
      if (m === '+') {
        return repeat(a, b);
      // randomize a, `b` times
      } else if (m === '?') {
        return [randomize(a, b)];
      // expand right, no regex reduction
      } else if (m === '>') {
        step = step.substr(0, i) + step.substr(i + 1);
        expand = true;
      // expand to an array, or if valid create a reduced
      // string for a regex logic `or`
      } else if (m === '|') {
        step = step.substr(0, i) + step.substr(i + 1);
        expand = true;
        regex = true;
        sep = m;
      // expand to an array, or if valid create a reduced
      // string for a regex range
      } else if (m === '~') {
        step = step.substr(0, i) + step.substr(i + 1);
        expand = true;
        regex = true;
        sep = m;
      }
    } else if (!isNumber(step)) {
      if (!opts.silent) {
        throw new TypeError('fill-range: invalid step.');
      }
      return null;
    }
  }
  if (/[.&*()[\]^%$#@!]/.test(a) || /[.&*()[\]^%$#@!]/.test(b)) {
    if (!opts.silent) {
      throw new RangeError('fill-range: invalid range arguments.');
    }
    return null;
  }
  // has neither a letter nor number, or has both letters and numbers
  // this needs to be after the step logic
  if (!noAlphaNum(a) || !noAlphaNum(b) || hasBoth(a) || hasBoth(b)) {
    if (!opts.silent) {
      throw new RangeError('fill-range: invalid range arguments.');
    }
    return null;
  }
  // validate arguments
  var isNumA = isNumber(zeros(a));
  var isNumB = isNumber(zeros(b));
  if ((!isNumA && isNumB) || (isNumA && !isNumB)) {
    if (!opts.silent) {
      throw new TypeError('fill-range: first range argument is incompatible with second.');
    }
    return null;
  }
  // by this point both are the same, so we
  // can use A to check going forward.
  var isNum = isNumA;
  var num = formatStep(step);
  // is the range alphabetical? or numeric?
  if (isNum) {
    // if numeric, coerce to an integer
    a = +a; b = +b;
  } else {
    // otherwise, get the charCode to expand alpha ranges
    a = a.charCodeAt(0);
    b = b.charCodeAt(0);
  }
  // is the pattern descending?
  var isDescending = a > b;
  // don't create a character class if the args are < 0
  if (a < 0 || b < 0) {
    expand = false;
    regex = false;
  }
  // detect padding
  var padding = isPadded(origA, origB);
  var res, pad, arr = [];
  var ii = 0;
  // character classes, ranges and logical `or`
  if (regex) {
    if (shouldExpand(a, b, num, isNum, padding, opts)) {
      // make sure the correct separator is used
      if (sep === '|' || sep === '~') {
        sep = detectSeparator(a, b, num, isNum, isDescending);
      }
      return wrap([origA, origB], sep, opts);
    }
  }
  while (isDescending ? (a >= b) : (a <= b)) {
    if (padding && isNum) {
      pad = padding(a);
    }
    // custom function
    if (typeof fn === 'function') {
      res = fn(a, isNum, pad, ii++);
    // letters
    } else if (!isNum) {
      if (regex && isInvalidChar(a)) {
        res = null;
      } else {
        res = String.fromCharCode(a);
      }
    // numbers
    } else {
      res = formatPadding(a, pad);
    }
    // add result to the array, filtering any nulled values
    if (res !== null) arr.push(res);
    // increment or decrement
    if (isDescending) {
      a -= num;
    } else {
      a += num;
    }
  }
  // now that the array is expanded, we need to handle regex
  // character classes, ranges or logical `or` that wasn't
  // already handled before the loop
  if ((regex || expand) && !opts.noexpand) {
    // make sure the correct separator is used
    if (sep === '|' || sep === '~') {
      sep = detectSeparator(a, b, num, isNum, isDescending);
    }
    if (arr.length === 1 || a < 0 || b < 0) { return arr; }
    return wrap(arr, sep, opts);
  }
  return arr;
}
/**
 * Wrap the string with the correct regex
 * syntax.
 */
function wrap(arr, sep, opts) {
  if (sep === '~') { sep = '-'; }
  var str = arr.join(sep);
  var pre = opts && opts.regexPrefix;
  // regex logical `or`
  if (sep === '|') {
    str = pre ? pre + str : str;
    str = '(' + str + ')';
  }
  // regex character class
  if (sep === '-') {
    str = (pre && pre === '^')
      ? pre + str
      : str;
    str = '[' + str + ']';
  }
  return [str];
}
/**
 * Check for invalid characters
 */
function isCharClass(a, b, step, isNum, isDescending) {
  if (isDescending) { return false; }
  if (isNum) { return a <= 9 && b <= 9; }
  if (a < b) { return step === 1; }
  return false;
}
/**
 * Detect the correct separator to use
 */
function shouldExpand(a, b, num, isNum, padding, opts) {
  if (isNum && (a > 9 || b > 9)) { return false; }
  return !padding && num === 1 && a < b;
}
/**
 * Detect the correct separator to use
 */
function detectSeparator(a, b, step, isNum, isDescending) {
  var isChar = isCharClass(a, b, step, isNum, isDescending);
  if (!isChar) {
    return '|';
  }
  return '~';
}
/**
 * Correctly format the step based on type
 */
function formatStep(step) {
  return Math.abs(step >> 0) || 1;
}
/**
 * Format padding, taking leading `-` into account
 */
function formatPadding(ch, pad) {
  var res = pad ? pad + ch : ch;
  if (pad && ch.toString().charAt(0) === '-') {
    res = '-' + pad + ch.toString().substr(1);
  }
  return res.toString();
}
/**
 * Check for invalid characters
 */
function isInvalidChar(str) {
  var ch = toStr(str);
  return ch === '\\'
    || ch === '['
    || ch === ']'
    || ch === '^'
    || ch === '('
    || ch === ')'
    || ch === '`';
}
/**
 * Convert to a string from a charCode
 */
function toStr(ch) {
  return String.fromCharCode(ch);
}
/**
 * Step regex
 */
function stepRe() {
  return /\?|>|\||\+|\~/g;
}
/**
 * Return true if `val` has either a letter
 * or a number
 */
function noAlphaNum(val) {
  return /[a-z0-9]/i.test(val);
}
/**
 * Return true if `val` has both a letter and
 * a number (invalid)
 */
function hasBoth(val) {
  return /[a-z][0-9]|[0-9][a-z]/i.test(val);
}
/**
 * Normalize zeros for checks
 */
function zeros(val) {
  if (/^-*0+$/.test(val.toString())) {
    return '0';
  }
  return val;
}
/**
 * Return true if `val` has leading zeros,
 * or a similar valid pattern.
 */
function hasZeros(val) {
  return /[^.]\.|^-*0+[0-9]/.test(val);
}
/**
 * If the string is padded, returns a curried function with
 * the a cached padding string, or `false` if no padding.
 *
 * @param  {*} `origA` String or number.
 * @return {String|Boolean}
 */
function isPadded(origA, origB) {
  if (hasZeros(origA) || hasZeros(origB)) {
    var alen = length(origA);
    var blen = length(origB);
    var len = alen >= blen
      ? alen
      : blen;
    return function (a) {
      return repeatStr('0', len - length(a));
    };
  }
  return false;
}
/**
 * Get the string length of `val`
 */
function length(val) {
  return val.toString().length;
}

+ 16 - 0
src/server/node_modules/for-in/index.js

@ -0,0 +1,16 @@
/*!
 * for-in <https://github.com/jonschlinkert/for-in>
 *
 * Copyright (c) 2014-2016, Jon Schlinkert.
 * Licensed under the MIT License.
 */
'use strict';
module.exports = function forIn(o, fn, thisArg) {
  for (var key in o) {
    if (fn.call(thisArg, o[key], key, o) === false) {
      break;
    }
  }
};

+ 19 - 0
src/server/node_modules/for-own/index.js

@ -0,0 +1,19 @@
/*!
 * for-own <https://github.com/jonschlinkert/for-own>
 *
 * Copyright (c) 2014-2016, Jon Schlinkert.
 * Licensed under the MIT License.
 */
'use strict';
var forIn = require('for-in');
var hasOwn = Object.prototype.hasOwnProperty;
module.exports = function forOwn(o, fn, thisArg) {
  forIn(o, function(val, key) {
    if (hasOwn.call(o, key)) {
      return fn.call(thisArg, o[key], key, o);
    }
  });
};

+ 51 - 0
src/server/node_modules/glob-base/index.js

@ -0,0 +1,51 @@
/*!
 * glob-base <https://github.com/jonschlinkert/glob-base>
 *
 * Copyright (c) 2015, Jon Schlinkert.
 * Licensed under the MIT License.
 */
'use strict';
var path = require('path');
var parent = require('glob-parent');
var isGlob = require('is-glob');
module.exports = function globBase(pattern) {
  if (typeof pattern !== 'string') {
    throw new TypeError('glob-base expects a string.');
  }
  var res = {};
  res.base = parent(pattern);
  res.isGlob = isGlob(pattern);
  if (res.base !== '.') {
    res.glob = pattern.substr(res.base.length);
    if (res.glob.charAt(0) === '/') {
      res.glob = res.glob.substr(1);
    }
  } else {
    res.glob = pattern;
  }
  if (!res.isGlob) {
    res.base = dirname(pattern);
    res.glob = res.base !== '.'
      ? pattern.substr(res.base.length)
      : pattern;
  }
  if (res.glob.substr(0, 2) === './') {
    res.glob = res.glob.substr(2);
  }
  if (res.glob.charAt(0) === '/') {
    res.glob = res.glob.substr(1);
  }
  return res;
};
function dirname(glob) {
  if (glob.slice(-1) === '/') return glob;
  return path.dirname(glob);
}

+ 10 - 0
src/server/node_modules/glob-base/node_modules/glob-parent/index.js

@ -0,0 +1,10 @@
'use strict';
var path = require('path');
var isglob = require('is-glob');
module.exports = function globParent(str) {
	str += 'a'; // preserves full path in case of trailing path separator
	do {str = path.dirname(str)} while (isglob(str));
	return str;
};

+ 28 - 0
src/server/node_modules/glob-base/node_modules/glob-parent/test.js

@ -0,0 +1,28 @@
'use strict';
var gp = require('./');
var assert = require('assert');
describe('glob-parent', function() {
  it('should strip glob magic to return parent path', function() {
    assert.equal(gp('path/to/*.js'), 'path/to');
    assert.equal(gp('/root/path/to/*.js'), '/root/path/to');
    assert.equal(gp('/*.js'), '/');
    assert.equal(gp('*.js'), '.');
    assert.equal(gp('**/*.js'), '.');
    assert.equal(gp('path/{to,from}'), 'path');
    assert.equal(gp('path/!(to|from)'), 'path');
    assert.equal(gp('path/?(to|from)'), 'path');
    assert.equal(gp('path/+(to|from)'), 'path');
    assert.equal(gp('path/*(to|from)'), 'path');
    assert.equal(gp('path/@(to|from)'), 'path');
    assert.equal(gp('path/**/*'), 'path');
    assert.equal(gp('path/**/subdir/foo.*'), 'path');
  });
  it('should return parent dirname from non-glob paths', function() {
    assert.equal(gp('path/foo/bar.js'), 'path/foo');
    assert.equal(gp('path/foo/'), 'path/foo');
    assert.equal(gp('path/foo'), 'path');
  });
});

+ 14 - 0
src/server/node_modules/glob-base/node_modules/is-glob/index.js

@ -0,0 +1,14 @@
/*!
 * is-glob <https://github.com/jonschlinkert/is-glob>
 *
 * Copyright (c) 2014-2015, Jon Schlinkert.
 * Licensed under the MIT License.
 */
var isExtglob = require('is-extglob');
module.exports = function isGlob(str) {
  return typeof str === 'string'
    && (/[*!?{}(|)[\]]/.test(str)
     || isExtglob(str));
};

+ 9 - 0
src/server/node_modules/glob-parent/index.js

@ -0,0 +1,9 @@
'use strict';
var path = require('path');
var isglob = require('is-glob');
module.exports = function globParent(str) {
	while (isglob(str)) str = path.dirname(str);
	return str;
};

+ 14 - 0
src/server/node_modules/glob-parent/node_modules/is-glob/index.js

@ -0,0 +1,14 @@
/*!
 * is-glob <https://github.com/jonschlinkert/is-glob>
 *
 * Copyright (c) 2014-2015, Jon Schlinkert.
 * Licensed under the MIT License.
 */
var isExtglob = require('is-extglob');
module.exports = function isGlob(str) {
  return typeof str === 'string'
    && (/[*!?{}(|)[\]]/.test(str)
     || isExtglob(str));
};

+ 22 - 0
src/server/node_modules/glob-parent/test.js

@ -0,0 +1,22 @@
'use strict';
var gp = require('./');
var assert = require('assert');
describe('glob-parent', function() {
  it('should strip glob magic to return parent path', function() {
    assert.equal(gp('path/to/*.js'), 'path/to');
    assert.equal(gp('/root/path/to/*.js'), '/root/path/to');
    assert.equal(gp('/*.js'), '/');
    assert.equal(gp('*.js'), '.');
    assert.equal(gp('**/*.js'), '.');
    assert.equal(gp('path/{to,from}'), 'path');
    assert.equal(gp('path/!(to|from)'), 'path');
    assert.equal(gp('path/?(to|from)'), 'path');
    assert.equal(gp('path/+(to|from)'), 'path');
    assert.equal(gp('path/*(to|from)'), 'path');
    assert.equal(gp('path/@(to|from)'), 'path');
    assert.equal(gp('path/**/*'), 'path');
    assert.equal(gp('path/**/subdir/foo.*'), 'path');
  });
});

+ 21 - 0
src/server/node_modules/graceful-fs/fs.js

@ -0,0 +1,21 @@
'use strict'
var fs = require('fs')
module.exports = clone(fs)
function clone (obj) {
  if (obj === null || typeof obj !== 'object')
    return obj
  if (obj instanceof Object)
    var copy = { __proto__: obj.__proto__ }
  else
    var copy = Object.create(null)
  Object.getOwnPropertyNames(obj).forEach(function (key) {
    Object.defineProperty(copy, key, Object.getOwnPropertyDescriptor(obj, key))
  })
  return copy
}

+ 262 - 0
src/server/node_modules/graceful-fs/graceful-fs.js

@ -0,0 +1,262 @@
var fs = require('fs')
var polyfills = require('./polyfills.js')
var legacy = require('./legacy-streams.js')
var queue = []
var util = require('util')
function noop () {}
var debug = noop
if (util.debuglog)
  debug = util.debuglog('gfs4')
else if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || ''))
  debug = function() {
    var m = util.format.apply(util, arguments)
    m = 'GFS4: ' + m.split(/\n/).join('\nGFS4: ')
    console.error(m)
  }
if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || '')) {
  process.on('exit', function() {
    debug(queue)
    require('assert').equal(queue.length, 0)
  })
}
module.exports = patch(require('./fs.js'))
if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH) {
  module.exports = patch(fs)
}
// Always patch fs.close/closeSync, because we want to
// retry() whenever a close happens *anywhere* in the program.
// This is essential when multiple graceful-fs instances are
// in play at the same time.
module.exports.close =
fs.close = (function (fs$close) { return function (fd, cb) {
  return fs$close.call(fs, fd, function (err) {
    if (!err)
      retry()
    if (typeof cb === 'function')
      cb.apply(this, arguments)
  })
}})(fs.close)
module.exports.closeSync =
fs.closeSync = (function (fs$closeSync) { return function (fd) {
  // Note that graceful-fs also retries when fs.closeSync() fails.
  // Looks like a bug to me, although it's probably a harmless one.
  var rval = fs$closeSync.apply(fs, arguments)
  retry()
  return rval
}})(fs.closeSync)
function patch (fs) {
  // Everything that references the open() function needs to be in here
  polyfills(fs)
  fs.gracefulify = patch
  fs.FileReadStream = ReadStream;  // Legacy name.
  fs.FileWriteStream = WriteStream;  // Legacy name.
  fs.createReadStream = createReadStream
  fs.createWriteStream = createWriteStream
  var fs$readFile = fs.readFile
  fs.readFile = readFile
  function readFile (path, options, cb) {
    if (typeof options === 'function')
      cb = options, options = null
    return go$readFile(path, options, cb)
    function go$readFile (path, options, cb) {
      return fs$readFile(path, options, function (err) {
        if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
          enqueue([go$readFile, [path, options, cb]])
        else {
          if (typeof cb === 'function')
            cb.apply(this, arguments)
          retry()
        }
      })
    }
  }
  var fs$writeFile = fs.writeFile
  fs.writeFile = writeFile
  function writeFile (path, data, options, cb) {
    if (typeof options === 'function')
      cb = options, options = null
    return go$writeFile(path, data, options, cb)
    function go$writeFile (path, data, options, cb) {
      return fs$writeFile(path, data, options, function (err) {
        if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
          enqueue([go$writeFile, [path, data, options, cb]])
        else {
          if (typeof cb === 'function')
            cb.apply(this, arguments)
          retry()
        }
      })
    }
  }
  var fs$appendFile = fs.appendFile
  if (fs$appendFile)
    fs.appendFile = appendFile
  function appendFile (path, data, options, cb) {
    if (typeof options === 'function')
      cb = options, options = null
    return go$appendFile(path, data, options, cb)
    function go$appendFile (path, data, options, cb) {
      return fs$appendFile(path, data, options, function (err) {
        if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
          enqueue([go$appendFile, [path, data, options, cb]])
        else {
          if (typeof cb === 'function')
            cb.apply(this, arguments)
          retry()
        }
      })
    }
  }
  var fs$readdir = fs.readdir
  fs.readdir = readdir
  function readdir (path, options, cb) {
    var args = [path]
    if (typeof options !== 'function') {
      args.push(options)
    } else {
      cb = options
    }
    args.push(go$readdir$cb)
    return go$readdir(args)
    function go$readdir$cb (err, files) {
      if (files && files.sort)
        files.sort()
      if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
        enqueue([go$readdir, [args]])
      else {
        if (typeof cb === 'function')
          cb.apply(this, arguments)
        retry()
      }
    }
  }
  function go$readdir (args) {
    return fs$readdir.apply(fs, args)
  }
  if (process.version.substr(0, 4) === 'v0.8') {
    var legStreams = legacy(fs)
    ReadStream = legStreams.ReadStream
    WriteStream = legStreams.WriteStream
  }
  var fs$ReadStream = fs.ReadStream
  ReadStream.prototype = Object.create(fs$ReadStream.prototype)
  ReadStream.prototype.open = ReadStream$open
  var fs$WriteStream = fs.WriteStream
  WriteStream.prototype = Object.create(fs$WriteStream.prototype)
  WriteStream.prototype.open = WriteStream$open
  fs.ReadStream = ReadStream
  fs.WriteStream = WriteStream
  function ReadStream (path, options) {
    if (this instanceof ReadStream)
      return fs$ReadStream.apply(this, arguments), this
    else
      return ReadStream.apply(Object.create(ReadStream.prototype), arguments)
  }
  function ReadStream$open () {
    var that = this
    open(that.path, that.flags, that.mode, function (err, fd) {
      if (err) {
        if (that.autoClose)
          that.destroy()
        that.emit('error', err)
      } else {
        that.fd = fd
        that.emit('open', fd)
        that.read()
      }
    })
  }
  function WriteStream (path, options) {
    if (this instanceof WriteStream)
      return fs$WriteStream.apply(this, arguments), this
    else
      return WriteStream.apply(Object.create(WriteStream.prototype), arguments)
  }
  function WriteStream$open () {
    var that = this
    open(that.path, that.flags, that.mode, function (err, fd) {
      if (err) {
        that.destroy()
        that.emit('error', err)
      } else {
        that.fd = fd
        that.emit('open', fd)
      }
    })
  }
  function createReadStream (path, options) {
    return new ReadStream(path, options)
  }
  function createWriteStream (path, options) {
    return new WriteStream(path, options)
  }
  var fs$open = fs.open
  fs.open = open
  function open (path, flags, mode, cb) {
    if (typeof mode === 'function')
      cb = mode, mode = null
    return go$open(path, flags, mode, cb)
    function go$open (path, flags, mode, cb) {
      return fs$open(path, flags, mode, function (err, fd) {
        if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
          enqueue([go$open, [path, flags, mode, cb]])
        else {
          if (typeof cb === 'function')
            cb.apply(this, arguments)
          retry()
        }
      })
    }
  }
  return fs
}
function enqueue (elem) {
  debug('ENQUEUE', elem[0].name, elem[1])
  queue.push(elem)
}
function retry () {
  var elem = queue.shift()
  if (elem) {
    debug('RETRY', elem[0].name, elem[1])
    elem[0].apply(null, elem[1])
  }
}

+ 118 - 0
src/server/node_modules/graceful-fs/legacy-streams.js

@ -0,0 +1,118 @@
var Stream = require('stream').Stream
module.exports = legacy
function legacy (fs) {
  return {
    ReadStream: ReadStream,
    WriteStream: WriteStream
  }
  function ReadStream (path, options) {
    if (!(this instanceof ReadStream)) return new ReadStream(path, options);
    Stream.call(this);
    var self = this;
    this.path = path;
    this.fd = null;
    this.readable = true;
    this.paused = false;
    this.flags = 'r';
    this.mode = 438; /*=0666*/
    this.bufferSize = 64 * 1024;
    options = options || {};
    // Mixin options into this
    var keys = Object.keys(options);
    for (var index = 0, length = keys.length; index < length; index++) {
      var key = keys[index];
      this[key] = options[key];
    }
    if (this.encoding) this.setEncoding(this.encoding);
    if (this.start !== undefined) {
      if ('number' !== typeof this.start) {
        throw TypeError('start must be a Number');
      }
      if (this.end === undefined) {
        this.end = Infinity;
      } else if ('number' !== typeof this.end) {
        throw TypeError('end must be a Number');
      }
      if (this.start > this.end) {
        throw new Error('start must be <= end');
      }
      this.pos = this.start;
    }
    if (this.fd !== null) {
      process.nextTick(function() {
        self._read();
      });
      return;
    }
    fs.open(this.path, this.flags, this.mode, function (err, fd) {
      if (err) {
        self.emit('error', err);
        self.readable = false;
        return;
      }
      self.fd = fd;
      self.emit('open', fd);
      self._read();
    })
  }
  function WriteStream (path, options) {
    if (!(this instanceof WriteStream)) return new WriteStream(path, options);
    Stream.call(this);
    this.path = path;
    this.fd = null;
    this.writable = true;
    this.flags = 'w';
    this.encoding = 'binary';
    this.mode = 438; /*=0666*/
    this.bytesWritten = 0;
    options = options || {};
    // Mixin options into this
    var keys = Object.keys(options);
    for (var index = 0, length = keys.length; index < length; index++) {
      var key = keys[index];
      this[key] = options[key];
    }
    if (this.start !== undefined) {
      if ('number' !== typeof this.start) {
        throw TypeError('start must be a Number');
      }
      if (this.start < 0) {
        throw new Error('start must be >= zero');
      }
      this.pos = this.start;
    }
    this.busy = false;
    this._queue = [];
    if (this.fd === null) {
      this._open = fs.open;
      this._queue.push([this._open, this.path, this.flags, this.mode, undefined]);
      this.flush();
    }
  }
}

+ 330 - 0
src/server/node_modules/graceful-fs/polyfills.js

@ -0,0 +1,330 @@
var fs = require('./fs.js')
var constants = require('constants')
var origCwd = process.cwd
var cwd = null
var platform = process.env.GRACEFUL_FS_PLATFORM || process.platform
process.cwd = function() {
  if (!cwd)
    cwd = origCwd.call(process)
  return cwd
}
try {
  process.cwd()
} catch (er) {}
var chdir = process.chdir
process.chdir = function(d) {
  cwd = null
  chdir.call(process, d)
}
module.exports = patch
function patch (fs) {
  // (re-)implement some things that are known busted or missing.
  // lchmod, broken prior to 0.6.2
  // back-port the fix here.
  if (constants.hasOwnProperty('O_SYMLINK') &&
      process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) {
    patchLchmod(fs)
  }
  // lutimes implementation, or no-op
  if (!fs.lutimes) {
    patchLutimes(fs)
  }
  // https://github.com/isaacs/node-graceful-fs/issues/4
  // Chown should not fail on einval or eperm if non-root.
  // It should not fail on enosys ever, as this just indicates
  // that a fs doesn't support the intended operation.
  fs.chown = chownFix(fs.chown)
  fs.fchown = chownFix(fs.fchown)
  fs.lchown = chownFix(fs.lchown)
  fs.chmod = chmodFix(fs.chmod)
  fs.fchmod = chmodFix(fs.fchmod)
  fs.lchmod = chmodFix(fs.lchmod)
  fs.chownSync = chownFixSync(fs.chownSync)
  fs.fchownSync = chownFixSync(fs.fchownSync)
  fs.lchownSync = chownFixSync(fs.lchownSync)
  fs.chmodSync = chmodFixSync(fs.chmodSync)
  fs.fchmodSync = chmodFixSync(fs.fchmodSync)
  fs.lchmodSync = chmodFixSync(fs.lchmodSync)
  fs.stat = statFix(fs.stat)
  fs.fstat = statFix(fs.fstat)
  fs.lstat = statFix(fs.lstat)
  fs.statSync = statFixSync(fs.statSync)
  fs.fstatSync = statFixSync(fs.fstatSync)
  fs.lstatSync = statFixSync(fs.lstatSync)
  // if lchmod/lchown do not exist, then make them no-ops
  if (!fs.lchmod) {
    fs.lchmod = function (path, mode, cb) {
      if (cb) process.nextTick(cb)
    }
    fs.lchmodSync = function () {}
  }
  if (!fs.lchown) {
    fs.lchown = function (path, uid, gid, cb) {
      if (cb) process.nextTick(cb)
    }
    fs.lchownSync = function () {}
  }
  // on Windows, A/V software can lock the directory, causing this
  // to fail with an EACCES or EPERM if the directory contains newly
  // created files.  Try again on failure, for up to 60 seconds.
  // Set the timeout this long because some Windows Anti-Virus, such as Parity
  // bit9, may lock files for up to a minute, causing npm package install
  // failures. Also, take care to yield the scheduler. Windows scheduling gives
  // CPU to a busy looping process, which can cause the program causing the lock
  // contention to be starved of CPU by node, so the contention doesn't resolve.
  if (platform === "win32") {
    fs.rename = (function (fs$rename) { return function (from, to, cb) {
      var start = Date.now()
      var backoff = 0;
      fs$rename(from, to, function CB (er) {
        if (er
            && (er.code === "EACCES" || er.code === "EPERM")
            && Date.now() - start < 60000) {
          setTimeout(function() {
            fs.stat(to, function (stater, st) {
              if (stater && stater.code === "ENOENT")
                fs$rename(from, to, CB);
              else
                cb(er)
            })
          }, backoff)
          if (backoff < 100)
            backoff += 10;
          return;
        }
        if (cb) cb(er)
      })
    }})(fs.rename)
  }
  // if read() returns EAGAIN, then just try it again.
  fs.read = (function (fs$read) { return function (fd, buffer, offset, length, position, callback_) {
    var callback
    if (callback_ && typeof callback_ === 'function') {
      var eagCounter = 0
      callback = function (er, _, __) {
        if (er && er.code === 'EAGAIN' && eagCounter < 10) {
          eagCounter ++
          return fs$read.call(fs, fd, buffer, offset, length, position, callback)
        }
        callback_.apply(this, arguments)
      }
    }
    return fs$read.call(fs, fd, buffer, offset, length, position, callback)
  }})(fs.read)
  fs.readSync = (function (fs$readSync) { return function (fd, buffer, offset, length, position) {
    var eagCounter = 0
    while (true) {
      try {
        return fs$readSync.call(fs, fd, buffer, offset, length, position)
      } catch (er) {
        if (er.code === 'EAGAIN' && eagCounter < 10) {
          eagCounter ++
          continue
        }
        throw er
      }
    }
  }})(fs.readSync)
}
function patchLchmod (fs) {
  fs.lchmod = function (path, mode, callback) {
    fs.open( path
           , constants.O_WRONLY | constants.O_SYMLINK
           , mode
           , function (err, fd) {
      if (err) {
        if (callback) callback(err)
        return
      }
      // prefer to return the chmod error, if one occurs,
      // but still try to close, and report closing errors if they occur.
      fs.fchmod(fd, mode, function (err) {
        fs.close(fd, function(err2) {
          if (callback) callback(err || err2)
        })
      })
    })
  }
  fs.lchmodSync = function (path, mode) {
    var fd = fs.openSync(path, constants.O_WRONLY | constants.O_SYMLINK, mode)
    // prefer to return the chmod error, if one occurs,
    // but still try to close, and report closing errors if they occur.
    var threw = true
    var ret
    try {
      ret = fs.fchmodSync(fd, mode)
      threw = false
    } finally {
      if (threw) {
        try {
          fs.closeSync(fd)
        } catch (er) {}
      } else {
        fs.closeSync(fd)
      }
    }
    return ret
  }
}
function patchLutimes (fs) {
  if (constants.hasOwnProperty("O_SYMLINK")) {
    fs.lutimes = function (path, at, mt, cb) {
      fs.open(path, constants.O_SYMLINK, function (er, fd) {
        if (er) {
          if (cb) cb(er)
          return
        }
        fs.futimes(fd, at, mt, function (er) {
          fs.close(fd, function (er2) {
            if (cb) cb(er || er2)
          })
        })
      })
    }
    fs.lutimesSync = function (path, at, mt) {
      var fd = fs.openSync(path, constants.O_SYMLINK)
      var ret
      var threw = true
      try {
        ret = fs.futimesSync(fd, at, mt)
        threw = false
      } finally {
        if (threw) {
          try {
            fs.closeSync(fd)
          } catch (er) {}
        } else {
          fs.closeSync(fd)
        }
      }
      return ret
    }
  } else {
    fs.lutimes = function (_a, _b, _c, cb) { if (cb) process.nextTick(cb) }
    fs.lutimesSync = function () {}
  }
}
function chmodFix (orig) {
  if (!orig) return orig
  return function (target, mode, cb) {
    return orig.call(fs, target, mode, function (er) {
      if (chownErOk(er)) er = null
      if (cb) cb.apply(this, arguments)
    })
  }
}
function chmodFixSync (orig) {
  if (!orig) return orig
  return function (target, mode) {
    try {
      return orig.call(fs, target, mode)
    } catch (er) {
      if (!chownErOk(er)) throw er
    }
  }
}
function chownFix (orig) {
  if (!orig) return orig
  return function (target, uid, gid, cb) {
    return orig.call(fs, target, uid, gid, function (er) {
      if (chownErOk(er)) er = null
      if (cb) cb.apply(this, arguments)
    })
  }
}
function chownFixSync (orig) {
  if (!orig) return orig
  return function (target, uid, gid) {
    try {
      return orig.call(fs, target, uid, gid)
    } catch (er) {
      if (!chownErOk(er)) throw er
    }
  }
}
function statFix (orig) {
  if (!orig) return orig
  // Older versions of Node erroneously returned signed integers for
  // uid + gid.
  return function (target, cb) {
    return orig.call(fs, target, function (er, stats) {
      if (!stats) return cb.apply(this, arguments)
      if (stats.uid < 0) stats.uid += 0x100000000
      if (stats.gid < 0) stats.gid += 0x100000000
      if (cb) cb.apply(this, arguments)
    })
  }
}
function statFixSync (orig) {
  if (!orig) return orig
  // Older versions of Node erroneously returned signed integers for
  // uid + gid.
  return function (target) {
    var stats = orig.call(fs, target)
    if (stats.uid < 0) stats.uid += 0x100000000
    if (stats.gid < 0) stats.gid += 0x100000000
    return stats;
  }
}
// ENOSYS means that the fs doesn't support the op. Just ignore
// that, because it doesn't matter.
//
// if there's no getuid, or if getuid() is something other
// than 0, and the error is EINVAL or EPERM, then just ignore
// it.
//
// This specific case is a silent failure in cp, install, tar,
// and most other unix tools that manage permissions.
//
// When running as root, or if other types of errors are
// encountered, then it's strict.
function chownErOk (er) {
  if (!er)
    return true
  if (er.code === "ENOSYS")
    return true
  var nonroot = !process.getuid || process.getuid() !== 0
  if (nonroot) {
    if (er.code === "EINVAL" || er.code === "EPERM")
      return true
  }
  return false
}

+ 12 - 0
src/server/node_modules/graceful-readlink/index.js

@ -0,0 +1,12 @@
var fs = require('fs')
  , lstat = fs.lstatSync;
exports.readlinkSync = function (p) {
  if (lstat(p).isSymbolicLink()) {
    return fs.readlinkSync(p);
  } else {
    return p;
  }
};

test/server/node_modules/mocha/node_modules/glob/node_modules/inherits/inherits.js → src/server/node_modules/inherits/inherits.js


test/server/node_modules/mocha/node_modules/glob/node_modules/inherits/inherits_browser.js → src/server/node_modules/inherits/inherits_browser.js


+ 12 - 0
src/server/node_modules/is-binary-path/index.js

@ -0,0 +1,12 @@
'use strict';
var path = require('path');
var binaryExtensions = require('binary-extensions');
var exts = Object.create(null);
binaryExtensions.forEach(function (el) {
	exts[el] = true;
});
module.exports = function (filepath) {
	return path.extname(filepath).slice(1).toLowerCase() in exts;
};

+ 21 - 0
src/server/node_modules/is-buffer/index.js

@ -0,0 +1,21 @@
/*!
 * Determine if an object is a Buffer
 *
 * @author   Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
 * @license  MIT
 */
// The _isBuffer check is for Safari 5-7 support, because it's missing
// Object.prototype.constructor. Remove this eventually
module.exports = function (obj) {
  return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer)
}
function isBuffer (obj) {
  return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj)
}
// For Node v0.10 support. Remove this eventually.
function isSlowBuffer (obj) {
  return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0))
}

+ 25 - 0
src/server/node_modules/is-buffer/test/basic.js

@ -0,0 +1,25 @@
var buffer = require('buffer')
var isBuffer = require('../')
var test = require('tape')
test('is-buffer', function (t) {
  t.equal(isBuffer(new Buffer(4)), true, 'new Buffer(4)')
  t.equal(isBuffer(buffer.SlowBuffer(100)), true, 'SlowBuffer(100)')
  t.equal(isBuffer(undefined), false, 'undefined')
  t.equal(isBuffer(null), false, 'null')
  t.equal(isBuffer(''), false, 'empty string')
  t.equal(isBuffer(true), false, 'true')
  t.equal(isBuffer(false), false, 'false')
  t.equal(isBuffer(0), false, '0')
  t.equal(isBuffer(1), false, '1')
  t.equal(isBuffer(1.0), false, '1.0')
  t.equal(isBuffer('string'), false, 'string')
  t.equal(isBuffer({}), false, '{}')
  t.equal(isBuffer([]), false, '[]')
  t.equal(isBuffer(function foo () {}), false, 'function foo () {}')
  t.equal(isBuffer({ isBuffer: null }), false, '{ isBuffer: null }')
  t.equal(isBuffer({ isBuffer: function () { throw new Error() } }), false, '{ isBuffer: function () { throw new Error() } }')
  t.end()
})

+ 15 - 0
src/server/node_modules/is-dotfile/index.js

@ -0,0 +1,15 @@
/*!
 * is-dotfile <https://github.com/regexps/is-dotfile>
 *
 * Copyright (c) 2015 Jon Schlinkert, contributors.
 * Licensed under the MIT license.
 */
module.exports = function(str) {
  if (str.charCodeAt(0) === 46 /* . */ && str.indexOf('/', 1) === -1) {
    return true;
  }
  var last = str.lastIndexOf('/');
  return last !== -1 ? str.charCodeAt(last + 1) === 46  /* . */ : false;
};

+ 27 - 0
src/server/node_modules/is-equal-shallow/index.js

@ -0,0 +1,27 @@
/*!
 * is-equal-shallow <https://github.com/jonschlinkert/is-equal-shallow>
 *
 * Copyright (c) 2015, Jon Schlinkert.
 * Licensed under the MIT License.
 */
'use strict';
var isPrimitive = require('is-primitive');
module.exports = function isEqual(a, b) {
  if (!a && !b) { return true; }
  if (!a && b || a && !b) { return false; }
  var numKeysA = 0, numKeysB = 0, key;
  for (key in b) {
    numKeysB++;
    if (!isPrimitive(b[key]) || !a.hasOwnProperty(key) || (a[key] !== b[key])) {
      return false;
    }
  }
  for (key in a) {
    numKeysA++;
  }
  return numKeysA === numKeysB;
};

+ 13 - 0
src/server/node_modules/is-extendable/index.js

@ -0,0 +1,13 @@
/*!
 * is-extendable <https://github.com/jonschlinkert/is-extendable>
 *
 * Copyright (c) 2015, Jon Schlinkert.
 * Licensed under the MIT License.
 */
'use strict';
module.exports = function isExtendable(val) {
  return typeof val !== 'undefined' && val !== null
    && (typeof val === 'object' || typeof val === 'function');
};

+ 11 - 0
src/server/node_modules/is-extglob/index.js

@ -0,0 +1,11 @@
/*!
 * is-extglob <https://github.com/jonschlinkert/is-extglob>
 *
 * Copyright (c) 2014-2015, Jon Schlinkert.
 * Licensed under the MIT License.
 */
module.exports = function isExtglob(str) {
  return typeof str === 'string'
    && /[@?!+*]\(/.test(str);
};

+ 11 - 0
src/server/node_modules/is-glob/index.js

@ -0,0 +1,11 @@
/*!
 * is-glob <https://github.com/jonschlinkert/is-glob>
 *
 * Copyright (c) 2014-2015, Jon Schlinkert.
 * Licensed under the MIT License.
 */
module.exports = function isGlob(str) {
  return typeof str === 'string'
    && /[!*{}?(|)[\]]/.test(str);
};

+ 19 - 0
src/server/node_modules/is-number/index.js

@ -0,0 +1,19 @@
/*!
 * is-number <https://github.com/jonschlinkert/is-number>
 *
 * Copyright (c) 2014-2015, Jon Schlinkert.
 * Licensed under the MIT License.
 */
'use strict';
var typeOf = require('kind-of');
module.exports = function isNumber(num) {
  var type = typeOf(num);
  if (type !== 'number' && type !== 'string') {
    return false;
  }
  var n = +num;
  return (n - n + 1) >= 0 && num !== '';
};

+ 10 - 0
src/server/node_modules/is-posix-bracket/index.js

@ -0,0 +1,10 @@
/*!
 * is-posix-bracket <https://github.com/jonschlinkert/is-posix-bracket>
 *
 * Copyright (c) 2015-2016, Jon Schlinkert.
 * Licensed under the MIT License.
 */
module.exports = function isPosixBracket(str) {
  return typeof str === 'string' && /\[([:.=+])(?:[^\[\]]|)+\1\]/.test(str);
};

+ 13 - 0
src/server/node_modules/is-primitive/index.js

@ -0,0 +1,13 @@
/*!
 * is-primitive <https://github.com/jonschlinkert/is-primitive>
 *
 * Copyright (c) 2014-2015, Jon Schlinkert.
 * Licensed under the MIT License.
 */
'use strict';
// see http://jsperf.com/testing-value-is-primitive/7
module.exports = function isPrimitive(value) {
  return value == null || (typeof value !== 'function' && typeof value !== 'object');
};

test/server/node_modules/mongoose/node_modules/mongodb/node_modules/readable-stream/node_modules/isarray/index.js → src/server/node_modules/isarray/index.js


test/server/node_modules/mongoose/node_modules/mongodb/node_modules/readable-stream/node_modules/isarray/test.js → src/server/node_modules/isarray/test.js


+ 14 - 0
src/server/node_modules/isobject/index.js

@ -0,0 +1,14 @@
/*!
 * isobject <https://github.com/jonschlinkert/isobject>
 *
 * Copyright (c) 2014-2015, Jon Schlinkert.
 * Licensed under the MIT License.
 */
'use strict';
var isArray = require('isarray');
module.exports = function isObject(val) {
  return val != null && typeof val === 'object' && isArray(val) === false;
};

+ 116 - 0
src/server/node_modules/kind-of/index.js

@ -0,0 +1,116 @@
var isBuffer = require('is-buffer');
var toString = Object.prototype.toString;
/**
 * Get the native `typeof` a value.
 *
 * @param  {*} `val`
 * @return {*} Native javascript type
 */
module.exports = function kindOf(val) {
  // primitivies
  if (typeof val === 'undefined') {
    return 'undefined';
  }
  if (val === null) {
    return 'null';
  }
  if (val === true || val === false || val instanceof Boolean) {
    return 'boolean';
  }
  if (typeof val === 'string' || val instanceof String) {
    return 'string';
  }
  if (typeof val === 'number' || val instanceof Number) {
    return 'number';
  }
  // functions
  if (typeof val === 'function' || val instanceof Function) {
    return 'function';
  }
  // array
  if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) {
    return 'array';
  }
  // check for instances of RegExp and Date before calling `toString`
  if (val instanceof RegExp) {
    return 'regexp';
  }
  if (val instanceof Date) {
    return 'date';
  }
  // other objects
  var type = toString.call(val);
  if (type === '[object RegExp]') {
    return 'regexp';
  }
  if (type === '[object Date]') {
    return 'date';
  }
  if (type === '[object Arguments]') {
    return 'arguments';
  }
  if (type === '[object Error]') {
    return 'error';
  }
  // buffer
  if (typeof Buffer !== 'undefined' && isBuffer(val)) {
    return 'buffer';
  }
  // es6: Map, WeakMap, Set, WeakSet
  if (type === '[object Set]') {
    return 'set';
  }
  if (type === '[object WeakSet]') {
    return 'weakset';
  }
  if (type === '[object Map]') {
    return 'map';
  }
  if (type === '[object WeakMap]') {
    return 'weakmap';
  }
  if (type === '[object Symbol]') {
    return 'symbol';
  }
  // typed arrays
  if (type === '[object Int8Array]') {
    return 'int8array';
  }
  if (type === '[object Uint8Array]') {
    return 'uint8array';
  }
  if (type === '[object Uint8ClampedArray]') {
    return 'uint8clampedarray';
  }
  if (type === '[object Int16Array]') {
    return 'int16array';
  }
  if (type === '[object Uint16Array]') {
    return 'uint16array';
  }
  if (type === '[object Int32Array]') {
    return 'int32array';
  }
  if (type === '[object Uint32Array]') {
    return 'uint32array';
  }
  if (type === '[object Float32Array]') {
    return 'float32array';
  }
  if (type === '[object Float64Array]') {
    return 'float64array';
  }
  // must be a plain object
  return 'object';
};

+ 46 - 0
src/server/node_modules/log4js/examples/example-connect-logger.js

@ -0,0 +1,46 @@
//The connect/express logger was added to log4js by danbell. This allows connect/express servers to log using log4js.
//https://github.com/nomiddlename/log4js-node/wiki/Connect-Logger
// load modules
var log4js = require('log4js');
var express = require("express");
var app = express();
//config
log4js.configure({
	appenders: [
		{ type: 'console' },
		{ type: 'file', filename: 'logs/log4jsconnect.log', category: 'log4jslog' }
	]
});
//define logger
var logger = log4js.getLogger('log4jslog');
// set at which time msg is logged print like: only on error & above
// logger.setLevel('ERROR');
//express app
app.configure(function() {
	app.use(express.favicon(''));
	// app.use(log4js.connectLogger(logger, { level: log4js.levels.INFO }));
	// app.use(log4js.connectLogger(logger, { level: 'auto', format: ':method :url :status' }));
	//### AUTO LEVEL DETECTION
	//http responses 3xx, level = WARN
	//http responses 4xx & 5xx, level = ERROR
	//else.level = INFO
	app.use(log4js.connectLogger(logger, { level: 'auto' }));
});
//route
app.get('/', function(req,res) {
	res.send('hello world');
});
//start app
app.listen(5000);
console.log('server runing at localhost:5000');
console.log('Simulation of normal response: goto localhost:5000');
console.log('Simulation of error response: goto localhost:5000/xxx');

+ 45 - 0
src/server/node_modules/log4js/examples/example-socket.js

@ -0,0 +1,45 @@
var log4js = require('./lib/log4js')
, cluster = require('cluster')
, numCPUs = require('os').cpus().length
, i = 0;
if (cluster.isMaster) {
    log4js.configure({
        appenders: [
            {
                type: "multiprocess",
                mode: "master",
                appender: {
                    type: "console"
                }
            }
        ]
    });
    console.info("Master creating %d workers", numCPUs);
    for (i=0; i < numCPUs; i++) {
        cluster.fork();
    }
    cluster.on('death', function(worker) {
        console.info("Worker %d died.", worker.pid);
    });
} else {
    log4js.configure({
        appenders: [
            {
                type: "multiprocess",
                mode: "worker"
            }
        ]
    });
    var logger = log4js.getLogger('example-socket');
    console.info("Worker %d started.", process.pid);
    for (i=0; i < 1000; i++) {
        logger.info("Worker %d - logging something %d", process.pid, i);
    }
}

+ 58 - 0
src/server/node_modules/log4js/examples/example.js

@ -0,0 +1,58 @@
var log4js = require('../lib/log4js');
//log the cheese logger messages to a file, and the console ones as well.
log4js.configure({
    appenders: [
        {
            type: "file",
            filename: "cheese.log",
            category: [ 'cheese','console' ]
        },
        {
            type: "console"
        }
    ],
    replaceConsole: true
});
//to add an appender programmatically, and without clearing other appenders
//loadAppender is only necessary if you haven't already configured an appender of this type
log4js.loadAppender('file');
log4js.addAppender(log4js.appenders.file('pants.log'), 'pants');
//a custom logger outside of the log4js/lib/appenders directory can be accessed like so
//log4js.loadAppender('what/you/would/put/in/require');
//log4js.addAppender(log4js.appenders['what/you/would/put/in/require'](args));
//or through configure as:
//log4js.configure({
//  appenders: [ { type: 'what/you/would/put/in/require', otherArgs: 'blah' } ]
//});
var logger = log4js.getLogger('cheese');
//only errors and above get logged.
//you can also set this log level in the config object
//via the levels field.
logger.setLevel('ERROR');
//console logging methods have been replaced with log4js ones.
//so this will get coloured output on console, and appear in cheese.log
console.error("AAArgh! Something went wrong", { some: "otherObject", useful_for: "debug purposes" });
//these will not appear (logging level beneath error)
logger.trace('Entering cheese testing');
logger.debug('Got cheese.');
logger.info('Cheese is Gouda.');
logger.warn('Cheese is quite smelly.');
//these end up on the console and in cheese.log
logger.error('Cheese %s is too ripe!', "gouda");
logger.fatal('Cheese was breeding ground for listeria.');
//these don't end up in cheese.log, but will appear on the console
var anotherLogger = log4js.getLogger('another');
anotherLogger.debug("Just checking");
//one for pants.log
//will also go to console, since that's configured for all categories
var pantsLog = log4js.getLogger('pants');
pantsLog.debug("Something for pants");

+ 27 - 0
src/server/node_modules/log4js/examples/flush-on-exit.js

@ -0,0 +1,27 @@
/**
 * run this, then "ab -c 10 -n 100 localhost:4444/" to test (in
 * another shell)
 */
var log4js = require('../lib/log4js');
log4js.configure({
      appenders: [
        { type: 'file', filename: 'cheese.log', category: 'cheese' },
        { type: 'console'}
  ]
});
var logger = log4js.getLogger('cheese');
logger.setLevel('INFO');
var http=require('http');
var server = http.createServer(function(request, response){
    response.writeHead(200, {'Content-Type': 'text/plain'});
    var rd = Math.random() * 50;
    logger.info("hello " + rd);
    response.write('hello ');
    if (Math.floor(rd) == 30){
        log4js.shutdown(function() { process.exit(1); });
    }
    response.end();
}).listen(4444);

+ 19 - 0
src/server/node_modules/log4js/examples/fromreadme.js

@ -0,0 +1,19 @@
//remember to change the require to just 'log4js' if you've npm install'ed it
var log4js = require('./lib/log4js');
//by default the console appender is loaded
//log4js.loadAppender('console');
//you'd only need to add the console appender if you
//had previously called log4js.clearAppenders();
//log4js.addAppender(log4js.appenders.console());
log4js.loadAppender('file');
log4js.addAppender(log4js.appenders.file('cheese.log'), 'cheese');
var logger = log4js.getLogger('cheese');
logger.setLevel('ERROR');
logger.trace('Entering cheese testing');
logger.debug('Got cheese.');
logger.info('Cheese is Gouda.');
logger.warn('Cheese is quite smelly.');
logger.error('Cheese is too ripe!');
logger.fatal('Cheese was breeding ground for listeria.');

+ 27 - 0
src/server/node_modules/log4js/examples/log-rolling.js

@ -0,0 +1,27 @@
var log4js = require('../lib/log4js')
, log
, i = 0;
log4js.configure({
  "appenders": [
      {
          type: "console"
        , category: "console"
      },
      {
          "type": "file",
          "filename": "tmp-test.log",
          "maxLogSize": 1024,
          "backups": 3,
          "category": "test"
      }
  ]
});
log = log4js.getLogger("test");
function doTheLogging(x) {
    log.info("Logging something %d", x);
}
for ( ; i < 5000; i++) {
    doTheLogging(i);
}

+ 24 - 0
src/server/node_modules/log4js/examples/loggly-appender.js

@ -0,0 +1,24 @@
//Note that loggly appender needs node-loggly to work.
//If you haven't got node-loggly installed, you'll get cryptic
//"cannot find module" errors when using the loggly appender
var log4js = require('../lib/log4js');
log4js.configure({
  "appenders": [
    {
      type: "console",
      category: "test"
    },
    {
      "type"     : "loggly",
      "token"    : "12345678901234567890",
      "subdomain": "your-subdomain",
      "tags"     : ["test"],
      "category" : "loggly"
    }
  ]
});
var logger = log4js.getLogger("loggly");
logger.info("Test log message");
//logger.debug("Test log message");

+ 39 - 0
src/server/node_modules/log4js/examples/logstashUDP.js

@ -0,0 +1,39 @@
var log4js = require('../lib/log4js');
/*
 Sample logstash config:
   udp {
    codec => json
    port => 10001
    queue_size => 2
    workers => 2
    type => myAppType
  }
*/
log4js.configure({
  "appenders": [
    {
      type: "console",
      category: "myLogger"
    },
    {
      "host": "127.0.0.1",
      "port": 10001,
      "type": "logstashUDP",
      "logType": "myAppType", // Optional, defaults to 'category'
      "fields": {             // Optional, will be added to the 'fields' object in logstash
        "field1": "value1",
        "field2": "value2"
      },
      "layout": {
        "type": "pattern",
        "pattern": "%m"
      },
      "category": "myLogger"
    }
  ]
});
var logger = log4js.getLogger("myLogger");
logger.info("Test log message %s", "arg1", "arg2");

+ 37 - 0
src/server/node_modules/log4js/examples/memory-test.js

@ -0,0 +1,37 @@
var log4js = require('./lib/log4js')
, logger
, usage
, i;
log4js.configure(
    {
        appenders: [
            {
                category: "memory-test"
              , type: "file"
              , filename: "memory-test.log"
            },
            {
                type: "console"
              , category: "memory-usage"
            },
            {
                type: "file"
              , filename: "memory-usage.log"
              , category: "memory-usage"
              , layout: {
                  type: "messagePassThrough"
              }
            }
        ]
    }
);
logger = log4js.getLogger("memory-test");
usage = log4js.getLogger("memory-usage");
for (i=0; i < 1000000; i++) {
    if ( (i % 5000) === 0) {
        usage.info("%d %d", i, process.memoryUsage().rss);
    }
    logger.info("Doing something.");
}

+ 11 - 0
src/server/node_modules/log4js/examples/missing-log-dir.js

@ -0,0 +1,11 @@
var log4js = require('../lib/log4js');
log4js.configure({
  appenders: [
    { type: "file", filename: "madeup/path/to/file.log" }
  ],
  replaceConsole: true
});
logger = log4js.getLogger();
logger.info("Does this work?");

+ 21 - 0
src/server/node_modules/log4js/examples/patternLayout-tokens.js

@ -0,0 +1,21 @@
var log4js = require('./lib/log4js');
var config = {
    "appenders": [
      {
        "type": "console",
        "layout": {
          "type": "pattern",
          "pattern": "%[%r (%x{pid}) %p %c -%] %m%n",
          "tokens": {
            "pid" : function() { return process.pid; }
          }
        }
      }
    ]
  };
log4js.configure(config, {});
var logger = log4js.getLogger("app");
logger.info("Test log message");

+ 43 - 0
src/server/node_modules/log4js/examples/smtp-appender.js

@ -0,0 +1,43 @@
//Note that smtp appender needs nodemailer to work.
//If you haven't got nodemailer installed, you'll get cryptic
//"cannot find module" errors when using the smtp appender
var log4js = require('../lib/log4js')
, log
, logmailer
, i = 0;
log4js.configure({
  "appenders": [
    {
      type: "console",
      category: "test"
    },
    {
      "type": "smtp",
      "recipients": "logfilerecipient@logging.com",
      "sendInterval": 5,
      "transport": "SMTP",
      "SMTP": {
        "host": "smtp.gmail.com",
        "secureConnection": true,
        "port": 465,
        "auth": {
          "user": "someone@gmail",
          "pass": "********************"
        },
        "debug": true
      },
      "category": "mailer"
    }
  ]
});
log = log4js.getLogger("test");
logmailer = log4js.getLogger("mailer");
function doTheLogging(x) {
    log.info("Logging something %d", x);
    logmailer.info("Logging something %d", x);
}
for ( ; i < 500; i++) {
    doTheLogging(i);
}

+ 20 - 0
src/server/node_modules/log4js/lib/appenders/categoryFilter.js

@ -0,0 +1,20 @@
"use strict";
var log4js = require('../log4js');
function categoryFilter (excludes, appender) {
  if (typeof(excludes) === 'string') excludes = [excludes];
  return function(logEvent) {
    if (excludes.indexOf(logEvent.categoryName) === -1) {
      appender(logEvent);
    }
  };
}
function configure(config) {
  log4js.loadAppender(config.appender.type);
  var appender = log4js.appenderMakers[config.appender.type](config.appender);
  return categoryFilter(config.exclude, appender);
}
exports.appender = categoryFilter;
exports.configure = configure;

+ 129 - 0
src/server/node_modules/log4js/lib/appenders/clustered.js

@ -0,0 +1,129 @@
"use strict";
var cluster = require('cluster');
var log4js = require('../log4js');
/**
 * Takes a loggingEvent object, returns string representation of it.
 */
function serializeLoggingEvent(loggingEvent) {
	// JSON.stringify(new Error('test')) returns {}, which is not really useful for us.
	// The following allows us to serialize errors correctly.
	for (var i = 0; i < loggingEvent.data.length; i++) {
		var item = loggingEvent.data[i];
		if (item && item.stack && JSON.stringify(item) === '{}') { // Validate that we really are in this case
			loggingEvent.data[i] = {stack : item.stack};
		}
	}
	return JSON.stringify(loggingEvent);
}
/**
 * Takes a string, returns an object with
 * the correct log properties.
 *
 * This method has been "borrowed" from the `multiprocess` appender 
 * by `nomiddlename` (https://github.com/nomiddlename/log4js-node/blob/master/lib/appenders/multiprocess.js)
 *
 * Apparently, node.js serializes everything to strings when using `process.send()`, 
 * so we need smart deserialization that will recreate log date and level for further processing by log4js internals.
 */
function deserializeLoggingEvent(loggingEventString) {
	var loggingEvent;
	
	try {
	
		loggingEvent = JSON.parse(loggingEventString);
		loggingEvent.startTime = new Date(loggingEvent.startTime);
		loggingEvent.level = log4js.levels.toLevel(loggingEvent.level.levelStr);
		
	} catch (e) {
		
		// JSON.parse failed, just log the contents probably a naughty.
		loggingEvent = {
			startTime: new Date(),
			categoryName: 'log4js',
			level: log4js.levels.ERROR,
			data: [ 'Unable to parse log:', loggingEventString ]
		};
	}
	return loggingEvent;
} 
/**
 * Creates an appender. 
 *
 * If the current process is a master (`cluster.isMaster`), then this will be a "master appender".
 * Otherwise this will be a worker appender, that just sends loggingEvents to the master process.
 *
 * If you are using this method directly, make sure to provide it with `config.actualAppenders` array 
 * of actual appender instances.
 *
 * Or better use `configure(config, options)`
 */
function createAppender(config) {
	if (cluster.isMaster) {
		var masterAppender = function(loggingEvent) {
	
			if (config.actualAppenders) {
				var size = config.actualAppenders.length;
				for(var i = 0; i < size; i++) {
			                if (!config.appenders[i].category || config.appenders[i].category === loggingEvent.categoryName) {
						// Relying on the index is not a good practice but otherwise the change would have been bigger.
						config.actualAppenders[i](loggingEvent);
                    			}
				}
			}
		}
		
		// Listen on new workers
		cluster.on('fork', function(worker) {
		
			worker.on('message', function(message) {
				if (message.type && message.type === '::log-message') {
					// console.log("master : " + cluster.isMaster + " received message: " + JSON.stringify(message.event));
					
					var loggingEvent = deserializeLoggingEvent(message.event);
					masterAppender(loggingEvent);
				}
			});
		
		});
		
		return masterAppender;
		
	} else {
		return function(loggingEvent) {
			// If inside the worker process, then send the logger event to master.
			if (cluster.isWorker) {
				// console.log("worker " + cluster.worker.id + " is sending message");
				process.send({ type: '::log-message', event: serializeLoggingEvent(loggingEvent)});
			}
		}
	}
}
function configure(config, options) {
	if (config.appenders && cluster.isMaster) {
	
		var size = config.appenders.length;
		config.actualAppenders = new Array(size);
	
		for(var i = 0; i < size; i++) {
		
			log4js.loadAppender(config.appenders[i].type);
			config.actualAppenders[i] = log4js.appenderMakers[config.appenders[i].type](config.appenders[i], options);
		
		}
	}
	
	return createAppender(config);
}
exports.appender = createAppender;
exports.configure = configure; 

+ 21 - 0
src/server/node_modules/log4js/lib/appenders/console.js

@ -0,0 +1,21 @@
"use strict";
var layouts = require('../layouts')
, consoleLog = console.log.bind(console);
function consoleAppender (layout) {
  layout = layout || layouts.colouredLayout;
  return function(loggingEvent) {
    consoleLog(layout(loggingEvent));
  };
}
function configure(config) {
  var layout;
  if (config.layout) {
    layout = layouts.layout(config.layout.type, config.layout);
  }
  return consoleAppender(layout);
}
exports.appender = consoleAppender;
exports.configure = configure;

+ 72 - 0
src/server/node_modules/log4js/lib/appenders/dateFile.js

@ -0,0 +1,72 @@
"use strict";
var streams = require('../streams')
, layouts = require('../layouts')
, async = require('async')
, path = require('path')
, os = require('os')
, eol = os.EOL || '\n'
, openFiles = [];
//close open files on process exit.
process.on('exit', function() {
  openFiles.forEach(function (file) {
    file.end();
  });
});
/**
 * File appender that rolls files according to a date pattern.
 * @filename base filename.
 * @pattern the format that will be added to the end of filename when rolling,
 *          also used to check when to roll files - defaults to '.yyyy-MM-dd'
 * @layout layout function for log messages - defaults to basicLayout
 */
function appender(filename, pattern, alwaysIncludePattern, layout) {
  layout = layout || layouts.basicLayout;
  var logFile = new streams.DateRollingFileStream(
    filename,
    pattern,
    { alwaysIncludePattern: alwaysIncludePattern }
  );
  openFiles.push(logFile);
  return function(logEvent) {
    logFile.write(layout(logEvent) + eol, "utf8");
  };
}
function configure(config, options) {
  var layout;
  if (config.layout) {
    layout = layouts.layout(config.layout.type, config.layout);
  }
  if (!config.alwaysIncludePattern) {
    config.alwaysIncludePattern = false;
  }
  if (options && options.cwd && !config.absolute) {
    config.filename = path.join(options.cwd, config.filename);
  }
  return appender(config.filename, config.pattern, config.alwaysIncludePattern, layout);
}
function shutdown(cb) {
  async.each(openFiles, function(file, done) {
    if (!file.write(eol, "utf-8")) {
      file.once('drain', function() {
        file.end(done);
      });
    } else {
      file.end(done);
    }
  }, cb);
}
exports.appender = appender;
exports.configure = configure;
exports.shutdown = shutdown;

+ 96 - 0
src/server/node_modules/log4js/lib/appenders/file.js

@ -0,0 +1,96 @@
"use strict";
var layouts = require('../layouts')
, async = require('async')
, path = require('path')
, fs = require('fs')
, streams = require('../streams')
, os = require('os')
, eol = os.EOL || '\n'
, openFiles = [];
//close open files on process exit.
process.on('exit', function() {
  openFiles.forEach(function (file) {
    file.end();
  });
});
/**
 * File Appender writing the logs to a text file. Supports rolling of logs by size.
 *
 * @param file file log messages will be written to
 * @param layout a function that takes a logevent and returns a string 
 *   (defaults to basicLayout).
 * @param logSize - the maximum size (in bytes) for a log file, 
 *   if not provided then logs won't be rotated.
 * @param numBackups - the number of log files to keep after logSize 
 *   has been reached (default 5)
 */
function fileAppender (file, layout, logSize, numBackups) {
  var bytesWritten = 0;
  file = path.normalize(file);
  layout = layout || layouts.basicLayout;
  numBackups = numBackups === undefined ? 5 : numBackups;
  //there has to be at least one backup if logSize has been specified
  numBackups = numBackups === 0 ? 1 : numBackups;
  function openTheStream(file, fileSize, numFiles) {
    var stream;
    if (fileSize) {
      stream = new streams.RollingFileStream(
        file,
        fileSize,
        numFiles
      );
    } else {
      stream = fs.createWriteStream(
        file, 
        { encoding: "utf8", 
          mode: parseInt('0644', 8), 
          flags: 'a' }
      );
    }
    stream.on("error", function (err) {
      console.error("log4js.fileAppender - Writing to file %s, error happened ", file, err);
    });
    return stream;
  }
  var logFile = openTheStream(file, logSize, numBackups);
  
  // push file to the stack of open handlers
  openFiles.push(logFile);
  
  return function(loggingEvent) {
    logFile.write(layout(loggingEvent) + eol, "utf8");
  };
}
function configure(config, options) {
  var layout;
  if (config.layout) {
    layout = layouts.layout(config.layout.type, config.layout);
  }
  if (options && options.cwd && !config.absolute) {
    config.filename = path.join(options.cwd, config.filename);
  }
  return fileAppender(config.filename, layout, config.maxLogSize, config.backups);
}
function shutdown(cb) {
  async.each(openFiles, function(file, done) {
    if (!file.write(eol, "utf-8")) {
      file.once('drain', function() {
        file.end(done);
      });
    } else {
      file.end(done);
    }
  }, cb);
}  
exports.appender = fileAppender;
exports.configure = configure;
exports.shutdown = shutdown;

+ 187 - 0
src/server/node_modules/log4js/lib/appenders/fileSync.js

@ -0,0 +1,187 @@
"use strict";
var debug = require('../debug')('fileSync')
, layouts = require('../layouts')
, path = require('path')
, fs = require('fs')
, streams = require('../streams')
, os = require('os')
, eol = os.EOL || '\n'
;
function RollingFileSync (filename, size, backups, options) {
  debug("In RollingFileStream");
  function throwErrorIfArgumentsAreNotValid() {
    if (!filename || !size || size <= 0) {
      throw new Error("You must specify a filename and file size");
    }
  }
  
  throwErrorIfArgumentsAreNotValid();
  
  this.filename = filename;
  this.size = size;
  this.backups = backups || 1;
  this.options = options || { encoding: 'utf8', mode: parseInt('0644', 8), flags: 'a' };
  this.currentSize = 0;
  
  function currentFileSize(file) {
    var fileSize = 0;
    try {
      fileSize = fs.statSync(file).size;
    } catch (e) {
      // file does not exist
      fs.appendFileSync(filename, '');
    }
    return fileSize;
  }
  this.currentSize = currentFileSize(this.filename);
}
RollingFileSync.prototype.shouldRoll = function() {
  debug("should roll with current size %d, and max size %d", this.currentSize, this.size);
  return this.currentSize >= this.size;
};
RollingFileSync.prototype.roll = function(filename) {
  var that = this,
  nameMatcher = new RegExp('^' + path.basename(filename));
  
  function justTheseFiles (item) {
    return nameMatcher.test(item);
  }
  
  function index(filename_) {
    return parseInt(filename_.substring((path.basename(filename) + '.').length), 10) || 0;
  }
  
  function byIndex(a, b) {
    if (index(a) > index(b)) {
      return 1;
    } else if (index(a) < index(b) ) {
      return -1;
    } else {
      return 0;
    }
  }
  function increaseFileIndex (fileToRename) {
    var idx = index(fileToRename);
    debug('Index of ' + fileToRename + ' is ' + idx);
    if (idx < that.backups) {
      //on windows, you can get a EEXIST error if you rename a file to an existing file
      //so, we'll try to delete the file we're renaming to first
      try {
        fs.unlinkSync(filename + '.' + (idx+1));
      } catch(e) {
        //ignore err: if we could not delete, it's most likely that it doesn't exist
      }
      
      debug('Renaming ' + fileToRename + ' -> ' + filename + '.' + (idx+1));
      fs.renameSync(path.join(path.dirname(filename), fileToRename), filename + '.' + (idx + 1));
    }
  }
  function renameTheFiles() {
    //roll the backups (rename file.n to file.n+1, where n <= numBackups)
    debug("Renaming the old files");
    
    var files = fs.readdirSync(path.dirname(filename));
    files.filter(justTheseFiles).sort(byIndex).reverse().forEach(increaseFileIndex);
  }
  debug("Rolling, rolling, rolling");
  renameTheFiles();
};
RollingFileSync.prototype.write = function(chunk, encoding) {
  var that = this;
  
  
  function writeTheChunk() {
    debug("writing the chunk to the file");
    that.currentSize += chunk.length;
    fs.appendFileSync(that.filename, chunk);
  }
  debug("in write");
  
  if (this.shouldRoll()) {
    this.currentSize = 0;
    this.roll(this.filename);
  }
  
  writeTheChunk();
};
/**
 * File Appender writing the logs to a text file. Supports rolling of logs by size.
 *
 * @param file file log messages will be written to
 * @param layout a function that takes a logevent and returns a string 
 *   (defaults to basicLayout).
 * @param logSize - the maximum size (in bytes) for a log file, 
 *   if not provided then logs won't be rotated.
 * @param numBackups - the number of log files to keep after logSize 
 *   has been reached (default 5)
 */
function fileAppender (file, layout, logSize, numBackups) {
  debug("fileSync appender created");
  var bytesWritten = 0;
  file = path.normalize(file);
  layout = layout || layouts.basicLayout;
  numBackups = numBackups === undefined ? 5 : numBackups;
  //there has to be at least one backup if logSize has been specified
  numBackups = numBackups === 0 ? 1 : numBackups;
  function openTheStream(file, fileSize, numFiles) {
    var stream;
    
    if (fileSize) {
      stream = new RollingFileSync(
        file,
        fileSize,
        numFiles
      );
    } else {
      stream = (function(f) {
        // create file if it doesn't exist
        if (!fs.existsSync(f))
            fs.appendFileSync(f, '');
        
        return {
            write: function(data) {
                fs.appendFileSync(f, data);
            }
        };
      })(file);
    }
    return stream;
  }
  var logFile = openTheStream(file, logSize, numBackups);
  
  return function(loggingEvent) {
    logFile.write(layout(loggingEvent) + eol);
  };
}
function configure(config, options) {
  var layout;
  if (config.layout) {
    layout = layouts.layout(config.layout.type, config.layout);
  }
  if (options && options.cwd && !config.absolute) {
    config.filename = path.join(options.cwd, config.filename);
  }
  return fileAppender(config.filename, layout, config.maxLogSize, config.backups);
}
exports.appender = fileAppender;
exports.configure = configure;

+ 142 - 0
src/server/node_modules/log4js/lib/appenders/gelf.js

@ -0,0 +1,142 @@
"use strict";
var zlib = require('zlib');
var layouts = require('../layouts');
var levels = require('../levels');
var dgram = require('dgram');
var util = require('util');
var debug = require('../debug')('GELF Appender');
var LOG_EMERG=0;    // system is unusable
var LOG_ALERT=1;    // action must be taken immediately
var LOG_CRIT=2;     // critical conditions
var LOG_ERR=3;      // error conditions
var LOG_ERROR=3;    // because people WILL typo
var LOG_WARNING=4;  // warning conditions
var LOG_NOTICE=5;   // normal, but significant, condition
var LOG_INFO=6;     // informational message
var LOG_DEBUG=7;    // debug-level message
var levelMapping = {};
levelMapping[levels.ALL] = LOG_DEBUG;
levelMapping[levels.TRACE] = LOG_DEBUG;
levelMapping[levels.DEBUG] = LOG_DEBUG;
levelMapping[levels.INFO] = LOG_INFO;
levelMapping[levels.WARN] = LOG_WARNING;
levelMapping[levels.ERROR] = LOG_ERR;
levelMapping[levels.FATAL] = LOG_CRIT;
/**
 * GELF appender that supports sending UDP packets to a GELF compatible server such as Graylog
 *
 * @param layout a function that takes a logevent and returns a string (defaults to none).
 * @param host - host to which to send logs (default:localhost)
 * @param port - port at which to send logs to (default:12201)
 * @param hostname - hostname of the current host (default:os hostname)
 * @param facility - facility to log to (default:nodejs-server)
 */
function gelfAppender (layout, host, port, hostname, facility) {
  var config, customFields;
  if (typeof(host) === 'object') {
    config = host;
    host = config.host;
    port = config.port;
    hostname = config.hostname;
    facility = config.facility;
    customFields = config.customFields;
  }
  
  host = host || 'localhost';
  port = port || 12201;
  hostname = hostname || require('os').hostname();
  layout = layout || layouts.messagePassThroughLayout;
  var defaultCustomFields = customFields || {};
  if(facility) {
    defaultCustomFields['_facility'] = facility;
  }
  var client = dgram.createSocket("udp4");
  
  process.on('exit', function() {
    if (client) client.close();
  });
  /**
   * Add custom fields (start with underscore ) 
   * - if the first object passed to the logger contains 'GELF' field, 
   *   copy the underscore fields to the message
   * @param loggingEvent
   * @param msg
   */
  function addCustomFields(loggingEvent, msg){
    /* append defaultCustomFields firsts */
    Object.keys(defaultCustomFields).forEach(function(key) {
      // skip _id field for graylog2, skip keys not starts with UNDERSCORE
      if (key.match(/^_/) && key !== "_id") { 
        msg[key] = defaultCustomFields[key];
      }
    });
    /* append custom fields per message */
    var data = loggingEvent.data;
    if (!Array.isArray(data) || data.length === 0) return;
    var firstData = data[0];
    
    if (!firstData.GELF) return; // identify with GELF field defined
    Object.keys(firstData).forEach(function(key) {
      // skip _id field for graylog2, skip keys not starts with UNDERSCORE
      if (key.match(/^_/) || key !== "_id") { 
        msg[key] = firstData[key];
      }
    });
    
    /* the custom field object should be removed, so it will not be looged by the later appenders */
    loggingEvent.data.shift(); 
  }
 
  function preparePacket(loggingEvent) {
    var msg = {};
    addCustomFields(loggingEvent, msg);
    msg.short_message = layout(loggingEvent);
    
    msg.version="1.1";
    msg.timestamp = msg.timestamp || new Date().getTime() / 1000; // log should use millisecond 
    msg.host = hostname;
    msg.level = levelMapping[loggingEvent.level || levels.DEBUG];
    return msg;
  }
  
  function sendPacket(packet) {
    try {
      client.send(packet, 0, packet.length, port, host);
    } catch(e) {}
  }
  return function(loggingEvent) {
    var message = preparePacket(loggingEvent);
    zlib.gzip(new Buffer(JSON.stringify(message)), function(err, packet) {
      if (err) {
        console.error(err.stack);
      } else {
        if (packet.length > 8192) {
          debug("Message packet length (" + packet.length + ") is larger than 8k. Not sending");
        } else {
          sendPacket(packet);
        }
      }
    });
  };
}
function configure(config) {
  var layout;
  if (config.layout) {
    layout = layouts.layout(config.layout.type, config.layout);
  }
  return gelfAppender(layout, config);
}
exports.appender = gelfAppender;
exports.configure = configure;

+ 23 - 0
src/server/node_modules/log4js/lib/appenders/logLevelFilter.js

@ -0,0 +1,23 @@
"use strict";
var levels = require('../levels')
, log4js = require('../log4js');
function logLevelFilter (minLevelString, maxLevelString, appender) {
  var minLevel = levels.toLevel(minLevelString);
  var maxLevel = levels.toLevel(maxLevelString, levels.FATAL);
  return function(logEvent) {
      var eventLevel = logEvent.level;
      if (eventLevel.isGreaterThanOrEqualTo(minLevel) && eventLevel.isLessThanOrEqualTo(maxLevel)) {
      appender(logEvent);
    }
  };
}
function configure(config, options) {
  log4js.loadAppender(config.appender.type);
  var appender = log4js.appenderMakers[config.appender.type](config.appender, options);
  return logLevelFilter(config.level, config.maxLevel, appender);
}
exports.appender = logLevelFilter;
exports.configure = configure;

+ 44 - 0
src/server/node_modules/log4js/lib/appenders/loggly.js

@ -0,0 +1,44 @@
'use strict';
var layouts = require('../layouts')
, loggly = require('loggly')
, os = require('os')
, passThrough = layouts.messagePassThroughLayout;
/**
 * Loggly Appender. Sends logging events to Loggly using node-loggly 
 *
 * @param config object with loggly configuration data
 * {
 *   token: 'your-really-long-input-token',
 *   subdomain: 'your-subdomain',
 *   tags: ['loggly-tag1', 'loggly-tag2', .., 'loggly-tagn'] 
 * }
 * @param layout a function that takes a logevent and returns a string (defaults to objectLayout).
 */
function logglyAppender(config, layout) {
	var client = loggly.createClient(config);
  if(!layout) layout = passThrough;
  return function(loggingEvent) {
		var msg = layout(loggingEvent);
		client.log({
			msg: msg,
			level: loggingEvent.level.levelStr,
			category: loggingEvent.categoryName,
			hostname: os.hostname().toString(),
		});
  }
}
function configure(config) {
	var layout;
	if (config.layout) {
		layout = layouts.layout(config.layout.type, config.layout);
	}
	return logglyAppender(config, layout);
}
exports.name      = 'loggly';
exports.appender  = logglyAppender;
exports.configure = configure;

+ 50 - 0
src/server/node_modules/log4js/lib/appenders/logstashUDP.js

@ -0,0 +1,50 @@
"use strict";
var layouts = require('../layouts')
, dgram = require('dgram')
, util = require('util');
function logstashUDP (config, layout) {
  var udp = dgram.createSocket('udp4');
  var type = config.logType ? config.logType : config.category;
  layout = layout || layouts.colouredLayout;
  if(!config.fields) {
    config.fields = {};
  }
  return function(loggingEvent) {
    var logMessage = layout(loggingEvent);
    var fields = {};
    for(var i in config.fields) {
      fields[i] = config.fields[i];
    }
    fields['level'] = loggingEvent.level.levelStr;
    var logObject = {
      '@timestamp': (new Date(loggingEvent.startTime)).toISOString(),
      type: type,
      message: logMessage,
      fields: fields
    };
    sendLog(udp, config.host, config.port, logObject);
  };
}
function sendLog(udp, host, port, logObject) {
  var buffer = new Buffer(JSON.stringify(logObject));
  udp.send(buffer, 0, buffer.length, port, host, function(err, bytes) {
    if(err) {
      console.error(
        "log4js.logstashUDP - %s:%p Error: %s", host, port, util.inspect(err)
      );
    }
  });
}
function configure(config) {
  var layout;
  if (config.layout) {
    layout = layouts.layout(config.layout.type, config.layout);
  }
  return logstashUDP(config, layout);
}
exports.appender = logstashUDP;
exports.configure = configure;

+ 134 - 0
src/server/node_modules/log4js/lib/appenders/multiprocess.js

@ -0,0 +1,134 @@
"use strict";
var log4js = require('../log4js')
, net = require('net')
, END_MSG = '__LOG4JS__';
/**
 * Creates a server, listening on config.loggerPort, config.loggerHost.
 * Output goes to config.actualAppender (config.appender is used to
 * set up that appender).
 */
function logServer(config) {
  
  /**
   * Takes a utf-8 string, returns an object with
   * the correct log properties.
   */
  function deserializeLoggingEvent(clientSocket, msg) {
    var loggingEvent;
    try {
      loggingEvent = JSON.parse(msg);
      loggingEvent.startTime = new Date(loggingEvent.startTime);
      loggingEvent.level = log4js.levels.toLevel(loggingEvent.level.levelStr);
    } catch (e) {
      // JSON.parse failed, just log the contents probably a naughty.
      loggingEvent = {
        startTime: new Date(),
        categoryName: 'log4js',
        level: log4js.levels.ERROR,
        data: [ 'Unable to parse log:', msg ]
      };
    }
    loggingEvent.remoteAddress = clientSocket.remoteAddress;
    loggingEvent.remotePort = clientSocket.remotePort;
    
    return loggingEvent;
  }
  
  var actualAppender = config.actualAppender,
  server = net.createServer(function serverCreated(clientSocket) {
    clientSocket.setEncoding('utf8');
    var logMessage = '';
    
    function logTheMessage(msg) {
      if (logMessage.length > 0) {
        actualAppender(deserializeLoggingEvent(clientSocket, msg));
      }
    }
    
    function chunkReceived(chunk) {
      var event;
      logMessage += chunk || '';
      if (logMessage.indexOf(END_MSG) > -1) {
        event = logMessage.substring(0, logMessage.indexOf(END_MSG));
        logTheMessage(event);
        logMessage = logMessage.substring(event.length + END_MSG.length) || '';
        //check for more, maybe it was a big chunk
        chunkReceived();
      }
    }
    
    clientSocket.on('data', chunkReceived);
    clientSocket.on('end', chunkReceived);
  });
  
  server.listen(config.loggerPort || 5000, config.loggerHost || 'localhost');
  
  return actualAppender;
}
function workerAppender(config) {
  var canWrite = false,
  buffer = [],
  socket;
  
  createSocket();
  
  function createSocket() {
    socket = net.createConnection(config.loggerPort || 5000, config.loggerHost || 'localhost');
    socket.on('connect', function() {
      emptyBuffer();
      canWrite = true;
    });
    socket.on('timeout', socket.end.bind(socket));
    //don't bother listening for 'error', 'close' gets called after that anyway
    socket.on('close', createSocket);
  }
  
  function emptyBuffer() {
    var evt;
    while ((evt = buffer.shift())) {
      write(evt);
    }
  }
  
  function write(loggingEvent) {
	// JSON.stringify(new Error('test')) returns {}, which is not really useful for us.
	// The following allows us to serialize errors correctly.
	if (loggingEvent && loggingEvent.stack && JSON.stringify(loggingEvent) === '{}') { // Validate that we really are in this case
		loggingEvent = {stack : loggingEvent.stack};
	}
    socket.write(JSON.stringify(loggingEvent), 'utf8');
    socket.write(END_MSG, 'utf8');
  }
  
  return function log(loggingEvent) {
    if (canWrite) {
      write(loggingEvent);
    } else {
      buffer.push(loggingEvent);
    }
  };
}
function createAppender(config) {
  if (config.mode === 'master') {
    return logServer(config);
  } else {
    return workerAppender(config);
  }
}
function configure(config, options) {
  var actualAppender;
  if (config.appender && config.mode === 'master') {
    log4js.loadAppender(config.appender.type);
    actualAppender = log4js.appenderMakers[config.appender.type](config.appender, options);
    config.actualAppender = actualAppender;
  }
  return createAppender(config);
}
exports.appender = createAppender;
exports.configure = configure;

+ 82 - 0
src/server/node_modules/log4js/lib/appenders/smtp.js

@ -0,0 +1,82 @@
"use strict";
var layouts = require("../layouts")
, mailer = require("nodemailer")
, os = require('os');
/**
* SMTP Appender. Sends logging events using SMTP protocol. 
* It can either send an email on each event or group several 
* logging events gathered during specified interval.
*
* @param config appender configuration data
*    config.sendInterval time between log emails (in seconds), if 0
*    then every event sends an email
* @param layout a function that takes a logevent and returns a string (defaults to basicLayout).
*/
function smtpAppender(config, layout) {
	layout = layout || layouts.basicLayout;
	var subjectLayout = layouts.messagePassThroughLayout;
	var sendInterval = config.sendInterval*1000 || 0;
	
	var logEventBuffer = [];
	var sendTimer;
	
	function sendBuffer() {
    if (logEventBuffer.length > 0) {
		
      var transport = mailer.createTransport(config.transport, config[config.transport]);
      var firstEvent = logEventBuffer[0];
      var body = "";
      while (logEventBuffer.length > 0) {
        body += layout(logEventBuffer.shift()) + "\n";
      }
      var msg = {
        to: config.recipients,
        subject: config.subject || subjectLayout(firstEvent),
        text: body,
        headers: { "Hostname": os.hostname() }
      };
      if (config.sender) {
        msg.from = config.sender;
      }
      transport.sendMail(msg, function(error, success) {
        if (error) {
          console.error("log4js.smtpAppender - Error happened", error);
        }
        transport.close();
      });
    }
	}
	
	function scheduleSend() {
		if (!sendTimer) {
			sendTimer = setTimeout(function() {
				sendTimer = null; 
				sendBuffer();
			}, sendInterval);
    }
	}
	
	return function(loggingEvent) {
		logEventBuffer.push(loggingEvent);
		if (sendInterval > 0) {
			scheduleSend();
		} else {
			sendBuffer();
    }
	};
}
function configure(config) {
	var layout;
	if (config.layout) {
		layout = layouts.layout(config.layout.type, config.layout);
	}
	return smtpAppender(config, layout);
}
exports.name = "smtp";
exports.appender = smtpAppender;
exports.configure = configure;

+ 200 - 0
src/server/node_modules/log4js/lib/connect-logger.js

@ -0,0 +1,200 @@
"use strict";
var levels = require("./levels");
var DEFAULT_FORMAT = ':remote-addr - -' + 
  ' ":method :url HTTP/:http-version"' + 
  ' :status :content-length ":referrer"' + 
  ' ":user-agent"';
/**
 * Log requests with the given `options` or a `format` string.
 *
 * Options:
 *
 *   - `format`        Format string, see below for tokens
 *   - `level`         A log4js levels instance. Supports also 'auto'
 *
 * Tokens:
 *
 *   - `:req[header]` ex: `:req[Accept]`
 *   - `:res[header]` ex: `:res[Content-Length]`
 *   - `:http-version`
 *   - `:response-time`
 *   - `:remote-addr`
 *   - `:date`
 *   - `:method`
 *   - `:url`
 *   - `:referrer`
 *   - `:user-agent`
 *   - `:status`
 *
 * @param {String|Function|Object} format or options
 * @return {Function}
 * @api public
 */
function getLogger(logger4js, options) {
	if ('object' == typeof options) {
		options = options || {};
	} else if (options) {
		options = { format: options };
	} else {
		options = {};
	}
	var thislogger = logger4js
  , level = levels.toLevel(options.level, levels.INFO)
  , fmt = options.format || DEFAULT_FORMAT
  , nolog = options.nolog ? createNoLogCondition(options.nolog) : null;
  return function (req, res, next) {
    // mount safety
    if (req._logging) return next();
		// nologs
		if (nolog && nolog.test(req.originalUrl)) return next();
		if (thislogger.isLevelEnabled(level) || options.level === 'auto') {
      
			var start = new Date()
			, statusCode
			, writeHead = res.writeHead
			, end = res.end
			, url = req.originalUrl;
			// flag as logging
			req._logging = true;
      
			// proxy for statusCode.
			res.writeHead = function(code, headers){
				res.writeHead = writeHead;
				res.writeHead(code, headers);
				res.__statusCode = statusCode = code;
				res.__headers = headers || {};
				//status code response level handling
				if(options.level === 'auto'){
					level = levels.INFO;
					if(code >= 300) level = levels.WARN;
					if(code >= 400) level = levels.ERROR;
				} else {
					level = levels.toLevel(options.level, levels.INFO);
				}
			};
      
			// proxy end to output a line to the provided logger.
			res.end = function(chunk, encoding) {
				res.end = end;
				res.end(chunk, encoding);
				res.responseTime = new Date() - start;
				//status code response level handling
				if(res.statusCode && options.level === 'auto'){
					level = levels.INFO;
					if(res.statusCode >= 300) level = levels.WARN;
					if(res.statusCode >= 400) level = levels.ERROR;
				}
				if (thislogger.isLevelEnabled(level)) {
					if (typeof fmt === 'function') {
						var line = fmt(req, res, function(str){ return format(str, req, res); });
						if (line) thislogger.log(level, line);
					} else {
						thislogger.log(level, format(fmt, req, res));
					}
				}
			};
		}
    
    //ensure next gets always called
    next();
  };
}
/**
 * Return formatted log line.
 *
 * @param  {String} str
 * @param  {IncomingMessage} req
 * @param  {ServerResponse} res
 * @return {String}
 * @api private
 */
function format(str, req, res) {
	return str
    .replace(':url', req.originalUrl)
    .replace(':method', req.method)
    .replace(':status', res.__statusCode || res.statusCode)
    .replace(':response-time', res.responseTime)
    .replace(':date', new Date().toUTCString())
    .replace(':referrer', req.headers.referer || req.headers.referrer || '')
    .replace(':http-version', req.httpVersionMajor + '.' + req.httpVersionMinor)
    .replace(
      ':remote-addr', req.ip || req._remoteAddress || ( 
      req.socket && 
        (req.socket.remoteAddress || (req.socket.socket && req.socket.socket.remoteAddress))
    ))
    .replace(':user-agent', req.headers['user-agent'] || '')
    .replace(
      ':content-length', 
      (res._headers && res._headers['content-length']) || 
        (res.__headers && res.__headers['Content-Length']) || 
        '-'
    )
    .replace(/:req\[([^\]]+)\]/g, function(_, field){ return req.headers[field.toLowerCase()]; })
    .replace(/:res\[([^\]]+)\]/g, function(_, field){
      return res._headers ? 
        (res._headers[field.toLowerCase()] || res.__headers[field])
        : (res.__headers && res.__headers[field]);
    });
}
/**
 * Return RegExp Object about nolog
 *
 * @param  {String} nolog
 * @return {RegExp}
 * @api private
 *
 * syntax
 *  1. String
 *   1.1 "\\.gif"
 *         NOT LOGGING http://example.com/hoge.gif and http://example.com/hoge.gif?fuga
 *         LOGGING http://example.com/hoge.agif
 *   1.2 in "\\.gif|\\.jpg$"
 *         NOT LOGGING http://example.com/hoge.gif and 
 *           http://example.com/hoge.gif?fuga and http://example.com/hoge.jpg?fuga
 *         LOGGING http://example.com/hoge.agif, 
 *           http://example.com/hoge.ajpg and http://example.com/hoge.jpg?hoge
 *   1.3 in "\\.(gif|jpe?g|png)$"
 *         NOT LOGGING http://example.com/hoge.gif and http://example.com/hoge.jpeg
 *         LOGGING http://example.com/hoge.gif?uid=2 and http://example.com/hoge.jpg?pid=3
 *  2. RegExp
 *   2.1 in /\.(gif|jpe?g|png)$/
 *         SAME AS 1.3
 *  3. Array
 *   3.1 ["\\.jpg$", "\\.png", "\\.gif"]
 *         SAME AS "\\.jpg|\\.png|\\.gif"
 */
function createNoLogCondition(nolog) {
  var regexp = null;
	if (nolog) {
    if (nolog instanceof RegExp) {
      regexp = nolog;
    } 
    
    if (typeof nolog === 'string') {
      regexp = new RegExp(nolog);
    }
    
    if (Array.isArray(nolog)) {
      var regexpsAsStrings = nolog.map(
        function convertToStrings(o) { 
          return o.source ? o.source : o;
        }
      );
      regexp = new RegExp(regexpsAsStrings.join('|'));
    }
  }
  return regexp;
}
exports.connectLogger = getLogger;

+ 66 - 0
src/server/node_modules/log4js/lib/date_format.js

@ -0,0 +1,66 @@
"use strict";
exports.ISO8601_FORMAT = "yyyy-MM-dd hh:mm:ss.SSS";
exports.ISO8601_WITH_TZ_OFFSET_FORMAT = "yyyy-MM-ddThh:mm:ssO";
exports.DATETIME_FORMAT = "dd MM yyyy hh:mm:ss.SSS";
exports.ABSOLUTETIME_FORMAT = "hh:mm:ss.SSS";
function padWithZeros(vNumber, width) {
  var numAsString = vNumber + "";
  while (numAsString.length < width) {
    numAsString = "0" + numAsString;
  }
  return numAsString;
}
  
function addZero(vNumber) {
  return padWithZeros(vNumber, 2);
}
/**
 * Formats the TimeOffest
 * Thanks to http://www.svendtofte.com/code/date_format/
 * @private
 */
function offset(date) {
  // Difference to Greenwich time (GMT) in hours
  var os = Math.abs(date.getTimezoneOffset());
  var h = String(Math.floor(os/60));
  var m = String(os%60);
  if (h.length == 1) {
    h = "0" + h;
  }
  if (m.length == 1) {
    m = "0" + m;
  }
  return date.getTimezoneOffset() < 0 ? "+"+h+m : "-"+h+m;
}
exports.asString = function(/*format,*/ date) {
  var format = exports.ISO8601_FORMAT;
  if (typeof(date) === "string") {
    format = arguments[0];
    date = arguments[1];
  }
  var vDay = addZero(date.getDate());
  var vMonth = addZero(date.getMonth()+1);
  var vYearLong = addZero(date.getFullYear());
  var vYearShort = addZero(date.getFullYear().toString().substring(2,4));
  var vYear = (format.indexOf("yyyy") > -1 ? vYearLong : vYearShort);
  var vHour  = addZero(date.getHours());
  var vMinute = addZero(date.getMinutes());
  var vSecond = addZero(date.getSeconds());
  var vMillisecond = padWithZeros(date.getMilliseconds(), 3);
  var vTimeZone = offset(date);
  var formatted = format
    .replace(/dd/g, vDay)
    .replace(/MM/g, vMonth)
    .replace(/y{1,4}/g, vYear)
    .replace(/hh/g, vHour)
    .replace(/mm/g, vMinute)
    .replace(/ss/g, vSecond)
    .replace(/SSS/g, vMillisecond)
    .replace(/O/g, vTimeZone);
  return formatted;
};

+ 15 - 0
src/server/node_modules/log4js/lib/debug.js

@ -0,0 +1,15 @@
"use strict";
module.exports = function(label) {
  var debug;
  if (process.env.NODE_DEBUG && /\blog4js\b/.test(process.env.NODE_DEBUG)) {
    debug = function(message) { 
      console.error('LOG4JS: (%s) %s', label, message); 
    };
  } else {
    debug = function() { };
  }
  return debug;
};

+ 324 - 0
src/server/node_modules/log4js/lib/layouts.js

@ -0,0 +1,324 @@
"use strict";
var dateFormat = require('./date_format')
, os = require('os')
, eol = os.EOL || '\n'
, util = require('util')
, replacementRegExp = /%[sdj]/g
, layoutMakers = {
  "messagePassThrough": function() { return messagePassThroughLayout; }, 
  "basic": function() { return basicLayout; }, 
  "colored": function() { return colouredLayout; }, 
  "coloured": function() { return colouredLayout; }, 
  "pattern": function (config) {
    return patternLayout(config && config.pattern, config && config.tokens);
	}
}
, colours = {
  ALL: "grey", 
  TRACE: "blue", 
  DEBUG: "cyan", 
  INFO: "green", 
  WARN: "yellow", 
  ERROR: "red", 
  FATAL: "magenta", 
  OFF: "grey"
};
function wrapErrorsWithInspect(items) {
  return items.map(function(item) {
    if ((item instanceof Error) && item.stack) {
      return { inspect: function() { return util.format(item) + '\n' + item.stack; } };
    } else {
      return item;
    }
  });
}
function formatLogData(logData) {
  var data = Array.isArray(logData) ? logData : Array.prototype.slice.call(arguments);
  return util.format.apply(util, wrapErrorsWithInspect(data));
}
var styles = {
    //styles
  'bold'      : [1,  22],
  'italic'    : [3,  23],
  'underline' : [4,  24],
  'inverse'   : [7,  27],
  //grayscale
  'white'     : [37, 39],
  'grey'      : [90, 39],
  'black'     : [90, 39],
  //colors
  'blue'      : [34, 39],
  'cyan'      : [36, 39],
  'green'     : [32, 39],
  'magenta'   : [35, 39],
  'red'       : [31, 39],
  'yellow'    : [33, 39]
};
function colorizeStart(style) {
  return style ? '\x1B[' + styles[style][0] + 'm' : '';
}
function colorizeEnd(style) {
  return style ? '\x1B[' + styles[style][1] + 'm' : '';
}
/**
 * Taken from masylum's fork (https://github.com/masylum/log4js-node)
 */
function colorize (str, style) {
  return colorizeStart(style) + str + colorizeEnd(style);
}
function timestampLevelAndCategory(loggingEvent, colour) {
  var output = colorize(
    formatLogData(
      '[%s] [%s] %s - '
      , dateFormat.asString(loggingEvent.startTime)
      , loggingEvent.level
      , loggingEvent.categoryName
    )
    , colour
  );
  return output;
}
/**
 * BasicLayout is a simple layout for storing the logs. The logs are stored
 * in following format:
 * <pre>
 * [startTime] [logLevel] categoryName - message\n
 * </pre>
 *
 * @author Stephan Strittmatter
 */
function basicLayout (loggingEvent) {
  return timestampLevelAndCategory(loggingEvent) + formatLogData(loggingEvent.data);
}
/**
 * colouredLayout - taken from masylum's fork.
 * same as basicLayout, but with colours.
 */
function colouredLayout (loggingEvent) {
  return timestampLevelAndCategory(
    loggingEvent,
    colours[loggingEvent.level.toString()]
  ) + formatLogData(loggingEvent.data);
}
function messagePassThroughLayout (loggingEvent) {
  return formatLogData(loggingEvent.data);
}
/**
 * PatternLayout
 * Format for specifiers is %[padding].[truncation][field]{[format]}
 * e.g. %5.10p - left pad the log level by 5 characters, up to a max of 10
 * Fields can be any of:
 *  - %r time in toLocaleTimeString format
 *  - %p log level
 *  - %c log category
 *  - %h hostname
 *  - %m log data
 *  - %d date in various formats
 *  - %% %
 *  - %n newline
 *  - %z pid
 *  - %x{<tokenname>} add dynamic tokens to your log. Tokens are specified in the tokens parameter
 * You can use %[ and %] to define a colored block.
 *
 * Tokens are specified as simple key:value objects. 
 * The key represents the token name whereas the value can be a string or function
 * which is called to extract the value to put in the log message. If token is not
 * found, it doesn't replace the field.
 *
 * A sample token would be: { "pid" : function() { return process.pid; } }
 *
 * Takes a pattern string, array of tokens and returns a layout function.
 * @param {String} Log format pattern String
 * @param {object} map object of different tokens
 * @return {Function}
 * @author Stephan Strittmatter
 * @author Jan Schmidle
 */
function patternLayout (pattern, tokens) {
  var TTCC_CONVERSION_PATTERN  = "%r %p %c - %m%n";
  var regex = /%(-?[0-9]+)?(\.?[0-9]+)?([\[\]cdhmnprzx%])(\{([^\}]+)\})?|([^%]+)/;
  
  pattern = pattern || TTCC_CONVERSION_PATTERN;
  function categoryName(loggingEvent, specifier) {
    var loggerName = loggingEvent.categoryName;
    if (specifier) {
      var precision = parseInt(specifier, 10);
      var loggerNameBits = loggerName.split(".");
      if (precision < loggerNameBits.length) {
        loggerName = loggerNameBits.slice(loggerNameBits.length - precision).join(".");
      }
    }
    return loggerName;
  }
  function formatAsDate(loggingEvent, specifier) {
    var format = dateFormat.ISO8601_FORMAT;
    if (specifier) {
      format = specifier;
      // Pick up special cases
      if (format == "ISO8601") {
        format = dateFormat.ISO8601_FORMAT;
      } else if (format == "ISO8601_WITH_TZ_OFFSET") {
        format = dateFormat.ISO8601_WITH_TZ_OFFSET_FORMAT; 
      } else if (format == "ABSOLUTE") {
        format = dateFormat.ABSOLUTETIME_FORMAT;
      } else if (format == "DATE") {
        format = dateFormat.DATETIME_FORMAT;
      }
    }
    // Format the date
    return dateFormat.asString(format, loggingEvent.startTime);
  }
  
  function hostname() {
    return os.hostname().toString();
  }
  function formatMessage(loggingEvent) {
    return formatLogData(loggingEvent.data);
  }
  
  function endOfLine() {
    return eol;
  }
  function logLevel(loggingEvent) {
    return loggingEvent.level.toString();
  }
  function startTime(loggingEvent) {
    return "" + loggingEvent.startTime.toLocaleTimeString();
  }
  function startColour(loggingEvent) {
    return colorizeStart(colours[loggingEvent.level.toString()]);
  }
  function endColour(loggingEvent) {
    return colorizeEnd(colours[loggingEvent.level.toString()]);
  }
  function percent() {
    return '%';
  }
  function pid() {
    return process.pid;
  }
  function userDefined(loggingEvent, specifier) {
    if (typeof(tokens[specifier]) !== 'undefined') {
      if (typeof(tokens[specifier]) === 'function') {
        return tokens[specifier](loggingEvent);
      } else {
        return tokens[specifier];
      }
    }
    return null;
  }
  var replacers = {
    'c': categoryName,
    'd': formatAsDate,
    'h': hostname,
    'm': formatMessage,
    'n': endOfLine,
    'p': logLevel,
    'r': startTime,
    '[': startColour,
    ']': endColour,
    'z': pid,
    '%': percent,
    'x': userDefined
  };
  function replaceToken(conversionCharacter, loggingEvent, specifier) {
    return replacers[conversionCharacter](loggingEvent, specifier);
  }
  function truncate(truncation, toTruncate) {
    var len;
    if (truncation) {
      len = parseInt(truncation.substr(1), 10);
      return toTruncate.substring(0, len);
    }
    return toTruncate;
  }
  function pad(padding, toPad) {
    var len;
    if (padding) {
      if (padding.charAt(0) == "-") {
        len = parseInt(padding.substr(1), 10);
        // Right pad with spaces
        while (toPad.length < len) {
          toPad += " ";
        }
      } else {
        len = parseInt(padding, 10);
        // Left pad with spaces
        while (toPad.length < len) {
          toPad = " " + toPad;
        }
      }
    }
    return toPad;
  }
  
  return function(loggingEvent) {
    var formattedString = "";
    var result;
    var searchString = pattern;
    
    while ((result = regex.exec(searchString))) {
      var matchedString = result[0];
      var padding = result[1];
      var truncation = result[2];
      var conversionCharacter = result[3];
      var specifier = result[5];
      var text = result[6];
      
      // Check if the pattern matched was just normal text
      if (text) {
        formattedString += "" + text;
      } else {
        // Create a raw replacement string based on the conversion
        // character and specifier
        var replacement = 
          replaceToken(conversionCharacter, loggingEvent, specifier) || 
          matchedString;
        // Format the replacement according to any padding or
        // truncation specified
        replacement = truncate(truncation, replacement);
        replacement = pad(padding, replacement);
        formattedString += replacement;
      }
      searchString = searchString.substr(result.index + result[0].length);
    }
    return formattedString;
  };
}
module.exports = {
  basicLayout: basicLayout, 
  messagePassThroughLayout: messagePassThroughLayout, 
  patternLayout: patternLayout, 
  colouredLayout: colouredLayout, 
  coloredLayout: colouredLayout, 
  layout: function(name, config) {
    return layoutMakers[name] && layoutMakers[name](config);
  }
};

+ 68 - 0
src/server/node_modules/log4js/lib/levels.js

@ -0,0 +1,68 @@
"use strict";
function Level(level, levelStr) {
  this.level = level;
  this.levelStr = levelStr;
}
/**
 * converts given String to corresponding Level
 * @param {String} sArg String value of Level OR Log4js.Level
 * @param {Log4js.Level} defaultLevel default Level, if no String representation
 * @return Level object
 * @type Log4js.Level
 */
function toLevel(sArg, defaultLevel) {
  if (!sArg) {
    return defaultLevel;
  }
  if (typeof sArg == "string") {
    var s = sArg.toUpperCase();
    if (module.exports[s]) {
      return module.exports[s];
    } else {
      return defaultLevel;
    }
  }
  return toLevel(sArg.toString());
}
Level.prototype.toString = function() {
  return this.levelStr;
};
Level.prototype.isLessThanOrEqualTo = function(otherLevel) {
  if (typeof otherLevel === "string") {
    otherLevel = toLevel(otherLevel);
  }
  return this.level <= otherLevel.level;
};
Level.prototype.isGreaterThanOrEqualTo = function(otherLevel) {
  if (typeof otherLevel === "string") {
    otherLevel = toLevel(otherLevel);
  }
  return this.level >= otherLevel.level;
};
Level.prototype.isEqualTo = function(otherLevel) {
  if (typeof otherLevel == "string") {
    otherLevel = toLevel(otherLevel);
  }
  return this.level === otherLevel.level;
};
module.exports = {
  ALL: new Level(Number.MIN_VALUE, "ALL"), 
  TRACE: new Level(5000, "TRACE"), 
  DEBUG: new Level(10000, "DEBUG"), 
  INFO: new Level(20000, "INFO"), 
  WARN: new Level(30000, "WARN"), 
  ERROR: new Level(40000, "ERROR"), 
  FATAL: new Level(50000, "FATAL"), 
  OFF: new Level(Number.MAX_VALUE, "OFF"), 
  toLevel: toLevel
};

+ 426 - 0
src/server/node_modules/log4js/lib/log4js.js

@ -0,0 +1,426 @@
"use strict";
/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * @fileoverview log4js is a library to log in JavaScript in similar manner
 * than in log4j for Java. The API should be nearly the same.
 *
 * <h3>Example:</h3>
 * <pre>
 *  var logging = require('log4js');
 *  //add an appender that logs all messages to stdout.
 *  logging.addAppender(logging.consoleAppender());
 *  //add an appender that logs "some-category" to a file
 *  logging.addAppender(logging.fileAppender("file.log"), "some-category");
 *  //get a logger
 *  var log = logging.getLogger("some-category");
 *  log.setLevel(logging.levels.TRACE); //set the Level
 *
 *  ...
 *
 *  //call the log
 *  log.trace("trace me" );
 * </pre>
 *
 * NOTE: the authors below are the original browser-based log4js authors
 * don't try to contact them about bugs in this version :)
 * @version 1.0
 * @author Stephan Strittmatter - http://jroller.com/page/stritti
 * @author Seth Chisamore - http://www.chisamore.com
 * @since 2005-05-20
 * @static
 * Website: http://log4js.berlios.de
 */
var events = require('events')
, async = require('async')
, fs = require('fs')
, path = require('path')
, util = require('util')
, layouts = require('./layouts')
, levels = require('./levels')
, loggerModule = require('./logger')
, LoggingEvent = loggerModule.LoggingEvent
, Logger = loggerModule.Logger
, ALL_CATEGORIES = '[all]'
, appenders = {}
, loggers = {}
, appenderMakers = {}
, appenderShutdowns = {}
, defaultConfig =   {
  appenders: [
    { type: "console" }
  ],
  replaceConsole: false
};
function hasLogger(logger) {
  return loggers.hasOwnProperty(logger);
}
function getBufferedLogger(categoryName) {
    var base_logger = getLogger(categoryName);
    var logger = {};
    logger.temp = [];
    logger.target = base_logger;
    logger.flush = function () {
        for (var i = 0; i < logger.temp.length; i++) {
            var log = logger.temp[i];
            logger.target[log.level](log.message);
            delete logger.temp[i];
        }
    };
    logger.trace = function (message) { logger.temp.push({level: 'trace', message: message}); };
    logger.debug = function (message) { logger.temp.push({level: 'debug', message: message}); };
    logger.info = function (message) { logger.temp.push({level: 'info', message: message}); };
    logger.warn = function (message) { logger.temp.push({level: 'warn', message: message}); };
    logger.error = function (message) { logger.temp.push({level: 'error', message: message}); };
    logger.fatal = function (message) { logger.temp.push({level: 'fatal', message: message}); };
    return logger;
}
/**
 * Get a logger instance. Instance is cached on categoryName level.
 * @param  {String} categoryName name of category to log to.
 * @return {Logger} instance of logger for the category
 * @static
 */
function getLogger (categoryName) {
  // Use default logger if categoryName is not specified or invalid
  if (typeof categoryName !== "string") {
    categoryName = Logger.DEFAULT_CATEGORY;
  }
  var appenderList;
  if (!hasLogger(categoryName)) {
    // Create the logger for this name if it doesn't already exist
    loggers[categoryName] = new Logger(categoryName);
    if (appenders[categoryName]) {
      appenderList = appenders[categoryName];
      appenderList.forEach(function(appender) {
        loggers[categoryName].addListener("log", appender);
      });
    }
    if (appenders[ALL_CATEGORIES]) {
      appenderList = appenders[ALL_CATEGORIES];
      appenderList.forEach(function(appender) {
        loggers[categoryName].addListener("log", appender);
      });
    }
  }
  
  return loggers[categoryName];
}
/**
 * args are appender, then zero or more categories
 */
function addAppender () {
  var args = Array.prototype.slice.call(arguments);
  var appender = args.shift();
  if (args.length === 0 || args[0] === undefined) {
    args = [ ALL_CATEGORIES ];
  }
  //argument may already be an array
  if (Array.isArray(args[0])) {
    args = args[0];
  }
  
  args.forEach(function(category) {
    addAppenderToCategory(appender, category);
    
    if (category === ALL_CATEGORIES) {
      addAppenderToAllLoggers(appender);
    } else if (hasLogger(category)) {
      loggers[category].addListener("log", appender);
    }
  });
}
function addAppenderToAllLoggers(appender) {
  for (var logger in loggers) {
    if (hasLogger(logger)) {
      loggers[logger].addListener("log", appender);
    }
  }
}
function addAppenderToCategory(appender, category) {
  if (!appenders[category]) {
    appenders[category] = [];
  }
  appenders[category].push(appender);
}
function clearAppenders () {
  appenders = {};
  for (var logger in loggers) {
    if (hasLogger(logger)) {
      loggers[logger].removeAllListeners("log");
    }
  }
}
function configureAppenders(appenderList, options) {
  clearAppenders();
  if (appenderList) {
    appenderList.forEach(function(appenderConfig) {
      loadAppender(appenderConfig.type);
      var appender;
      appenderConfig.makers = appenderMakers;
      try {
        appender = appenderMakers[appenderConfig.type](appenderConfig, options);
        addAppender(appender, appenderConfig.category);
      } catch(e) {
        throw new Error("log4js configuration problem for " + util.inspect(appenderConfig), e);
      }
    });
  }
}
function configureLevels(levels) {
  if (levels) {
    for (var category in levels) {
      if (levels.hasOwnProperty(category)) {
        if(category === ALL_CATEGORIES) {
          setGlobalLogLevel(levels[category]);
        }
        getLogger(category).setLevel(levels[category]);
      }
    }
  }
}
function setGlobalLogLevel(level) {
  Logger.prototype.level = levels.toLevel(level, levels.TRACE);
}
/**
 * Get the default logger instance.
 * @return {Logger} instance of default logger
 * @static
 */
function getDefaultLogger () {
  return getLogger(Logger.DEFAULT_CATEGORY);
}
var configState = {};
function loadConfigurationFile(filename) {
  if (filename) {
    return JSON.parse(fs.readFileSync(filename, "utf8"));
  }
  return undefined;
}
function configureOnceOff(config, options) {
  if (config) {
    try {
      configureAppenders(config.appenders, options);
      configureLevels(config.levels);
      
      if (config.replaceConsole) {
        replaceConsole();
      } else {
        restoreConsole();
      }
    } catch (e) {
      throw new Error(
        "Problem reading log4js config " + util.inspect(config) + 
          ". Error was \"" + e.message + "\" (" + e.stack + ")"
      );
    }
  }
}
function reloadConfiguration() {
  var mtime = getMTime(configState.filename);
  if (!mtime) return;
  if (configState.lastMTime && (mtime.getTime() > configState.lastMTime.getTime())) {
    configureOnceOff(loadConfigurationFile(configState.filename));
  }
  configState.lastMTime = mtime;
}
function getMTime(filename) {
  var mtime;
  try {
    mtime = fs.statSync(configState.filename).mtime;
  } catch (e) {
    getLogger('log4js').warn('Failed to load configuration file ' + filename);
  }
  return mtime;
}
function initReloadConfiguration(filename, options) {
  if (configState.timerId) {
    clearInterval(configState.timerId);
    delete configState.timerId;
  }
  configState.filename = filename;
  configState.lastMTime = getMTime(filename);
  configState.timerId = setInterval(reloadConfiguration, options.reloadSecs*1000);
}
function configure(configurationFileOrObject, options) {
  var config = configurationFileOrObject;
  config = config || process.env.LOG4JS_CONFIG;
  options = options || {};
  
  if (config === undefined || config === null || typeof(config) === 'string') {
    if (options.reloadSecs) {
      initReloadConfiguration(config, options);
    }
    config = loadConfigurationFile(config) || defaultConfig;
  } else {
    if (options.reloadSecs) {
      getLogger('log4js').warn(
        'Ignoring configuration reload parameter for "object" configuration.'
      );
    }
  }
  configureOnceOff(config, options);
}
var originalConsoleFunctions = {
  log: console.log,
  debug: console.debug,
  info: console.info,
  warn: console.warn,
  error: console.error
};
function replaceConsole(logger) {
  function replaceWith(fn) {
    return function() {
      fn.apply(logger, arguments);
    };
  }
  logger = logger || getLogger("console");
  ['log','debug','info','warn','error'].forEach(function (item) {
    console[item] = replaceWith(item === 'log' ? logger.info : logger[item]);
  });
}
function restoreConsole() {
  ['log', 'debug', 'info', 'warn', 'error'].forEach(function (item) {
    console[item] = originalConsoleFunctions[item];
  });
}
/**
 * Load an appenderModule based on the provided appender filepath. Will first
 * check if the appender path is a subpath of the log4js "lib/appenders" directory.
 * If not, it will attempt to load the the appender as complete path.
 *
 * @param {string} appender The filepath for the appender.
 * @returns {Object|null} The required appender or null if appender could not be loaded.
 * @private
 */
function requireAppender(appender) {
  var appenderModule;
  try {
    appenderModule = require('./appenders/' + appender);
  } catch (e) {
    appenderModule = require(appender);
  }
  return appenderModule;
}
/**
 * Load an appender. Provided the appender path to be loaded. If appenderModule is defined,
 * it will be used in place of requiring the appender module.
 *
 * @param {string} appender The path to the appender module.
 * @param {Object|void} [appenderModule] The pre-required appender module. When provided,
 * instead of requiring the appender by its path, this object will be used.
 * @returns {void}
 * @private
 */
function loadAppender(appender, appenderModule) {
  appenderModule = appenderModule || requireAppender(appender);
  if (!appenderModule) {
    throw new Error("Invalid log4js appender: " + util.inspect(appender));
  }
  module.exports.appenders[appender] = appenderModule.appender.bind(appenderModule);
  if (appenderModule.shutdown) {
    appenderShutdowns[appender] = appenderModule.shutdown.bind(appenderModule);
  }
  appenderMakers[appender] = appenderModule.configure.bind(appenderModule);
}
/**
 * Shutdown all log appenders. This will first disable all writing to appenders
 * and then call the shutdown function each appender.
 *
 * @params {Function} cb - The callback to be invoked once all appenders have
 *  shutdown. If an error occurs, the callback will be given the error object
 *  as the first argument.
 * @returns {void}
 */
function shutdown(cb) {
  // First, disable all writing to appenders. This prevents appenders from
  // not being able to be drained because of run-away log writes.
  loggerModule.disableAllLogWrites();
  // Next, get all the shutdown functions for appenders as an array.
  var shutdownFunctions = Object.keys(appenderShutdowns).reduce(
    function(accum, category) {
      return accum.concat(appenderShutdowns[category]);
    }, []);
  // Call each of the shutdown functions.
  async.each(
    shutdownFunctions,
    function(shutdownFn, done) {
      shutdownFn(done);
    },
		cb
  );
}
module.exports = {
  getBufferedLogger: getBufferedLogger,
  getLogger: getLogger,
  getDefaultLogger: getDefaultLogger,
  hasLogger: hasLogger,
  
  addAppender: addAppender,
  loadAppender: loadAppender,
  clearAppenders: clearAppenders,
  configure: configure,
  shutdown: shutdown,
  
  replaceConsole: replaceConsole,
  restoreConsole: restoreConsole,
  
  levels: levels,
  setGlobalLogLevel: setGlobalLogLevel,
  
  layouts: layouts,
  appenders: {},
  appenderMakers: appenderMakers,
  connectLogger: require('./connect-logger').connectLogger
};
//set ourselves up
configure();

+ 102 - 0
src/server/node_modules/log4js/lib/logger.js

@ -0,0 +1,102 @@
"use strict";
var levels = require('./levels')
, util = require('util')
, events = require('events')
, DEFAULT_CATEGORY = '[default]';
var logWritesEnabled = true;
/**
 * Models a logging event.
 * @constructor
 * @param {String} categoryName name of category
 * @param {Log4js.Level} level level of message
 * @param {Array} data objects to log
 * @param {Log4js.Logger} logger the associated logger
 * @author Seth Chisamore
 */
function LoggingEvent (categoryName, level, data, logger) {
  this.startTime = new Date();
  this.categoryName = categoryName;
  this.data = data;
  this.level = level;
  this.logger = logger;
}
/**
 * Logger to log messages.
 * use {@see Log4js#getLogger(String)} to get an instance.
 * @constructor
 * @param name name of category to log to
 * @author Stephan Strittmatter
 */
function Logger (name, level) {
  this.category = name || DEFAULT_CATEGORY;
  
  if (level) {
    this.setLevel(level);
  }
}
util.inherits(Logger, events.EventEmitter);
Logger.DEFAULT_CATEGORY = DEFAULT_CATEGORY;
Logger.prototype.level = levels.TRACE;
Logger.prototype.setLevel = function(level) {
  this.level = levels.toLevel(level, this.level || levels.TRACE);
};
Logger.prototype.removeLevel = function() {
  delete this.level;
};
Logger.prototype.log = function() {
  var args = Array.prototype.slice.call(arguments)
  , logLevel = levels.toLevel(args.shift())
  , loggingEvent;
  if (this.isLevelEnabled(logLevel)) {
    loggingEvent = new LoggingEvent(this.category, logLevel, args, this);
    this.emit("log", loggingEvent);
  }
};
Logger.prototype.isLevelEnabled = function(otherLevel) {
  return this.level.isLessThanOrEqualTo(otherLevel);
};
['Trace','Debug','Info','Warn','Error','Fatal'].forEach(
  function(levelString) {
    var level = levels.toLevel(levelString);
    Logger.prototype['is'+levelString+'Enabled'] = function() {
      return this.isLevelEnabled(level);
    };
    
    Logger.prototype[levelString.toLowerCase()] = function () {
      if (logWritesEnabled && this.isLevelEnabled(level)) {
        var args = Array.prototype.slice.call(arguments);
        args.unshift(level);
        Logger.prototype.log.apply(this, args);
      }
    };
  }
);
/**
 * Disable all log writes.
 * @returns {void}
 */
function disableAllLogWrites() {
  logWritesEnabled = false;
}
/**
 * Enable log writes.
 * @returns {void}
 */
function enableAllLogWrites() {
  logWritesEnabled = true;
}
exports.LoggingEvent = LoggingEvent;
exports.Logger = Logger;
exports.disableAllLogWrites = disableAllLogWrites;
exports.enableAllLogWrites = enableAllLogWrites;

+ 90 - 0
src/server/node_modules/log4js/lib/streams/BaseRollingFileStream.js

@ -0,0 +1,90 @@
"use strict";
var fs = require('fs')
, stream
, debug = require('../debug')('BaseRollingFileStream')
, util = require('util')
, semver = require('semver');
if (semver.satisfies(process.version, '>=0.10.0')) {
  stream = require('stream');
} else {
  stream = require('readable-stream');
}
module.exports = BaseRollingFileStream;
function BaseRollingFileStream(filename, options) {
  debug("In BaseRollingFileStream");
  this.filename = filename;
  this.options = options || { encoding: 'utf8', mode: parseInt('0644', 8), flags: 'a' };
  this.currentSize = 0;
  
  function currentFileSize(file) {
    var fileSize = 0;
    try {
      fileSize = fs.statSync(file).size;
    } catch (e) {
      // file does not exist
    }
    return fileSize;
  }
  function throwErrorIfArgumentsAreNotValid() {
    if (!filename) {
      throw new Error("You must specify a filename");
    }
  }
  throwErrorIfArgumentsAreNotValid();
  debug("Calling BaseRollingFileStream.super");
  BaseRollingFileStream.super_.call(this);
  this.openTheStream();
  this.currentSize = currentFileSize(this.filename);
}
util.inherits(BaseRollingFileStream, stream.Writable);
BaseRollingFileStream.prototype._write = function(chunk, encoding, callback) {
  var that = this;
  function writeTheChunk() {
    debug("writing the chunk to the underlying stream");
    that.currentSize += chunk.length;
    try {
      that.theStream.write(chunk, encoding, callback);
    }
    catch (err){
      debug(err);
      callback();
    }
  }
  debug("in _write");
  if (this.shouldRoll()) {
    this.currentSize = 0;
    this.roll(this.filename, writeTheChunk);
  } else {
    writeTheChunk();
  }
};
BaseRollingFileStream.prototype.openTheStream = function(cb) {
  debug("opening the underlying stream");
  this.theStream = fs.createWriteStream(this.filename, this.options);
  if (cb) {
    this.theStream.on("open", cb);
  }
};
BaseRollingFileStream.prototype.closeTheStream = function(cb) {
  debug("closing the underlying stream");
  this.theStream.end(cb);
};
BaseRollingFileStream.prototype.shouldRoll = function() {
  return false; // default behaviour is never to roll
};
BaseRollingFileStream.prototype.roll = function(filename, callback) {
  callback(); // default behaviour is not to do anything
};

+ 95 - 0
src/server/node_modules/log4js/lib/streams/DateRollingFileStream.js

@ -0,0 +1,95 @@
"use strict";
var BaseRollingFileStream = require('./BaseRollingFileStream')
, debug = require('../debug')('DateRollingFileStream')
, format = require('../date_format')
, async = require('async')
, fs = require('fs')
, util = require('util');
module.exports = DateRollingFileStream;
function DateRollingFileStream(filename, pattern, options, now) {
  debug("Now is " + now);
  if (pattern && typeof(pattern) === 'object') {
    now = options;
    options = pattern;
    pattern = null;
  }
  this.pattern = pattern || '.yyyy-MM-dd';
  this.now = now || Date.now;
  if (fs.existsSync(filename)) {
    var stat = fs.statSync(filename);
    this.lastTimeWeWroteSomething = format.asString(this.pattern, stat.mtime);
  } else {
    this.lastTimeWeWroteSomething = format.asString(this.pattern, new Date(this.now()));
  }
  this.baseFilename = filename;
  this.alwaysIncludePattern = false;
  
  if (options) {
    if (options.alwaysIncludePattern) {
      this.alwaysIncludePattern = true;
      filename = this.baseFilename + this.lastTimeWeWroteSomething;
    }
    delete options.alwaysIncludePattern;
    if (Object.keys(options).length === 0) { 
      options = null; 
    }
  }
  debug("this.now is " + this.now + ", now is " + now);
  
  DateRollingFileStream.super_.call(this, filename, options);
}
util.inherits(DateRollingFileStream, BaseRollingFileStream);
DateRollingFileStream.prototype.shouldRoll = function() {
  var lastTime = this.lastTimeWeWroteSomething,
  thisTime = format.asString(this.pattern, new Date(this.now()));
  
  debug("DateRollingFileStream.shouldRoll with now = " + 
        this.now() + ", thisTime = " + thisTime + ", lastTime = " + lastTime);
  
  this.lastTimeWeWroteSomething = thisTime;
  this.previousTime = lastTime;
  
  return thisTime !== lastTime;
};
DateRollingFileStream.prototype.roll = function(filename, callback) {
  var that = this;
  
  debug("Starting roll");
  
  if (this.alwaysIncludePattern) {
    this.filename = this.baseFilename + this.lastTimeWeWroteSomething;
    async.series([
      this.closeTheStream.bind(this),
      this.openTheStream.bind(this)
    ], callback);
  } else {
    var newFilename = this.baseFilename + this.previousTime;
    async.series([
      this.closeTheStream.bind(this),
      deleteAnyExistingFile,
      renameTheCurrentFile,
      this.openTheStream.bind(this)
    ], callback);
  }
  
  function deleteAnyExistingFile(cb) {
    //on windows, you can get a EEXIST error if you rename a file to an existing file
    //so, we'll try to delete the file we're renaming to first
    fs.unlink(newFilename, function (err) {
      //ignore err: if we could not delete, it's most likely that it doesn't exist
      cb();
    });
  }
  function renameTheCurrentFile(cb) {
    debug("Renaming the " + filename + " -> " + newFilename);
    fs.rename(filename, newFilename, cb);
  }
};

+ 89 - 0
src/server/node_modules/log4js/lib/streams/RollingFileStream.js

@ -0,0 +1,89 @@
"use strict";
var BaseRollingFileStream = require('./BaseRollingFileStream')
, debug = require('../debug')('RollingFileStream')
, util = require('util')
, path = require('path')
, fs = require('fs')
, async = require('async');
module.exports = RollingFileStream;
function RollingFileStream (filename, size, backups, options) {
  this.size = size;
  this.backups = backups || 1;
  
  function throwErrorIfArgumentsAreNotValid() {
    if (!filename || !size || size <= 0) {
      throw new Error("You must specify a filename and file size");
    }
  }
  
  throwErrorIfArgumentsAreNotValid();
  
  RollingFileStream.super_.call(this, filename, options);
}
util.inherits(RollingFileStream, BaseRollingFileStream);
RollingFileStream.prototype.shouldRoll = function() {
  debug("should roll with current size %d, and max size %d", this.currentSize, this.size);
  return this.currentSize >= this.size;
};
RollingFileStream.prototype.roll = function(filename, callback) {
  var that = this,
  nameMatcher = new RegExp('^' + path.basename(filename));
  
  function justTheseFiles (item) {
    return nameMatcher.test(item);
  }
  
  function index(filename_) {
    return parseInt(filename_.substring((path.basename(filename) + '.').length), 10) || 0;
  }
  
  function byIndex(a, b) {
    if (index(a) > index(b)) {
      return 1;
    } else if (index(a) < index(b) ) {
      return -1;
    } else {
      return 0;
    }
  }
  function increaseFileIndex (fileToRename, cb) {
    var idx = index(fileToRename);
    debug('Index of ' + fileToRename + ' is ' + idx);
    if (idx < that.backups) {
      //on windows, you can get a EEXIST error if you rename a file to an existing file
      //so, we'll try to delete the file we're renaming to first
      fs.unlink(filename + '.' + (idx+1), function (err) {
        //ignore err: if we could not delete, it's most likely that it doesn't exist
        debug('Renaming ' + fileToRename + ' -> ' + filename + '.' + (idx+1));
        fs.rename(path.join(path.dirname(filename), fileToRename), filename + '.' + (idx + 1), cb);
      });
    } else {
      cb();
    }
  }
  function renameTheFiles(cb) {
    //roll the backups (rename file.n to file.n+1, where n <= numBackups)
    debug("Renaming the old files");
    fs.readdir(path.dirname(filename), function (err, files) {
      async.eachSeries(
        files.filter(justTheseFiles).sort(byIndex).reverse(),
        increaseFileIndex,
        cb
      );
    });
  }
  debug("Rolling, rolling, rolling");
  async.series([
    this.closeTheStream.bind(this),
    renameTheFiles,
    this.openTheStream.bind(this)
  ], callback);
};

+ 0 - 0
src/server/node_modules/log4js/lib/streams/index.js


Some files were not shown because too many files changed in this diff