<commit_before>'use strict';

var path = require('path');

var level = 'info';

module.exports = {

    /**
     * Generic log function for printing the logs
     * @param _level Level of debug
     * @param _msg Message to print
     */
    log: function (_level, _msg) {

        switch (_level) {
            case 'debug':
                if (this.getLogLevel() === 'debug') {
                    console.log(_msg);
                }
                break;
            case 'info':
                console.log(_msg);
                break;
            case 'warn':
                console.warn(_msg);
                break;
            case 'error':
                console.error(_msg);
                break;
            default :
                console.error('This debug level is not defined');
        }
    },

    /**
     * Method for exiting the program with a concrete exit code
     * @param _code Exit code
     */
    exit: function (_code) {
        this.log('debug', 'exiting program with code <' + _code + '>');
        process.exit(_code);
    },

    /**
     * Returns the full execution path of the bin command
     * @returns {string} bin command path
     */
    getBinPath: function () {
        return 'node ' + path.join(__dirname, '../src/dockgrant.js') + ' ';
    },

    /**
     * Function for testing if a concrete command is installed on the system
     * @param _command Command to test
     */
    isCommandAvailable: function (_command) {

        if (shell.exec(_command, {silent: true}).code !== 0) {
            this.log('error', 'The command <' + _command + '> is not available');
            this.exit(1);
        } else {
            this.log('debug', 'The command <' + _command + '> is available!');
        }
    },

    setLogLevel: function (_level) {
        level = _level;
    },

    getLogLevel: function () {
        return level;
    }

};
<commit_msg>Configure logging<commit_after>'use strict';

require('colors');
var path = require('path');
var shell = require('shelljs');

var level = 'info';

module.exports = {

    /**
     * Generic log function for printing the logs
     * @param _level Level of debug
     * @param _msg Message to print
     */
    log: function (_level, _msg) {

        switch (_level) {
            case 'debug':
                if (this.getLogLevel() === 'debug') {
                    console.log((_msg).blue);
                }
                break;
            case 'info':
                console.log(_msg);
                break;
            case 'warn':
                console.warn((_msg).yellow);
                break;
            case 'error':
                console.error((_msg).red);
                break;
            default :
                console.error(('This debug level is not defined').red);
        }
    },

    /**
     * Method for exiting the program with a concrete exit code
     * @param _code Exit code
     */
    exit: function (_code) {
        this.log('debug', 'exiting program with code <' + _code + '>');
        process.exit(_code);
    },

    /**
     * Returns the full execution path of the bin command
     * @returns {string} bin command path
     */
    getBinPath: function () {
        return 'node ' + path.join(__dirname, '../src/dockgrant.js') + ' ';
    },

    /**
     * Function for testing if a concrete command is installed on the system
     * @param _command Command to test
     */
    isCommandAvailable: function (_command) {

        if (shell.exec(_command, {silent: true}).code !== 0) {
            this.log('error', 'The command <' + _command + '> is not available');
            this.exit(1);
        } else {
            this.log('debug', 'The command <' + _command + '> is available!');
        }
    },

    /**
     * Sets the log level of the application
     * @param _level Level of log
     */
    setLogLevel: function (_level) {
        level = _level;
    },

    /**
     * Returns the log level of the application
     * @returns {string}
     */
    getLogLevel: function () {
        return level;
    }

};
<|endoftext|>


<commit_before>class FetchInterceptor {
  constructor() {
    this.interceptors = [];

    this.fetch = (...args) => this.interceptorWrapper(fetch, ...args);
  }

  /**
   * add new interceptors
   * @param {(Object|Object[])} interceptors
   */
  addInterceptors(interceptors) {
    const removeIndex = [];

    if (Array.isArray(interceptors)) {
      interceptors.map(interceptor => {
        removeIndex.push(this.interceptors.length);
        return this.interceptors.push(interceptor);
      });
    } else if (interceptors instanceof Object) {
      removeIndex.push(this.interceptors.length);
      this.interceptors.push(interceptors);
    }

    this.updateInterceptors();

    return () => this.removeInterceptors(removeIndex);
  }

  removeInterceptors(indexes) {
    if (Array.isArray(indexes)) {
      indexes.map(index => this.interceptors.splice(index, 1));
      this.updateInterceptors();
    }
  }

  updateInterceptors() {
    this.reversedInterceptors = this.interceptors
      .reduce((array, interceptor) => [interceptor].concat(array), []);
  }

  /**
   * remove all interceptors
   */
  clearInterceptors() {
    this.interceptors = [];

    this.updateInterceptors();
  }

  interceptorWrapper(fetch, ...args) {
    let promise = Promise.resolve(args);

    this.reversedInterceptors.forEach(({ request, requestError }) => {
      if (request || requestError) {
        promise = promise.then(() => request(...args), requestError);
      }
    });

    promise = promise.then(() => fetch(...args));

    this.reversedInterceptors.forEach(({ response, responseError }) => {
      if (response || responseError) {
        promise = promise.then(response, responseError);
      }
    });

    return promise;
  }
}

class FetchQL extends FetchInterceptor {
  /**
   * FetchQL Class
   * @class
   * @param {String} url - the server address of GraphQL
   * @param {(Object|Object[])=} interceptors
   * @param {{}=} headers - request headers
   * @param {FetchQL~requestQueueChanged=} onStart - callback function of a new request queue
   * @param {FetchQL~requestQueueChanged=} onEnd - callback function of request queue finished
   * @param {Boolean=} omitEmptyVariables - remove null props(null or '') from the variables
   */
  constructor({ url, interceptors, headers, onStart, onEnd, omitEmptyVariables = false }) {
    super();

    this.requestObject = {
      method: 'POST',
      headers: Object.assign({}, {
        Accept: 'application/json',
        'Content-Type': 'application/json',
      }, headers),
      credentials: 'same-origin',
    };

    this.url = url;

    this.omitEmptyVariables = omitEmptyVariables;

    // marker for request queue
    this.requestQueueLength = 0;

    // using for caching enums' type
    this.EnumMap = {};

    this.callbacks = {
      onStart,
      onEnd,
    };

    this.addInterceptors(interceptors);
  }

  /**
   * operate an query
   * @param {String} operationName
   * @param {String} query
   * @param {Object} variables
   * @param {Object} opts - addition options(will not be passed to server)
   * @param {Boolean=} opts.omitEmptyVariables - remove null props(null or '') from the variables
   * @returns {Promise}
   * @memberOf FetchQL
   */
  query({ operationName, query, variables, opts = {} }) {
    const options = Object.assign({}, this.requestObject);
    let vars;
    if (this.omitEmptyVariables || opts.omitEmptyVariables) {
      vars = this.doOmitEmptyVariables(variables);
    } else {
      vars = variables;
    }
    const body = {
      operationName,
      query,
      variables: JSON.stringify(vars),
    };
    options.body = JSON.stringify(body);

    this.onStart();

    return this.fetch(this.url, options)
      .then(res => {
        if (res.ok) {
          return res.json();
        }
        // return an custom error stack if request error
        return {
          errors: [{
            message: res.statusText,
            stack: res,
          }],
        };
      })
      .then(({ data, errors }) => (
        new Promise((resolve, reject) => {
          this.onEnd();

          // if data in response is 'null'
          if (!data) {
            return reject(errors || [{}]);
          }
          // if all properties of data is 'null'
          const allDataKeyEmpty = Object.keys(data).every(key => !data[key]);
          if (allDataKeyEmpty) {
            return reject(errors);
          }
          return resolve({ data, errors });
        })
      ));
  }

  /**
   * get current server address
   * @returns {String}
   * @memberOf FetchQL
   */
  getUrl() {
    return this.url;
  }

  /**
   * setting a new server address
   * @param {String} url
   * @memberOf FetchQL
   */
  setUrl(url) {
    this.url = url;
  }

  /**
   * get information of enum type
   * @param {String[]} EnumNameList - array of enums' name
   * @returns {Promise}
   * @memberOf FetchQL
   */
  getEnumTypes(EnumNameList) {
    const fullData = {};

    // check cache status
    const unCachedEnumList = EnumNameList.filter(element => {
      if (this.EnumMap[element]) {
        // enum has been cached
        fullData[element] = this.EnumMap[element];
        return false;
      }
      return true;
    });

    // immediately return the data if all enums have been cached
    if (!unCachedEnumList.length) {
      return new Promise((resolve) => {
        resolve({ data: fullData });
      });
    }

    // build query string for uncached enums
    const EnumTypeQuery = unCachedEnumList.map(type => (
      `${type}: __type(name: "${type}") {
        ...EnumFragment
      }`
    ));

    const query = `
      query {
        ${EnumTypeQuery.join('\n')}
      }

      fragment EnumFragment on __Type {
        kind
        description
        enumValues {
          name
          description
        }
      }`;

    const options = Object.assign({}, this.requestObject);
    options.body = JSON.stringify({ query });

    this.onStart();

    return this.fetch(this.url, options)
      .then(res => {
        if (res.ok) {
          return res.json();
        }
        // return an custom error stack if request error
        return {
          errors: [{
            message: res.statusText,
            stack: res,
          }],
        };
      })
      .then(({ data, errors }) => (
        new Promise((resolve, reject) => {
          this.onEnd();

          // if data in response is 'null' and have any errors
          if (!data) {
            return reject(errors || [{}]);
          }
          // if all properties of data is 'null'
          const allDataKeyEmpty = Object.keys(data).every(key => !data[key]);
          if (allDataKeyEmpty && errors && errors.length) {
            return reject(errors);
          }
          // merge enums' data
          const passData = Object.assign(fullData, data);
          // cache new enums' data
          Object.keys(data).map(key => {
            this.EnumMap[key] = data[key];
            return key;
          });
          return resolve({ data: passData, errors });
        })
      ));
  }

  /**
   * calling on a request starting
   * if the request belong to a new queue, call the 'onStart' method
   */
  onStart() {
    this.requestQueueLength++;
    if (this.requestQueueLength > 1 || !this.callbacks.onStart) {
      return;
    }
    this.callbacks.onStart(this.requestQueueLength);
  }

  /**
   * calling on a request ending
   * if current queue finished, calling the 'onEnd' method
   */
  onEnd() {
    this.requestQueueLength--;
    if (this.requestQueueLength || !this.callbacks.onEnd) {
      return;
    }
    this.callbacks.onEnd(this.requestQueueLength);
  }

  /**
   * Callback of requests queue changes.(e.g. new queue or queue finished)
   * @callback FetchQL~requestQueueChanged
   * @param {number} queueLength - length of current request queue
   */

  /**
   * remove empty props(null or '') from object
   * @param {Object} input
   * @returns {Object}
   * @memberOf FetchQL
   * @private
   */
  doOmitEmptyVariables(input) {
    const nonEmptyObj = {};
    Object.keys(input).map(key => {
      if (input[key] instanceof Object) {
        nonEmptyObj[key] = this.doOmitEmptyVariables(input[key]);
      } else {
        nonEmptyObj[key] = input[key];
      }
      return key;
    });
    return nonEmptyObj;
  }
}

export default FetchQL;
<commit_msg>fix(omitEmtpyVariables): correctly omit emty variables<commit_after>class FetchInterceptor {
  constructor() {
    this.interceptors = [];

    this.fetch = (...args) => this.interceptorWrapper(fetch, ...args);
  }

  /**
   * add new interceptors
   * @param {(Object|Object[])} interceptors
   */
  addInterceptors(interceptors) {
    const removeIndex = [];

    if (Array.isArray(interceptors)) {
      interceptors.map(interceptor => {
        removeIndex.push(this.interceptors.length);
        return this.interceptors.push(interceptor);
      });
    } else if (interceptors instanceof Object) {
      removeIndex.push(this.interceptors.length);
      this.interceptors.push(interceptors);
    }

    this.updateInterceptors();

    return () => this.removeInterceptors(removeIndex);
  }

  removeInterceptors(indexes) {
    if (Array.isArray(indexes)) {
      indexes.map(index => this.interceptors.splice(index, 1));
      this.updateInterceptors();
    }
  }

  updateInterceptors() {
    this.reversedInterceptors = this.interceptors
      .reduce((array, interceptor) => [interceptor].concat(array), []);
  }

  /**
   * remove all interceptors
   */
  clearInterceptors() {
    this.interceptors = [];

    this.updateInterceptors();
  }

  interceptorWrapper(fetch, ...args) {
    let promise = Promise.resolve(args);

    this.reversedInterceptors.forEach(({ request, requestError }) => {
      if (request || requestError) {
        promise = promise.then(() => request(...args), requestError);
      }
    });

    promise = promise.then(() => fetch(...args));

    this.reversedInterceptors.forEach(({ response, responseError }) => {
      if (response || responseError) {
        promise = promise.then(response, responseError);
      }
    });

    return promise;
  }
}

class FetchQL extends FetchInterceptor {
  /**
   * FetchQL Class
   * @class
   * @param {String} url - the server address of GraphQL
   * @param {(Object|Object[])=} interceptors
   * @param {{}=} headers - request headers
   * @param {FetchQL~requestQueueChanged=} onStart - callback function of a new request queue
   * @param {FetchQL~requestQueueChanged=} onEnd - callback function of request queue finished
   * @param {Boolean=} omitEmptyVariables - remove null props(null or '') from the variables
   */
  constructor({ url, interceptors, headers, onStart, onEnd, omitEmptyVariables = false }) {
    super();

    this.requestObject = {
      method: 'POST',
      headers: Object.assign({}, {
        Accept: 'application/json',
        'Content-Type': 'application/json',
      }, headers),
      credentials: 'same-origin',
    };

    this.url = url;

    this.omitEmptyVariables = omitEmptyVariables;

    // marker for request queue
    this.requestQueueLength = 0;

    // using for caching enums' type
    this.EnumMap = {};

    this.callbacks = {
      onStart,
      onEnd,
    };

    this.addInterceptors(interceptors);
  }

  /**
   * operate an query
   * @param {String} operationName
   * @param {String} query
   * @param {Object} variables
   * @param {Object} opts - addition options(will not be passed to server)
   * @param {Boolean=} opts.omitEmptyVariables - remove null props(null or '') from the variables
   * @returns {Promise}
   * @memberOf FetchQL
   */
  query({ operationName, query, variables, opts = {} }) {
    const options = Object.assign({}, this.requestObject);
    let vars;
    if (this.omitEmptyVariables || opts.omitEmptyVariables) {
      vars = this.doOmitEmptyVariables(variables);
    } else {
      vars = variables;
    }
    const body = {
      operationName,
      query,
      variables: JSON.stringify(vars),
    };
    options.body = JSON.stringify(body);

    this.onStart();

    return this.fetch(this.url, options)
      .then(res => {
        if (res.ok) {
          return res.json();
        }
        // return an custom error stack if request error
        return {
          errors: [{
            message: res.statusText,
            stack: res,
          }],
        };
      })
      .then(({ data, errors }) => (
        new Promise((resolve, reject) => {
          this.onEnd();

          // if data in response is 'null'
          if (!data) {
            return reject(errors || [{}]);
          }
          // if all properties of data is 'null'
          const allDataKeyEmpty = Object.keys(data).every(key => !data[key]);
          if (allDataKeyEmpty) {
            return reject(errors);
          }
          return resolve({ data, errors });
        })
      ));
  }

  /**
   * get current server address
   * @returns {String}
   * @memberOf FetchQL
   */
  getUrl() {
    return this.url;
  }

  /**
   * setting a new server address
   * @param {String} url
   * @memberOf FetchQL
   */
  setUrl(url) {
    this.url = url;
  }

  /**
   * get information of enum type
   * @param {String[]} EnumNameList - array of enums' name
   * @returns {Promise}
   * @memberOf FetchQL
   */
  getEnumTypes(EnumNameList) {
    const fullData = {};

    // check cache status
    const unCachedEnumList = EnumNameList.filter(element => {
      if (this.EnumMap[element]) {
        // enum has been cached
        fullData[element] = this.EnumMap[element];
        return false;
      }
      return true;
    });

    // immediately return the data if all enums have been cached
    if (!unCachedEnumList.length) {
      return new Promise((resolve) => {
        resolve({ data: fullData });
      });
    }

    // build query string for uncached enums
    const EnumTypeQuery = unCachedEnumList.map(type => (
      `${type}: __type(name: "${type}") {
        ...EnumFragment
      }`
    ));

    const query = `
      query {
        ${EnumTypeQuery.join('\n')}
      }

      fragment EnumFragment on __Type {
        kind
        description
        enumValues {
          name
          description
        }
      }`;

    const options = Object.assign({}, this.requestObject);
    options.body = JSON.stringify({ query });

    this.onStart();

    return this.fetch(this.url, options)
      .then(res => {
        if (res.ok) {
          return res.json();
        }
        // return an custom error stack if request error
        return {
          errors: [{
            message: res.statusText,
            stack: res,
          }],
        };
      })
      .then(({ data, errors }) => (
        new Promise((resolve, reject) => {
          this.onEnd();

          // if data in response is 'null' and have any errors
          if (!data) {
            return reject(errors || [{}]);
          }
          // if all properties of data is 'null'
          const allDataKeyEmpty = Object.keys(data).every(key => !data[key]);
          if (allDataKeyEmpty && errors && errors.length) {
            return reject(errors);
          }
          // merge enums' data
          const passData = Object.assign(fullData, data);
          // cache new enums' data
          Object.keys(data).map(key => {
            this.EnumMap[key] = data[key];
            return key;
          });
          return resolve({ data: passData, errors });
        })
      ));
  }

  /**
   * calling on a request starting
   * if the request belong to a new queue, call the 'onStart' method
   */
  onStart() {
    this.requestQueueLength++;
    if (this.requestQueueLength > 1 || !this.callbacks.onStart) {
      return;
    }
    this.callbacks.onStart(this.requestQueueLength);
  }

  /**
   * calling on a request ending
   * if current queue finished, calling the 'onEnd' method
   */
  onEnd() {
    this.requestQueueLength--;
    if (this.requestQueueLength || !this.callbacks.onEnd) {
      return;
    }
    this.callbacks.onEnd(this.requestQueueLength);
  }

  /**
   * Callback of requests queue changes.(e.g. new queue or queue finished)
   * @callback FetchQL~requestQueueChanged
   * @param {number} queueLength - length of current request queue
   */

  /**
   * remove empty props(null or '') from object
   * @param {Object} input
   * @returns {Object}
   * @memberOf FetchQL
   * @private
   */
  doOmitEmptyVariables(input) {
    const nonEmptyObj = {};
    Object.keys(input).map(key => {
      const value = input[key];
      if ((typeof value === 'string' && value.length === 0) || value === null || value === undefined) {
        return key;
      } else if (value instanceof Object) {
        nonEmptyObj[key] = this.doOmitEmptyVariables(value);
      } else {
        nonEmptyObj[key] = value;
      }
      return key;
    });
    return nonEmptyObj;
  }
}

export default FetchQL;
<|endoftext|>


<commit_before>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You 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.
 *
 */

var sys = require('sys');

var sprintf = require('sprintf').sprintf;
var constants = require('./constants');
var testUtil = require('./util');

var isValidTestFunctionName = function(name) {
  if (name.indexOf('test') === 0) {
    return true;
  }

  return false;
};

var printChildResults = function(succeeded, failed) {
  var failedCount = Object.keys(failed).length;
  var succeededNames = Object.keys(succeeded);
  var err, failedMessages = [];

  process.stderr.write(constants.OUTPUT_DELIMITER);

  process.stderr.write(constants.SUCCEEDED_STRING);
  process.stderr.write(succeededNames.join(constants.TEST_NAME_DELIMITER));
  process.stderr.write('\n');

  process.stderr.write(constants.FAILED_STRING);

  for (var key in failed) {
    if (failed.hasOwnProperty(key)) {
      err = failed[key].stack;
      failedMessages.push(sprintf('%s%s%s', key, constants.ERROR_MESSAGE_DELIMITER,
                                  err));
    }
  }

  process.stderr.write(failedMessages.join(constants.TEST_NAME_DELIMITER));

  process.stderr.write('\n');

  process.stderr.write(constants.OUTPUT_DELIMITER);
  process.exit(failedCount);
};

/**
 * Parse name and error of the fail tests and name of the succeeded tests from
 * child stdderr.
 *
 * @param {String} Child stderr output.
 *
 * @return {Array} First member is an object with succeeded tests results and
 *                 a second member is an object with failed tests results.
 */
var parseResult = function(stderr) {
  var succeeded = {};
  var failed = {};

  var i;
  var succeededString, failedString;
  var succeededNames, failedNames;
  var succeededLen, succeededName;
  var failedValues, failedValuesLen, failedValue, split;

  var testOutputStart = stderr.indexOf(constants.OUTPUT_DELIMITER);
  var testOutputEnd = stderr.lastIndexOf(constants.OUTPUT_DELIMITER);

  stderr = stderr.substring(testOutputStart + constants.OUTPUT_DELIMITER.length,
                            testOutputEnd).trim();

  var succeededStart = stderr.indexOf(constants.SUCCEEDED_STRING);
  var failedStart = stderr.indexOf(constants.FAILED_STRING);
  var stderrLen = stderr.length;

  if ((succeededStart + constants.SUCCEEDED_STRING.length + 1) !== failedStart) {
    succeededString = stderr.substring(succeededStart + constants.SUCCEEDED_STRING.length,
                                       failedStart).trim();
    succeededNames = succeededString.split(constants.TEST_NAME_DELIMITER);
    succeededLen = succeededNames.length;

    for (i = 0; i < succeededLen; i++) {
      succeededName = succeededNames[i];
      succeeded[succeededName] = true;
    }
  }

  if ((failedStart + constants.FAILED_STRING.length) !== stderrLen) {
    failedString = stderr.substring(failedStart + constants.FAILED_STRING.length,
                                    stderrLen).trim();
    failedValues = failedString.split(constants.TEST_NAME_DELIMITER);
    failedValuesLen = failedValues.length;

    for (i = 0; i < failedValuesLen; i++) {
      failedValue = failedValues[i];
      var split = failedValue.split(constants.ERROR_MESSAGE_DELIMITER);
      failed[split[0]] = split[1];
    }
  }

  return [ succeeded, failed ];
};

var reportSucceeded = function(succeeded) {
  var succeededNames = Object.keys(succeeded);
  var succeededLen = succeededNames.length;
  var i, succeededName;

  for (i = 0; i < succeededLen; i++) {
    succeededName = succeededNames[i];
    sys.puts(sprintf(' %s \033[32m[OK]\033[39m',
                     testUtil.addCharacters(succeededName, 70, ' ')));
  }
};

var reportFailed = function(failed) {
  var failedErr;

  for (var failedName in failed) {
    if (failed.hasOwnProperty(failedName)) {
      failedErr = failed[failedName];

      sys.puts(sprintf(' %s \033[31m[FAIL]\033[39m',
                       testUtil.addCharacters(failedName, 70, ' ')));
      sys.puts(failedErr);
    }
  }
};

var printTestsSummary = function(dateStart, successes, failures, timeouts) {
  var dateEnd = testUtil.getUnixTimestamp();
  var runTime = (dateEnd - dateStart);

  sys.puts(testUtil.addCharacters('', 80, '-'));
  sys.puts(sprintf('Ran %d tests in %0.3fs', (successes + failures), runTime));
  sys.puts('');
  sys.puts(sprintf('Successes: %s', successes));
  sys.puts(sprintf('Failures: %s', failures));
  sys.puts(sprintf('Timeouts: %s', timeouts));
  sys.puts('');

  if (failures === 0) {
    sys.puts('\033[32mPASSED\033[39m');
  }
  else {
    sys.puts('\033[31mFAILED\033[39m');
  }

  process.exit(failures + timeouts);
};

exports.isValidTestFunctionName = isValidTestFunctionName;
exports.printChildResults = printChildResults;
exports.parseResult = parseResult;
exports.reportSucceeded = reportSucceeded;
exports.reportFailed = reportFailed;
exports.printTestsSummary = printTestsSummary;
<commit_msg>Better alignment.<commit_after>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You 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.
 *
 */

var sys = require('sys');

var sprintf = require('sprintf').sprintf;
var constants = require('./constants');
var testUtil = require('./util');

var isValidTestFunctionName = function(name) {
  if (name.indexOf('test') === 0) {
    return true;
  }

  return false;
};

var printChildResults = function(succeeded, failed) {
  var failedCount = Object.keys(failed).length;
  var succeededNames = Object.keys(succeeded);
  var err, failedMessages = [];

  process.stderr.write(constants.OUTPUT_DELIMITER);

  process.stderr.write(constants.SUCCEEDED_STRING);
  process.stderr.write(succeededNames.join(constants.TEST_NAME_DELIMITER));
  process.stderr.write('\n');

  process.stderr.write(constants.FAILED_STRING);

  for (var key in failed) {
    if (failed.hasOwnProperty(key)) {
      err = failed[key].stack;
      failedMessages.push(sprintf('%s%s%s', key, constants.ERROR_MESSAGE_DELIMITER,
                                  err));
    }
  }

  process.stderr.write(failedMessages.join(constants.TEST_NAME_DELIMITER));

  process.stderr.write('\n');

  process.stderr.write(constants.OUTPUT_DELIMITER);
  process.exit(failedCount);
};

/**
 * Parse name and error of the fail tests and name of the succeeded tests from
 * child stdderr.
 *
 * @param {String} Child stderr output.
 *
 * @return {Array} First member is an object with succeeded tests results and
 *                 a second member is an object with failed tests results.
 */
var parseResult = function(stderr) {
  var succeeded = {};
  var failed = {};

  var i;
  var succeededString, failedString;
  var succeededNames, failedNames;
  var succeededLen, succeededName;
  var failedValues, failedValuesLen, failedValue, split;

  var testOutputStart = stderr.indexOf(constants.OUTPUT_DELIMITER);
  var testOutputEnd = stderr.lastIndexOf(constants.OUTPUT_DELIMITER);

  stderr = stderr.substring(testOutputStart + constants.OUTPUT_DELIMITER.length,
                            testOutputEnd).trim();

  var succeededStart = stderr.indexOf(constants.SUCCEEDED_STRING);
  var failedStart = stderr.indexOf(constants.FAILED_STRING);
  var stderrLen = stderr.length;

  if ((succeededStart + constants.SUCCEEDED_STRING.length + 1) !== failedStart) {
    succeededString = stderr.substring(succeededStart + constants.SUCCEEDED_STRING.length,
                                       failedStart).trim();
    succeededNames = succeededString.split(constants.TEST_NAME_DELIMITER);
    succeededLen = succeededNames.length;

    for (i = 0; i < succeededLen; i++) {
      succeededName = succeededNames[i];
      succeeded[succeededName] = true;
    }
  }

  if ((failedStart + constants.FAILED_STRING.length) !== stderrLen) {
    failedString = stderr.substring(failedStart + constants.FAILED_STRING.length,
                                    stderrLen).trim();
    failedValues = failedString.split(constants.TEST_NAME_DELIMITER);
    failedValuesLen = failedValues.length;

    for (i = 0; i < failedValuesLen; i++) {
      failedValue = failedValues[i];
      var split = failedValue.split(constants.ERROR_MESSAGE_DELIMITER);
      failed[split[0]] = split[1];
    }
  }

  return [ succeeded, failed ];
};

var reportSucceeded = function(succeeded) {
  var succeededNames = Object.keys(succeeded);
  var succeededLen = succeededNames.length;
  var i, succeededName;

  for (i = 0; i < succeededLen; i++) {
    succeededName = succeededNames[i];
    sys.puts(sprintf(' %s \033[32m[OK]\033[39m',
                     testUtil.addCharacters(succeededName, 74, ' ')));
  }
};

var reportFailed = function(failed) {
  var failedErr;

  for (var failedName in failed) {
    if (failed.hasOwnProperty(failedName)) {
      failedErr = failed[failedName];

      sys.puts(sprintf(' %s \033[31m[FAIL]\033[39m',
                       testUtil.addCharacters(failedName, 73, ' ')));
      sys.puts(failedErr);
    }
  }
};

var printTestsSummary = function(dateStart, successes, failures, timeouts) {
  var dateEnd = testUtil.getUnixTimestamp();
  var runTime = (dateEnd - dateStart);

  sys.puts(testUtil.addCharacters('', 80, '-'));
  sys.puts(sprintf('Ran %d tests in %0.3fs', (successes + failures), runTime));
  sys.puts('');
  sys.puts(sprintf('Successes: %s', successes));
  sys.puts(sprintf('Failures: %s', failures));
  sys.puts(sprintf('Timeouts: %s', timeouts));
  sys.puts('');

  if (failures === 0) {
    sys.puts('\033[32mPASSED\033[39m');
  }
  else {
    sys.puts('\033[31mFAILED\033[39m');
  }

  process.exit(failures + timeouts);
};

exports.isValidTestFunctionName = isValidTestFunctionName;
exports.printChildResults = printChildResults;
exports.parseResult = parseResult;
exports.reportSucceeded = reportSucceeded;
exports.reportFailed = reportFailed;
exports.printTestsSummary = printTestsSummary;
<|endoftext|>


<commit_before>/**
 * Created by longhao on 2017/5/4.
 */

var winston = require('winston');
var fs = require('fs');
var path = require('path');
var nconf = require('nconf');
var async = require('async');
var _ = require('lodash');
var cors = require('cors');

var express = require('express');
var app = express();
var server;

var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var session = require('express-session');
var useragent = require('express-useragent');
var favicon = require('serve-favicon');

var middleware = require('./server/middleware');

var connectRedis = require("connect-redis")(session);
var storeRedis = new connectRedis({
    host: nconf.get('redis:host'),
    port: nconf.get('redis:port'),
    ttl: nconf.get('redis:ttl'),
    db: 0
});

var utils = require('./server/utils');
var logger = require('./server/logger');
var userAgent = require('./server/socket.io/userAgent');

// init config file
nconf.argv().env().file({
    file: path.join(__dirname, 'config.json')
});

if (nconf.get('app:ssl')) {
    server = require('https').createServer({
        key: fs.readFileSync(nconf.get('app:ssl').key),
        cert: fs.readFileSync(nconf.get('app:ssl').cert),
    }, app);
} else {
    server = require('http').createServer(app);
}

module.exports.server = server;

server.on('error', function (err) {
    winston.error(err);
    if (err.code === 'EADDRINUSE') {
        winston.error('uuChat address in use, exiting...');
        process.exit(1);
    } else if (err.code === 'EADDRNOTAVAIL') {
        winston.error('uuChat ip address is not avail, exiting...');
        process.exit(1);
    } else {
        throw err;
    }
});

server.sessionStore = function() {
    var redisHost = nconf.get('redis:host');
    if (_.isEmpty(redisHost)) {
        var SequelizeStore = require('connect-session-sequelize')(session.Store);
        var sequelize = require('./server/models/index').sequelize;
        winston.info(sequelize.Message);
        return new SequelizeStore({
            db: sequelize
        });
    } else {
        return storeRedis;
    }
};

module.exports.listen = function (callback) {
    callback = callback || function () { };
    async.waterfall([
        function (next) {
            setupExpress(app, next);
            next();
        },
        function (next) {
            checkRedisStarted(next);

        },
        function () {
            listen();
        }
    ], function (err) {
        if (err) {
            switch (err.message) {
                case 'redis-need-start':
                    winston.error('you need to start redis, eg: redis-server /usr/local/redis/redis.conf &');
                    break;
                case 'redis-version-too-lower':
                    winston.error('you redis version is too lower , please update redis version above 3.0.0');
                    break;
                case 'logger-folder-need-create':
                    winston.error('logger folder need create in root directory.');
                default:
                    winston.error(err);
                    break;
            }
            process.exit();
        }
        callback();
    });
};

function baseHtmlRoute(app, middlewareDev) {
    app.use(express.static(path.join(__dirname, '../build')));
    //need filter css, js, images files
    app.use(fileFilters);
    app.use(session({
        store: server.sessionStore(),
        secret: nconf.get('socket.io:secretKey'),
        key: nconf.get('socket.io:sessionKey'),
        cookie: setupCookie(),
        resave: false,
        saveUninitialized: true
    }));

    app.get('/', function response(req, res) {
        var html = path.join(__dirname, '../build/app.html');
        htmlRender(middlewareDev, res, html);
    });
    app.get('/demo', function response(req, res) {
        setupSession(req, res);
        var html = path.join(__dirname, '../build/customer.html');
        htmlRender(middlewareDev, res, html);
    });
    app.get('/console', function response(req, res) {
        var html = path.join(__dirname, '../build/console.html');
        htmlRender(middlewareDev, res, html);
    });
    app.get('/console/index', function response(req, res) {
        if (!req.session.csid) {
            res.redirect('/console');
        }
        var html = path.join(__dirname, '../build/console.html');
        htmlRender(middlewareDev, res, html);
    });
    app.get('/chat', function response(req, res) {
        if (!req.session.csid) {
            res.redirect('/');
        }
        var html = path.join(__dirname, '../build/app.html');
        htmlRender(middlewareDev, res, html);
    });
    app.get('/register', function response(req, res) {
        var html = path.join(__dirname, '../build/app.html');
        htmlRender(middlewareDev, res, html);
    });
    var opts = middleware.whiteListOpt();
    opts.credentials = true;
    app.get('/s', cors(opts), function response(req, res) {
        setupSession(req, res);
        var html = path.join(__dirname, '../build/storage.html');
        htmlRender(middlewareDev, res, html);
    });
}

function htmlRender(middlewareDev, res, html) {
    if (middlewareDev) {
        res.write(middlewareDev.fileSystem.readFileSync(html));
        res.end();
    } else {
        res.render(html);
    }
}

function setupExpress(app, callback) {
    app.set('showStackError', true);
    app.disable('x-powered-by'); // http://expressjs.com/zh-cn/advanced/best-practice-security.html
    app.set('json spaces', process.env.NODE_ENV === 'development' ? 4 : 0);

    app.use('/static/images', express.static(path.join(__dirname, './client/static/images')));
    app.use('/content/upload', express.static(path.join(__dirname, '../content/upload')));
    app.use('/content/avatar', express.static(path.join(__dirname, '../content/avatar')));

    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({ extended: false }));
    app.use(cookieParser(nconf.get('socket.io:secretKey')));

    app.use(useragent.express());
    setupFavicon(app);

    if (global.env === 'development') {
        var webpack = require('webpack');
        var webpackMiddleware = require('webpack-dev-middleware');
        var webpackHotMiddleware = require('webpack-hot-middleware');
        var config = require('../tools/webpack.config.dev.js');
        var compiler = webpack(config);
        var middlewareDev = webpackMiddleware(compiler, {
            publicPath: config.output.publicPath,
            contentBase: 'src',
            stats: {
                colors: true,
                hash: false,
                timings: true,
                chunks: false,
                chunkModules: false,
                modules: false
            }
        });

        app.use(middlewareDev);
        app.use(webpackHotMiddleware(compiler, {
            log: console.log, path: '/__webpack_hmr', heartbeat: 10 * 1000
        }));

        baseHtmlRoute(app, middlewareDev);
    } else {
        baseHtmlRoute(app, null);
        app.enable('cache');
        app.enable('minification');
    }

    app.set('view engine', 'html');
    app.engine('html', require('ejs').renderFile);
    app.enable('view cache');

    var routes = require('./server/routes');
    routes(app, middleware);

    //app.use(middleware.checkAccountPermissions);

    setupAutoLocale(app, callback);

    // catch 404 and forward to error handler
    app.use(function(req, res, next) {
        logger.error("~~~~~~ has 404 error, please see browser console log!");
        res.status(404).send('can not find page!');
    });
    app.use(function(err, req, res, next) {
        if (global.env === 'development') {
            logger.error(err.stack);
        } else {
            logger.error("~~~~~~ has 503 error!");
        }
        res.status(503).send('system has problem.');
    });

    winston.info('setup express success!');
}

function setupFavicon(app) {
    app.use(favicon(path.join(__dirname, 'client/static/images/uuchat.ico')));
}

function setupCookie() {
    var oneMonth = 30 * 86400000;

    var cookie = {
        expires: new Date(Date.now() + oneMonth)
    };

    var relativePath = nconf.get('app:relative_path');
    if (relativePath !== '') {
        cookie.path = relativePath;
    }

    return cookie;
}

function setupSession(req, res) {
    var cid = '';
    var ua = req.useragent;
    if (req.session.cid) {
        cid = req.session.cid;
    } else {
        cid = require('uuid/v4')();  //gen uuid
        req.session.cid = cid;
        ua.needSnycDB = true;
    }

    //res.cookie('uu.c', cid, {expires: new Date(Date.now() + 900000), httpOnly: true, path: '/'});

    var headers = req ? req.headers : {};
    var host = headers.host;
    var referer = headers.referer || '';

    if (!host) {
        var url = require('url');
        host = url.parse(referer).host || '';
    }
    var ip = headers['x-forwarded-for'] || req.connection.remoteAddress;

    ua.cid = cid;
    ua.ip = ip;
    ua.host = host;
    ua.url = req.protocol + '://' + req.get('host') + req.originalUrl;
    userAgent.create(ua);
    winston.info('Customer session had set');
}

function fileFilters(req, res, next) {
    var originalUrl = req.originalUrl;
    var fileFilters = ['css', 'js', 'png', 'jpg', 'jpeg', 'ico'];
    var flag = false;
    var suffix = originalUrl.split('.').pop();
    winston.info(suffix);
    if (fileFilters.indexOf(suffix) !== -1) {
        flag = true;
    }
    if (flag) {
        res.render(path.join(__dirname, originalUrl));
    } else {
        next();
    }
}

//check redis has started;

function checkRedisStarted(callback){
    var redisHost = nconf.get('redis:host');
    if (!_.isEmpty(redisHost)) {
        utils.lsof(nconf.get('redis:port'), function (data) {
            if (data.length > 0) {
                winston.info('');
                winston.info("[redis] has started");
            } else {
                callback(new Error('redis-need-start'));
            }
        });

        //version print
        if (global.env !== 'development') {
            var _redis = require("../node_modules/connect-redis/node_modules/redis"),
                client = _redis.createClient();
            client.info(function () {
                var info = client.server_info;
                var versions = info.versions;
                if (versions[0] < 3) {
                    callback(new Error('redis-version-too-lower'));
                } else {
                    winston.info("[redis] version = %s", info.redis_version);
                    winston.info("[redis] executable = %s", info.executable);
                    winston.info("[redis] config file = %s", info.config_file);
                    winston.info('');
                }
            });
        }
    }

    callback();
}

function setupAutoLocale(app, callback) {

}

function listen() {
    var configAddress = nconf.get('app:address');
    var address = ((configAddress === '0.0.0.0' || !configAddress) ? '0.0.0.0' : configAddress);

    //server.listen.apply(server, args);
    server.listen(nconf.get('app:port'), address, function () {
        process.setMaxListeners(0);
        process.env.TZ = 'Hongkong';
    });
    server.on('listening', function onListening() {
        var addr = server.address();
        var bind = typeof addr === 'string' ?
            'pipe ' + addr :
            'port ' + addr.port;
        winston.info('Listening on ' + bind);
    });
}
<commit_msg>/chat redirect<commit_after>/**
 * Created by longhao on 2017/5/4.
 */

var winston = require('winston');
var fs = require('fs');
var path = require('path');
var nconf = require('nconf');
var async = require('async');
var _ = require('lodash');
var cors = require('cors');

var express = require('express');
var app = express();
var server;

var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var session = require('express-session');
var useragent = require('express-useragent');
var favicon = require('serve-favicon');

var middleware = require('./server/middleware');

var connectRedis = require("connect-redis")(session);
var storeRedis = new connectRedis({
    host: nconf.get('redis:host'),
    port: nconf.get('redis:port'),
    ttl: nconf.get('redis:ttl'),
    db: 0
});

var utils = require('./server/utils');
var logger = require('./server/logger');
var userAgent = require('./server/socket.io/userAgent');

// init config file
nconf.argv().env().file({
    file: path.join(__dirname, 'config.json')
});

if (nconf.get('app:ssl')) {
    server = require('https').createServer({
        key: fs.readFileSync(nconf.get('app:ssl').key),
        cert: fs.readFileSync(nconf.get('app:ssl').cert),
    }, app);
} else {
    server = require('http').createServer(app);
}

module.exports.server = server;

server.on('error', function (err) {
    winston.error(err);
    if (err.code === 'EADDRINUSE') {
        winston.error('uuChat address in use, exiting...');
        process.exit(1);
    } else if (err.code === 'EADDRNOTAVAIL') {
        winston.error('uuChat ip address is not avail, exiting...');
        process.exit(1);
    } else {
        throw err;
    }
});

server.sessionStore = function() {
    var redisHost = nconf.get('redis:host');
    if (_.isEmpty(redisHost)) {
        var SequelizeStore = require('connect-session-sequelize')(session.Store);
        var sequelize = require('./server/models/index').sequelize;
        winston.info(sequelize.Message);
        return new SequelizeStore({
            db: sequelize
        });
    } else {
        return storeRedis;
    }
};

module.exports.listen = function (callback) {
    callback = callback || function () { };
    async.waterfall([
        function (next) {
            setupExpress(app, next);
            next();
        },
        function (next) {
            checkRedisStarted(next);

        },
        function () {
            listen();
        }
    ], function (err) {
        if (err) {
            switch (err.message) {
                case 'redis-need-start':
                    winston.error('you need to start redis, eg: redis-server /usr/local/redis/redis.conf &');
                    break;
                case 'redis-version-too-lower':
                    winston.error('you redis version is too lower , please update redis version above 3.0.0');
                    break;
                case 'logger-folder-need-create':
                    winston.error('logger folder need create in root directory.');
                default:
                    winston.error(err);
                    break;
            }
            process.exit();
        }
        callback();
    });
};

function baseHtmlRoute(app, middlewareDev) {
    app.use(express.static(path.join(__dirname, '../build')));
    //need filter css, js, images files
    app.use(fileFilters);
    app.use(session({
        store: server.sessionStore(),
        secret: nconf.get('socket.io:secretKey'),
        key: nconf.get('socket.io:sessionKey'),
        cookie: setupCookie(),
        resave: false,
        saveUninitialized: true
    }));

    app.get('/', function response(req, res) {
        var html = path.join(__dirname, '../build/app.html');
        htmlRender(middlewareDev, res, html);
    });
    app.get('/demo', function response(req, res) {
        setupSession(req, res);
        var html = path.join(__dirname, '../build/customer.html');
        htmlRender(middlewareDev, res, html);
    });
    app.get('/console', function response(req, res) {
        var html = path.join(__dirname, '../build/console.html');
        htmlRender(middlewareDev, res, html);
    });
    app.get('/console/index', function response(req, res) {
        if (!req.session.csid) {
            res.redirect('/console');
        }
        var html = path.join(__dirname, '../build/console.html');
        htmlRender(middlewareDev, res, html);
    });
    app.get('/chat', function response(req, res) {
        if (!req.session.csid) {
            res.redirect('/');
        }else {
            var customerSuccess = require('./server/socket.io/customerSuccess');
            var csid = req.session.csid;
            winston.info(req.session);
            if (_.isEmpty(customerSuccess.get(csid))) {
                customerSuccess.create({csid: csid, name: req.session.csName, photo: req.session.photo});
            }
        }
        var html = path.join(__dirname, '../build/app.html');
        htmlRender(middlewareDev, res, html);
    });
    app.get('/register', function response(req, res) {
        var html = path.join(__dirname, '../build/app.html');
        htmlRender(middlewareDev, res, html);
    });
    var opts = middleware.whiteListOpt();
    opts.credentials = true;
    app.get('/s', cors(opts), function response(req, res) {
        setupSession(req, res);
        var html = path.join(__dirname, '../build/storage.html');
        htmlRender(middlewareDev, res, html);
    });
}

function htmlRender(middlewareDev, res, html) {
    if (middlewareDev) {
        res.write(middlewareDev.fileSystem.readFileSync(html));
        res.end();
    } else {
        res.render(html);
    }
}

function setupExpress(app, callback) {
    app.set('showStackError', true);
    app.disable('x-powered-by'); // http://expressjs.com/zh-cn/advanced/best-practice-security.html
    app.set('json spaces', process.env.NODE_ENV === 'development' ? 4 : 0);

    app.use('/static/images', express.static(path.join(__dirname, './client/static/images')));
    app.use('/content/upload', express.static(path.join(__dirname, '../content/upload')));
    app.use('/content/avatar', express.static(path.join(__dirname, '../content/avatar')));

    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({ extended: false }));
    app.use(cookieParser(nconf.get('socket.io:secretKey')));

    app.use(useragent.express());
    setupFavicon(app);

    if (global.env === 'development') {
        var webpack = require('webpack');
        var webpackMiddleware = require('webpack-dev-middleware');
        var webpackHotMiddleware = require('webpack-hot-middleware');
        var config = require('../tools/webpack.config.dev.js');
        var compiler = webpack(config);
        var middlewareDev = webpackMiddleware(compiler, {
            publicPath: config.output.publicPath,
            contentBase: 'src',
            stats: {
                colors: true,
                hash: false,
                timings: true,
                chunks: false,
                chunkModules: false,
                modules: false
            }
        });

        app.use(middlewareDev);
        app.use(webpackHotMiddleware(compiler, {
            log: console.log, path: '/__webpack_hmr', heartbeat: 10 * 1000
        }));

        baseHtmlRoute(app, middlewareDev);
    } else {
        baseHtmlRoute(app, null);
        app.enable('cache');
        app.enable('minification');
    }

    app.set('view engine', 'html');
    app.engine('html', require('ejs').renderFile);
    app.enable('view cache');

    var routes = require('./server/routes');
    routes(app, middleware);

    //app.use(middleware.checkAccountPermissions);

    setupAutoLocale(app, callback);

    // catch 404 and forward to error handler
    app.use(function(req, res, next) {
        logger.error("~~~~~~ has 404 error, please see browser console log!");
        res.status(404).send('can not find page!');
    });
    app.use(function(err, req, res, next) {
        if (global.env === 'development') {
            logger.error(err.stack);
        } else {
            logger.error("~~~~~~ has 503 error!");
        }
        res.status(503).send('system has problem.');
    });

    winston.info('setup express success!');
}

function setupFavicon(app) {
    app.use(favicon(path.join(__dirname, 'client/static/images/uuchat.ico')));
}

function setupCookie() {
    var oneMonth = 30 * 86400000;

    var cookie = {
        expires: new Date(Date.now() + oneMonth)
    };

    var relativePath = nconf.get('app:relative_path');
    if (relativePath !== '') {
        cookie.path = relativePath;
    }

    return cookie;
}

function setupSession(req, res) {
    var cid = '';
    var ua = req.useragent;
    if (req.session.cid) {
        cid = req.session.cid;
    } else {
        cid = require('uuid/v4')();  //gen uuid
        req.session.cid = cid;
        ua.needSnycDB = true;
    }

    //res.cookie('uu.c', cid, {expires: new Date(Date.now() + 900000), httpOnly: true, path: '/'});

    var headers = req ? req.headers : {};
    var host = headers.host;
    var referer = headers.referer || '';

    if (!host) {
        var url = require('url');
        host = url.parse(referer).host || '';
    }
    var ip = headers['x-forwarded-for'] || req.connection.remoteAddress;

    ua.cid = cid;
    ua.ip = ip;
    ua.host = host;
    ua.url = req.protocol + '://' + req.get('host') + req.originalUrl;
    userAgent.create(ua);
    winston.info('Customer session had set');
}

function fileFilters(req, res, next) {
    var originalUrl = req.originalUrl;
    var fileFilters = ['css', 'js', 'png', 'jpg', 'jpeg', 'ico'];
    var flag = false;
    var suffix = originalUrl.split('.').pop();
    winston.info(suffix);
    if (fileFilters.indexOf(suffix) !== -1) {
        flag = true;
    }
    if (flag) {
        res.render(path.join(__dirname, originalUrl));
    } else {
        next();
    }
}

//check redis has started;

function checkRedisStarted(callback){
    var redisHost = nconf.get('redis:host');
    if (!_.isEmpty(redisHost)) {
        utils.lsof(nconf.get('redis:port'), function (data) {
            if (data.length > 0) {
                winston.info('');
                winston.info("[redis] has started");
            } else {
                callback(new Error('redis-need-start'));
            }
        });

        //version print
        if (global.env !== 'development') {
            var _redis = require("../node_modules/connect-redis/node_modules/redis"),
                client = _redis.createClient();
            client.info(function () {
                var info = client.server_info;
                var versions = info.versions;
                if (versions[0] < 3) {
                    callback(new Error('redis-version-too-lower'));
                } else {
                    winston.info("[redis] version = %s", info.redis_version);
                    winston.info("[redis] executable = %s", info.executable);
                    winston.info("[redis] config file = %s", info.config_file);
                    winston.info('');
                }
            });
        }
    }

    callback();
}

function setupAutoLocale(app, callback) {

}

function listen() {
    var configAddress = nconf.get('app:address');
    var address = ((configAddress === '0.0.0.0' || !configAddress) ? '0.0.0.0' : configAddress);

    //server.listen.apply(server, args);
    server.listen(nconf.get('app:port'), address, function () {
        process.setMaxListeners(0);
        process.env.TZ = 'Hongkong';
    });
    server.on('listening', function onListening() {
        var addr = server.address();
        var bind = typeof addr === 'string' ?
            'pipe ' + addr :
            'port ' + addr.port;
        winston.info('Listening on ' + bind);
    });
}
<|endoftext|>


<commit_before>Elm.Native.Char = {};
Elm.Native.Char.make = function(elm) {
    elm.Native = elm.Native || {};
    elm.Native.Char = elm.Native.Char || {};
    if (elm.Native.Char.values) return elm.Native.Char.values;

    var Utils = Elm.Native.Utils.make(elm);

    function isBetween(lo,hi) { return function(chr) {
	var c = chr.charCodeAt(0);
	return lo <= c && c <= hi;
    };
                              }
    var isDigit = isBetween('0'.charCodeAt(0),'9'.charCodeAt(0));
    var chk1 = isBetween('a'.charCodeAt(0),'f'.charCodeAt(0));
    var chk2 = isBetween('A'.charCodeAt(0),'F'.charCodeAt(0));

    return elm.Native.Char.values = {
        fromCode : function(c) { return String.fromCharCode(c); },
        toCode   : function(c) { return c.toUpperCase().charCodeAt(0); },
        toUpper  : function(c) { return Utils.chr(c.toUpperCase()); },
        toLower  : function(c) { return Utils.chr(c.toLowerCase()); },
        toLocaleUpper : function(c) { return Utils.chr(c.toLocaleUpperCase()); },
        toLocaleLower : function(c) { return Utils.chr(c.toLocaleLowerCase()); },
        isLower    : isBetween('a'.charCodeAt(0),'z'.charCodeAt(0)),
        isUpper    : isBetween('A'.charCodeAt(0),'Z'.charCodeAt(0)),
        isDigit    : isDigit,
        isOctDigit : isBetween('0'.charCodeAt(0),'7'.charCodeAt(0)),
        isHexDigit : function(c) { return isDigit(c) || chk1(c) || chk2(c); }
    };
};
<commit_msg>elm -> localRuntime in Char.js<commit_after>Elm.Native.Char = {};
Elm.Native.Char.make = function(localRuntime) {
    localRuntime.Native = localRuntime.Native || {};
    localRuntime.Native.Char = localRuntime.Native.Char || {};
    if (localRuntime.Native.Char.values) return localRuntime.Native.Char.values;

    var Utils = Elm.Native.Utils.make(localRuntime);

    function isBetween(lo,hi) { return function(chr) {
	var c = chr.charCodeAt(0);
	return lo <= c && c <= hi;
    };
                              }
    var isDigit = isBetween('0'.charCodeAt(0),'9'.charCodeAt(0));
    var chk1 = isBetween('a'.charCodeAt(0),'f'.charCodeAt(0));
    var chk2 = isBetween('A'.charCodeAt(0),'F'.charCodeAt(0));

    return localRuntime.Native.Char.values = {
        fromCode : function(c) { return String.fromCharCode(c); },
        toCode   : function(c) { return c.toUpperCase().charCodeAt(0); },
        toUpper  : function(c) { return Utils.chr(c.toUpperCase()); },
        toLower  : function(c) { return Utils.chr(c.toLowerCase()); },
        toLocaleUpper : function(c) { return Utils.chr(c.toLocaleUpperCase()); },
        toLocaleLower : function(c) { return Utils.chr(c.toLocaleLowerCase()); },
        isLower    : isBetween('a'.charCodeAt(0),'z'.charCodeAt(0)),
        isUpper    : isBetween('A'.charCodeAt(0),'Z'.charCodeAt(0)),
        isDigit    : isDigit,
        isOctDigit : isBetween('0'.charCodeAt(0),'7'.charCodeAt(0)),
        isHexDigit : function(c) { return isDigit(c) || chk1(c) || chk2(c); }
    };
};
<|endoftext|>


<commit_before>/**
 * @file
 *
 * Utilities for "key-tagged values": An object with a single-key, hinting at
 * its value. Useful for tagged unions.
 */

/**
 * Thrown when expecting a key-tagged value but got something else.
 */
export class NonConformingError extends TypeError {
}

/**
 * Thrown when a match() found no matching key.
 */
export class MatchError extends TypeError {
}

/**
 * @param {object} obj key-tagged value.
 * @return {string} the key of object.
 * @throws NonConformingError when obj is not a key-tagged value.
 */
export function getKey(obj) {
  const keys = Object.keys(obj);
  if (keys.length !== 1) {
    throw new NonConformingError(
      `Expected exactly one key but found ${keys.length}`
    );
  }
  return keys[0];
}

/**
 * Given any value, returns whether this value is a conforming key-tagged
 * value. That is, an object with exactly one enumerable property.
 *
 * @param {*} val any value
 * @return {boolean} true if the object is a suitable key-tagged value.
 */
export function isKeyTaggedValue(val) {
  return (
    typeof val === 'object' &&
    val !== null &&
    Object.keys(val).length === 1
  );
}

/**
 * Returns an array of the key and value from the key-tagged value.
 *
 * @param {object} obj key-tagged value.
 * @return {Array<?>} An array of two elements: key and its value.
 * @throws NonConformingError when obj is not a key-tagged value.
 */
export function unpack(obj) {
  const key = getKey(obj);
  return [key, obj[key]];
}

/**
 * Like unpack(), but returns an object with key and value.
 *
 * @param {object} obj key-tagged value.
 * @return {{key: string, value}} An object with properties `key` and `value`.
 * @throws NonConformingError when obj is not a key-tagged value.
 */
export function unpackObject(obj) {
  const key = getKey(obj);
  return {key, value: obj[key]};
}

/**
 * Runs an action depending on the single key in the object. Throws if the
 * object has more than one key, or if there is no action given for the key.
 *
 * It's similar to switch statement on the key name. Unlike a switch
 * statement, it has a return value, and it may only run one case per call.
 *
 * The callback matched is called with the value, and the key, respectively.
 *
 * @param {object} obj key-tagged value.
 * @param {object} map a map of possible keys to the callback that should be
 *                     invoked when the key is matched.
 * @param {function} otherwise called on match failure; it should have the
 * same signature as a function given in `map`.
 * @return {?} The return of the matched callback.
 * @throws MatchError When there is no match, and no third parameter is
 * provided.
 * @throws NonConformingError when obj is not a key-tagged value.
 */
export function match(obj, map, otherwise) {
  const [key, val] = unpack(obj);
  const action = map[key];

  if (!(action instanceof Function)) {
    if (otherwise instanceof Function) {
      return otherwise(val, key);
    }
    throw new MatchError(`No action provided for key: ${key}`);
  }

  /* Invoke the action. */
  return action(val, key);
}

/**
 * Alias for match().
 * @deprecated
 */
export function onKey(...args) {
  return match(...args);
}
<commit_msg>Remove onKey()<commit_after>/**
 * @file
 *
 * Utilities for "key-tagged values": An object with a single-key, hinting at
 * its value. Useful for tagged unions.
 */

/**
 * Thrown when expecting a key-tagged value but got something else.
 */
export class NonConformingError extends TypeError {
}

/**
 * Thrown when a match() found no matching key.
 */
export class MatchError extends TypeError {
}

/**
 * @param {object} obj key-tagged value.
 * @return {string} the key of object.
 * @throws NonConformingError when obj is not a key-tagged value.
 */
export function getKey(obj) {
  const keys = Object.keys(obj);
  if (keys.length !== 1) {
    throw new NonConformingError(
      `Expected exactly one key but found ${keys.length}`
    );
  }
  return keys[0];
}

/**
 * Given any value, returns whether this value is a conforming key-tagged
 * value. That is, an object with exactly one enumerable property.
 *
 * @param {*} val any value
 * @return {boolean} true if the object is a suitable key-tagged value.
 */
export function isKeyTaggedValue(val) {
  return (
    typeof val === 'object' &&
    val !== null &&
    Object.keys(val).length === 1
  );
}

/**
 * Returns an array of the key and value from the key-tagged value.
 *
 * @param {object} obj key-tagged value.
 * @return {Array<?>} An array of two elements: key and its value.
 * @throws NonConformingError when obj is not a key-tagged value.
 */
export function unpack(obj) {
  const key = getKey(obj);
  return [key, obj[key]];
}

/**
 * Like unpack(), but returns an object with key and value.
 *
 * @param {object} obj key-tagged value.
 * @return {{key: string, value}} An object with properties `key` and `value`.
 * @throws NonConformingError when obj is not a key-tagged value.
 */
export function unpackObject(obj) {
  const key = getKey(obj);
  return {key, value: obj[key]};
}

/**
 * Runs an action depending on the single key in the object. Throws if the
 * object has more than one key, or if there is no action given for the key.
 *
 * It's similar to switch statement on the key name. Unlike a switch
 * statement, it has a return value, and it may only run one case per call.
 *
 * The callback matched is called with the value, and the key, respectively.
 *
 * @param {object} obj key-tagged value.
 * @param {object} map a map of possible keys to the callback that should be
 *                     invoked when the key is matched.
 * @param {function} otherwise called on match failure; it should have the
 * same signature as a function given in `map`.
 * @return {?} The return of the matched callback.
 * @throws MatchError When there is no match, and no third parameter is
 * provided.
 * @throws NonConformingError when obj is not a key-tagged value.
 */
export function match(obj, map, otherwise) {
  const [key, val] = unpack(obj);
  const action = map[key];

  if (!(action instanceof Function)) {
    if (otherwise instanceof Function) {
      return otherwise(val, key);
    }
    throw new MatchError(`No action provided for key: ${key}`);
  }

  /* Invoke the action. */
  return action(val, key);
}
<|endoftext|>


<commit_before>// @ts-check

const fs = require('fs');
const ts = require('typescript');
const curry = require('lodash/curry');
const flatten = require('lodash/flatten');
const readdir = require('recursive-readdir');

const shouldAnalyze = (predicate, sourceFile, kind) => predicate(kind.getText(sourceFile));

const extractRelevantClassMethods = (classDefinition, predicate) => {
  return classDefinition.members
    .filter(member => member.kind === ts.SyntaxKind.MethodDeclaration)
    .filter(member => predicate(member))
    .map(member => member.name.text)
}

const extractRelevantMethods = (fileObject, predicate) => {
  return fileObject.statements.reduce((acc, node) => {
    switch (node.kind) {
      case ts.SyntaxKind.ModuleDeclaration:
        return acc.concat(extractRelevantMethods(node.body, predicate));
      case ts.SyntaxKind.ClassDeclaration:
        return acc.concat(extractRelevantClassMethods(node, predicate));
      default:
        return acc;
    }
  }, []);
};

exports.parseFile = (filePath, predicate) => {
  const fileName = filePath.split('/').pop();
  const sourceFile = ts.createSourceFile(
    fileName,
    fs.readFileSync(filePath).toString(),
    ts.ScriptTarget.ES2016
  );

  const shouldAnalyzeKind = curry(shouldAnalyze)(predicate)(sourceFile);

  return new Promise((resolve, reject) => {
    if (shouldAnalyzeKind(sourceFile)) {
      resolve(extractRelevantMethods(sourceFile, shouldAnalyzeKind));
    } else {
      resolve([]);
    }
  });
};

exports.parseFolder = (path, fileType, predicate) => {
  return readdir(path, [`!*.${fileType}`, `*.spec.${fileType}`, `*.d.ts`])
    .then(files => {
      const parseFiles = files.map(filePath => this.parseFile(filePath, predicate));
      return Promise.all(parseFiles);
    })
    .then((values) => {
      return flatten(values);
    });
}
<commit_msg>chore(parser): exclude drivers<commit_after>// @ts-check

const fs = require('fs');
const ts = require('typescript');
const curry = require('lodash/curry');
const flatten = require('lodash/flatten');
const readdir = require('recursive-readdir');

const shouldAnalyze = (predicate, sourceFile, kind) => predicate(kind.getText(sourceFile));

const extractRelevantClassMethods = (classDefinition, predicate) => {
  return classDefinition.members
    .filter(member => member.kind === ts.SyntaxKind.MethodDeclaration)
    .filter(member => predicate(member))
    .map(member => member.name.text)
}

const extractRelevantMethods = (fileObject, predicate) => {
  return fileObject.statements.reduce((acc, node) => {
    switch (node.kind) {
      case ts.SyntaxKind.ModuleDeclaration:
        return acc.concat(extractRelevantMethods(node.body, predicate));
      case ts.SyntaxKind.ClassDeclaration:
        return acc.concat(extractRelevantClassMethods(node, predicate));
      default:
        return acc;
    }
  }, []);
};

exports.parseFile = (filePath, predicate) => {
  const fileName = filePath.split('/').pop();
  const sourceFile = ts.createSourceFile(
    fileName,
    fs.readFileSync(filePath).toString(),
    ts.ScriptTarget.ES2016
  );

  const shouldAnalyzeKind = curry(shouldAnalyze)(predicate)(sourceFile);

  return new Promise((resolve, reject) => {
    if (shouldAnalyzeKind(sourceFile)) {
      resolve(extractRelevantMethods(sourceFile, shouldAnalyzeKind));
    } else {
      resolve([]);
    }
  });
};

exports.parseFolder = (path, fileType, predicate) => {
  return readdir(path, [`!*.${fileType}`, `*.spec.${fileType}`, `*.driver.${fileType}`, `*.d.ts`])
    .then(files => {
      const parseFiles = files.map(filePath => this.parseFile(filePath, predicate));
      return Promise.all(parseFiles);
    })
    .then((values) => {
      return flatten(values);
    });
}
<|endoftext|>


<commit_before>import _ from 'lodash'
import request from 'request-promise'
import fs from 'fs'

const BASE_SENTRY_URL = 'https://sentry.io/api/0/projects'

const DEFAULT_TRANSFORM = (filename) => filename

module.exports = class SentryPlugin {
	constructor(options) {
		this.baseSentryURL = options.baseSentryURL || BASE_SENTRY_URL
		this.organisationSlug = options.organisation
		this.projectSlug = options.project
		this.apiKey = options.apiKey

		this.releaseVersion = options.release;

		this.include = options.include || /\.js$|\.map$/
		this.exclude = options.exclude

		this.filenameTransform = options.filenameTransform || DEFAULT_TRANSFORM
		this.suppressErrors = options.suppressErrors
	}

	apply(compiler) {
		compiler.plugin('after-emit', (compilation, cb) => {
			const errors = this.ensureRequiredOptions()

			if (errors) {
				return this.handleErrors(errors, compilation, cb)
			}

			const files = this.getFiles(compilation)

			if (_.isFunction(this.releaseVersion)) {
				this.releaseVersion = this.releaseVersion(compilation.hash)
			}

			return this.createRelease()
				.then(() => this.uploadFiles(files))
				.then(() => cb())
				.catch((err) => this.handleErrors(err, compilation, cb))
		})
	}

	handleErrors(err, compilation, cb) {
		const errorMsg = `Sentry Plugin: ${err}`
		if (this.suppressErrors) {
			compilation.warnings.push(errorMsg)
		}
		else {
			compilation.errors.push(errorMsg)
		}

		cb()
	}

	ensureRequiredOptions() {
		if (!this.organisationSlug) {
			return new Error('Must provide organisation')
		}
		else if (!this.projectSlug) {
			return new Error(('Must provide project'))
		}
		else if (!this.apiKey) {
			return new Error('Must provide api key')
		}
		else if (!this.releaseVersion) {
			return new Error('Must provide release version')
		}
		else {
			return null
		}
	}

	getFiles(compilation) {
		return _.reduce(compilation.assets, (acc, asset, name) => {
			return this.isIncludeOrExclude(name)
				? acc.concat({ name, path: asset.existsAt })
				: acc
		}, [])
	}

	isIncludeOrExclude(filename) {
		const isIncluded = this.include ? this.include.test(filename) : true
		const isExcluded = this.exclude ? this.exclude.test(filename) : false

		return isIncluded && !isExcluded
	}

	createRelease() {
		return request({
			url: `${this.sentryReleaseUrl()}/`,
			method: 'POST',
			auth: {
				bearer: this.apiKey
			},
			headers: {
				'Content-Type': 'application/json'
			},
			body: JSON.stringify({ version: this.releaseVersion })
		})
	}

	uploadFiles(files) {
		return Promise.all(files.map(this.uploadFile.bind(this)))
	}

	uploadFile({ path, name }) {
		return request({
			url: `${this.sentryReleaseUrl()}/${this.releaseVersion}/files/`,
			method: 'POST',
			auth: {
				bearer: this.apiKey
			},
			formData: {
				file: fs.createReadStream(path),
				name: this.filenameTransform(name)
			}
		})
	}

	sentryReleaseUrl() {
		return `${this.baseSentryURL}/${this.organisationSlug}/${this.projectSlug}/releases`
	}
}
<commit_msg>Make default transform work correctly<commit_after>import _ from 'lodash'
import request from 'request-promise'
import fs from 'fs'

const BASE_SENTRY_URL = 'https://sentry.io/api/0/projects'

const DEFAULT_TRANSFORM = (filename) => `~/${filename}`

module.exports = class SentryPlugin {
	constructor(options) {
		this.baseSentryURL = options.baseSentryURL || BASE_SENTRY_URL
		this.organisationSlug = options.organisation
		this.projectSlug = options.project
		this.apiKey = options.apiKey

		this.releaseVersion = options.release;

		this.include = options.include || /\.js$|\.map$/
		this.exclude = options.exclude

		this.filenameTransform = options.filenameTransform || DEFAULT_TRANSFORM
		this.suppressErrors = options.suppressErrors
	}

	apply(compiler) {
		compiler.plugin('after-emit', (compilation, cb) => {
			const errors = this.ensureRequiredOptions()

			if (errors) {
				return this.handleErrors(errors, compilation, cb)
			}

			const files = this.getFiles(compilation)

			if (_.isFunction(this.releaseVersion)) {
				this.releaseVersion = this.releaseVersion(compilation.hash)
			}

			return this.createRelease()
				.then(() => this.uploadFiles(files))
				.then(() => cb())
				.catch((err) => this.handleErrors(err, compilation, cb))
		})
	}

	handleErrors(err, compilation, cb) {
		const errorMsg = `Sentry Plugin: ${err}`
		if (this.suppressErrors) {
			compilation.warnings.push(errorMsg)
		}
		else {
			compilation.errors.push(errorMsg)
		}

		cb()
	}

	ensureRequiredOptions() {
		if (!this.organisationSlug) {
			return new Error('Must provide organisation')
		}
		else if (!this.projectSlug) {
			return new Error(('Must provide project'))
		}
		else if (!this.apiKey) {
			return new Error('Must provide api key')
		}
		else if (!this.releaseVersion) {
			return new Error('Must provide release version')
		}
		else {
			return null
		}
	}

	getFiles(compilation) {
		return _.reduce(compilation.assets, (acc, asset, name) => {
			return this.isIncludeOrExclude(name)
				? acc.concat({ name, path: asset.existsAt })
				: acc
		}, [])
	}

	isIncludeOrExclude(filename) {
		const isIncluded = this.include ? this.include.test(filename) : true
		const isExcluded = this.exclude ? this.exclude.test(filename) : false

		return isIncluded && !isExcluded
	}

	createRelease() {
		return request({
			url: `${this.sentryReleaseUrl()}/`,
			method: 'POST',
			auth: {
				bearer: this.apiKey
			},
			headers: {
				'Content-Type': 'application/json'
			},
			body: JSON.stringify({ version: this.releaseVersion })
		})
	}

	uploadFiles(files) {
		return Promise.all(files.map(this.uploadFile.bind(this)))
	}

	uploadFile({ path, name }) {
		return request({
			url: `${this.sentryReleaseUrl()}/${this.releaseVersion}/files/`,
			method: 'POST',
			auth: {
				bearer: this.apiKey
			},
			formData: {
				file: fs.createReadStream(path),
				name: this.filenameTransform(name)
			}
		})
	}

	sentryReleaseUrl() {
		return `${this.baseSentryURL}/${this.organisationSlug}/${this.projectSlug}/releases`
	}
}
<|endoftext|>


<commit_before>function node(head) {
    return {
        parse: token => {
            return {
                head: head,
                args: [token.value],
                line: token.line
            };
        }
    }
}

let prefixes = {
    name: node('name') ,
    number: node('number'),
    string: node('string') ,
    newline: {
        parse: token => {}
    }
};

let infixes = {
    leftParen: {
        parse: (tokens, left, token) => {
            let args = [];
            while (true) {
                let next = tokens.shift();
                if (!next) {
                    throw 'expected: , or )';
                }
                if (next.type == 'rightParen') {
                    return {head: left.args[0], meta: left, args: args};
                }
                if ('comma' != next.type) {
                    args.push(prefixes[next.type].parse(next));
                }
           }
        }
    }
};

function parseX(tokens) {
    let token = tokens.shift(),
        prefix = prefixes[token.type];
    if (!prefix) {
        throw 'line ' + token.line + ': could not parse "' + token.value + '"';
    }
    let left = prefix.parse(token);
    token = tokens[0] || {};
    let infix = infixes[token.type];
    if (!infix) {
         return left;
    }
    tokens.shift();
    return infix.parse(tokens, left, token);
}

export default function parse(tokens) {
    let ast = [];
    while (tokens.length > 0) {
        let token = parseX(tokens);
        if (token) {
            ast.push(token);
        }
    }
    return ast;
}
<commit_msg>simplified node<commit_after>function node(head) {
    return {
        parse: token => {
            return {
                head: head,
                args: [token.value],
                line: token.line
            };
        }
    }
}

let prefixes = {
    name: node('name'),
    number: node('number'),
    string: node('string') ,
    newline: {
        parse: token => {}
    }
};

let infixes = {
    leftParen: {
        parse: (tokens, left, token) => {
            let args = [];
            while (true) {
                let next = tokens.shift();
                if (!next) {
                    throw 'expected: , or )';
                }
                if (next.type == 'rightParen') {
                    return {head: left.args[0], meta: left, args: args};
                }
                if ('comma' != next.type) {
                    args.push(prefixes[next.type].parse(next));
                }
           }
        }
    }
};

function parseX(tokens) {
    let token = tokens.shift(),
        prefix = prefixes[token.type];
    if (!prefix) {
        throw 'line ' + token.line + ': could not parse "' + token.value + '"';
    }
    let left = prefix.parse(token);
    token = tokens[0] || {};
    let infix = infixes[token.type];
    if (!infix) {
         return left;
    }
    tokens.shift();
    return infix.parse(tokens, left, token);
}

export default function parse(tokens) {
    let ast = [];
    while (tokens.length > 0) {
        let token = parseX(tokens);
        if (token) {
            ast.push(token);
        }
    }
    return ast;
}
<|endoftext|>


<commit_before>/**
* Handles connecting and communicating with our API's,
* this module wraps our Socket so we can replace it if
* needs be.
**/

/**
* Get our modules
**/
const pkg           = require('../package.json');
const fs            = require('fs');
const Constants     = require('./constants');
const args          = require('./utils/args');
const Log           = require('./utils/log');
const api           = require('./api');
const _             = require('lodash');
const S             = require('string');

/**
*
**/
Config = {

  data: {}

};

/**
* Returns the token if any
**/
Config.getLang = function() { return require('../lang/en.json'); };

/**
* sets the token
**/
Config.setToken = function(token) {

  // returns the token or null
  this.data = _.extend(this.data, {

    token: token

  });

};

/**
* Returns the given config file
**/
Config.getFile = function() {

  // check if a custom config file was given
  if(S(args.config).isEmpty() === false) {

    // return the file
    return args.config;

  } else {

    // return the default
    return Constants.CONFIG_FILE;

  }

};

/**
* Returns the token if any
**/
Config.getToken = function() {

  // returns the token or null
  return (this.data || {}).token || null;

};

/**
* Creates the initial config file
**/
Config.init = function(fn) {

  // report install
  api.track({

    key:      'setup',
    message:  'First run of the Passmarked CLI'

  }, function() {

    // debugging
    Log.debug('Init config file from ' + Config.getFile());

    // set to the initial state
    this.data = Constants.BASIC_CONFIG;

    /**
    * write to the file
    **/
    fs.writeFile(

      Config.getFile(),
      JSON.stringify(Constants.BASIC_CONFIG),
      fn

    );

  });

};

/**
* Saves the config to the passmarked config file
**/
Config.save = function(fn) {

  // debugging
  Log.debug('Saving config file to ' + Config.getFile());

  /**
  * write to the file
  **/
  fs.writeFile(

    Config.getFile(),
    JSON.stringify(_.extend(

      {},
      Constants.BASIC_CONFIG,
      this.data

    )),
    fn

  );

};

/**
* Builds up the config from the config file on
* the users system if present
**/
Config.build = function(fn) {

  // debugging
  Log.debug('Reading config file from ' + Config.getFile());

  // get the
  fs.stat(Config.getFile(), function(err, stats) {

    // does the file exist ?
    if(stats && stats.isFile()) {

      // read in the file
      return fs.readFile(Config.getFile(), function(err, data){

        // check for a error
        if(err) {

          // output the error
          Log.error('Something went wrong while reading the config file', err);

          // return
          return fn(err);

        }

        // debugging
        Log.debug('Loaded config from ' + Config.getFile() + '\n' + data.toString());

        // set the config from the file
        Config.data = JSON.parse(data.toString());

        // done
        fn(null);

      });

    }

    // else create the file
    Config.init(fn);

  });

};

/**
* Returns the current version
**/
Config.getVersion = function() { return pkg.version; };

/**
* Expose the Config
**/
module.exports = exports = Config;
<commit_msg>Updated to allow token to be passed as environment variable<commit_after>/**
* Handles connecting and communicating with our API's,
* this module wraps our Socket so we can replace it if
* needs be.
**/

/**
* Get our modules
**/
const pkg           = require('../package.json');
const fs            = require('fs');
const Constants     = require('./constants');
const args          = require('./utils/args');
const Log           = require('./utils/log');
const api           = require('./api');
const _             = require('lodash');
const S             = require('string');

/**
*
**/
Config = {

  data: {}

};

/**
* Returns the token if any
**/
Config.getLang = function() { return require('../lang/en.json'); };

/**
* sets the token
**/
Config.setToken = function(token) {

  // returns the token or null
  this.data = _.extend(this.data, {

    token: token

  });

};

/**
* Returns the given config file
**/
Config.getFile = function() {

  // check if a custom config file was given
  if(S(args.config).isEmpty() === false) {

    // return the file
    return args.config;

  } else {

    // return the default
    return Constants.CONFIG_FILE;

  }

};

/**
* Returns the token if any
**/
Config.getToken = function() {

  // returns the token or null
  return process.env.PM_TOKEN || (this.data || {}).token || null;

};

/**
* Creates the initial config file
**/
Config.init = function(fn) {

  // report install
  api.track({

    key:      'setup',
    message:  'First run of the Passmarked CLI'

  }, function() {

    // debugging
    Log.debug('Init config file from ' + Config.getFile());

    // set to the initial state
    this.data = Constants.BASIC_CONFIG;

    /**
    * write to the file
    **/
    fs.writeFile(

      Config.getFile(),
      JSON.stringify(Constants.BASIC_CONFIG),
      fn

    );

  });

};

/**
* Saves the config to the passmarked config file
**/
Config.save = function(fn) {

  // debugging
  Log.debug('Saving config file to ' + Config.getFile());

  /**
  * write to the file
  **/
  fs.writeFile(

    Config.getFile(),
    JSON.stringify(_.extend(

      {},
      Constants.BASIC_CONFIG,
      this.data

    )),
    fn

  );

};

/**
* Builds up the config from the config file on
* the users system if present
**/
Config.build = function(fn) {

  // debugging
  Log.debug('Reading config file from ' + Config.getFile());

  // get the
  fs.stat(Config.getFile(), function(err, stats) {

    // does the file exist ?
    if(stats && stats.isFile()) {

      // read in the file
      return fs.readFile(Config.getFile(), function(err, data){

        // check for a error
        if(err) {

          // output the error
          Log.error('Something went wrong while reading the config file', err);

          // return
          return fn(err);

        }

        // debugging
        Log.debug('Loaded config from ' + Config.getFile() + '\n' + data.toString());

        // set the config from the file
        Config.data = JSON.parse(data.toString());

        // done
        fn(null);

      });

    }

    // else create the file
    Config.init(fn);

  });

};

/**
* Returns the current version
**/
Config.getVersion = function() { return pkg.version; };

/**
* Expose the Config
**/
module.exports = exports = Config;
<|endoftext|>