<commit_before>var _ = require('lodash');
var async = require('async');
var chalk = require('chalk');
var fs = require('fs-extra');
var mutil = require('miaow-util');
var path = require('path');
var Q = require('q');
var temp = require('temp');
var url = require('url');

temp.track();

/**
 * 模块
 *
 * 模块是处理文件的单元,每个文件都被抽象成模块
 *
 * @param {String} srcPath 待处理的文件对象或是路径
 * @param {Object} options 配置信息
 * @param {Cache} cache 缓存组件
 * @param {Buffer} [contents] 文件内容
 * @constructor
 */
function Module(srcPath, options, cache, contents) {
  this.srcPath = mutil.relative('', srcPath);
  this.contents = contents || fs.readFileSync(path.resolve(options.cwd, srcPath));

  this.options = options;
  this.cache = cache;

  // 依赖的模块列表
  this.dependList = [];

  // 被依赖的模块列表
  this.dependedList = [];

  // 需要打包的模块列表
  this.packedModules = [];

  // 获取一些模块配置
  var moduleOptions = this.moduleOptions = {};
  _.each(['road', 'tasks'], function (name) {
    moduleOptions[name] = getModuleOption(options, 'module.' + name, srcPath);
  });

  function getModuleOption(options, path, relativeFilePath) {
    return _.find(_.result(options, path) || [], function (option) {
        return option.test.test(relativeFilePath);
      }) || {};
  }
}

Module.get = function (srcPath, options, cache, contents) {
  var module = cache.get(srcPath);
  if (!module) {
    module = new Module(srcPath, options, cache, contents);

    // 添加缓存
    cache.add(module);
  }

  return module;
};

/**
 * 执行任务
 *
 * @param cb
 */
Module.prototype.runTasks = function (cb) {
  var tasks = this.moduleOptions.tasks.plugins;

  if (tasks) {
    var module = this;
    mutil.execPlugins(this, this.moduleOptions.tasks.plugins, function (err) {
      if (err && !err.fileName) {
        err.fileName = module.srcAbsPath;
      }

      cb(err);
    });
  } else {
    cb();
  }
};

/**
 * 生成文件
 *
 * @param cb
 */
Module.prototype.dest = function (cb) {
  var module = this;

  // 默认生成不带hash的文件
  var writePathList = _.uniq([
    this.destAbsPath,
    this.destAbsPathWithHash
  ]);

  // 设置编码
  var encoding = this.charset;

  // 生成文件
  this.getContents(function (err, contents) {
    if (err) {
      return cb(err);
    }

    async.each(writePathList, function (writePath, cb) {
      mutil.dest(writePath, contents, encoding, cb);
    }, function (err) {
      if (err) {
        return cb(err);
      }

      // 将contents写入临时文件,免得在内存中占用空间
      // 删除destContents引用,节省内存占用
      try {
        var tempPath = temp.openSync().path;
        fs.writeFileSync(tempPath, module.contents);
        module.contents = tempPath;
        module.destContents = null;
      } catch (e) {
      }

      cb();
    });
  });
};

/**
 * 获取生成文件用得内容
 *
 * 首先查看destContents是否有内容,如果有内容就直接使用,因为可能是压缩任务直接读取的缓存
 * 如果destContents没有内容,就查看是否需要打包,如果需要打包就通过打包配置返回内容
 * 如果以上都没有,就返回contents
 *
 * @param cb
 * @returns {*}
 */
Module.prototype.getContents = function (cb) {
  var module = this;

  if (this.destContents) {
    return cb(null, this.destContents);
  } else if (this.packed && this.packedModules.length > 0) {
    async.mapSeries(_.uniq(this.packedModules), function (srcPath, cb) {
      var packedModule = Module.get(srcPath, module.options, module.cache);

      packedModule.compile().then(function (packedModule) {
        cb(null, packedModule.contents.toString());
      }, cb);
    }, function (err, contentsList) {
      if (err) {
        return cb(err);
      }

      contentsList = contentsList.concat(module.contents.toString());

      return cb(null, new Buffer(contentsList.join('\n')));
    });
  } else {
    return cb(null, this.contents);
  }
};

Module.prototype.getCachedContents = function (cb) {
  this.cache.getCachedContent(this.srcPath, this.hash, cb);
};

Module.prototype.getCachedContentsSync = function () {
  return this.cache.getCachedContentSync(this.srcPath, this.hash);
};

Module.prototype.compile = function () {

  if (this.__compilePromise__) {
    return this.__compilePromise__;
  }

  var module = this;

  this.__compilePromise__ = Q.Promise(function (fullfill, reject) {
    if (module.verbase) {
      mutil.log('编译开始 ' + chalk.green.underline.bold(module.srcPath));
    }

    async.eachSeries([
      'runTasks',
      'dest'
    ], function (task, cb) {
      module[task](cb);
    }, function (err) {
      if (err) {
        if (module.verbase) {
          mutil.log('编译失败 ' + chalk.red.underline.bold(module.srcPath));
        }

        return reject(err);
      }

      if (module.verbase) {
        mutil.log('编译成功 ' + chalk.green.underline.bold(module.srcPath));
      }

      fullfill(module);
    });
  });

  return this.__compilePromise__;
};

/**
 * 删除自己
 *
 * 主要是删除自己产生的文件, 并删除缓存中的信息
 */
Module.prototype.destroy = function () {
  try {
    fs.removeSync(this.destAbsPath);
    fs.removeSync(this.destAbsPathWithHash);
  } catch (e) {
  }

  // 删除依赖和被依赖关系
  var module = this;
  var cache = this.cache;
  // 删除依赖关系
  this.dependList.forEach(function (dependSrcPath) {
    var dependModule = cache.get(dependSrcPath);
    dependModule && module.unDepend(dependModule);
  });

  // 删除被依赖关系
  this.dependedList.forEach(function (dependedSrcPath) {
    var dependedModule = cache.get(dependedSrcPath);
    dependedModule && dependedModule.unDepend(module);
  });

  this.contents = null;
  this.destContents = null;

  this.cache.remove(this.srcPath);
};

/**
 * 获取对应路径的已编译好的模块
 *
 * @param {String} relative 相对路径
 * @param {Function} cb
 */
Module.prototype.getModule = function (relative, cb) {
  var resolve = {};
  var basedir = path.dirname(this.srcAbsPath);
  if (_.isObject(relative)) {
    resolve = relative.resolve;
    basedir = relative.basedir || basedir;
    relative = relative.relative;
  }

  var srcPath;
  try {
    srcPath = mutil.resolve(
      relative,
      basedir,
      _.extend({}, this.options.resolve, resolve)
    );
  } catch (err) {
    return cb(err);
  }

  srcPath = mutil.relative(this.options.cwd, srcPath);

  var cycleError;
  if ((cycleError = this.checkCycleDepend(srcPath))) {
    return cb(cycleError);
  }

  var module = Module.get(srcPath, this.options, this.cache);

  // 添加依赖信息
  this.depend(module);

  module.compile().then(_.partial(cb, null), cb);
};

/**
 * 创建模块
 *
 * @param {String} relativePath 相对路径
 * @param {Buffer} contents 内容
 * @param cb
 */
Module.prototype.createModule = function (relativePath, contents, cb) {
  var srcAbsPath = path.resolve(path.dirname(this.srcAbsPath), relativePath);
  var srcPath = mutil.relative(this.cwd, srcAbsPath);

  var cycleError;
  if ((cycleError = this.checkCycleDepend(srcPath))) {
    return cb(cycleError);
  }

  var module = Module.get(srcPath, this.options, this.cache, contents);

  // 添加依赖信息
  this.depend(module);

  module.compile().then(_.partial(cb, null), cb);
};

/**
 * 依赖其他模块
 *
 * @param {Module} module 被依赖的模块
 */
Module.prototype.depend = function (module) {
  if (this.dependList.indexOf(module.srcPath) === -1) {
    this.dependList.push(module.srcPath);
  }

  if (module.dependedList.indexOf(this.srcPath) === -1) {
    module.dependedList.push(this.srcPath);
  }
};

Module.prototype.unDepend = function (module) {
  this.dependList = _.remove(this.dependList, module.srcPath);
  module.dependedList = _.remove(module.dependedList, this.srcPath);
};

Module.prototype.checkCycleDepend = function (srcPath) {
  // 如果出现循环依赖
  var cache = this.cache;

  function check(module, srcPath) {
    if (module.srcPath === srcPath) {
      return [module.srcPath];
    }

    var cycledList = [];
    module.dependedList.some(function (depend) {
      cycledList = check(cache.get(depend), srcPath);

      if (cycledList && cycledList.length) {
        cycledList.push(module.srcPath);
        return true;
      }
    });

    return cycledList;
  }

  var cycledList = check(this, srcPath);

  if (cycledList.length) {
    cycledList.push(srcPath);
    return new Error(srcPath + '被循环依赖了, 依赖链为: ' + cycledList.join(' <- '));
  }
};

// 生成目标的相对路径
Object.defineProperty(Module.prototype, 'destPath', {
  get: function () {
    var roadConfig = this.moduleOptions.road;
    var destPath = this.srcPath;

    // 判断是否修改生成文件的相对路径
    if (roadConfig.release) {
      destPath = destPath.replace(roadConfig.test, roadConfig.release);
    }

    return destPath;
  }
});

// 生成目标的相对路径并且应用了hash版本号
Object.defineProperty(Module.prototype, 'destPathWithHash', {
  get: function () {
    var destPathWithHash = this.destPath;

    if (this.useHash) {
      var hash = this.hash.slice(0, this.options.hash);
      var hashConcat = this.options.hashConcat;
      destPathWithHash = destPathWithHash.replace(/\.[^\.]+$/, function (ext) {
        return hashConcat + hash + ext;
      });
    }

    return destPathWithHash;
  }
});

// 文件内容
Object.defineProperty(Module.prototype, 'contents', {
  get: function () {
    if (_.isString(this.__contents__)) {
      return fs.readFileSync(this.__contents__);
    } else {
      return this.__contents__;
    }
  },

  set: function (contents) {
    this.__contents__ = contents;
  }
});

// 生成目标的绝对路径
Object.defineProperty(Module.prototype, 'destAbsPath', {
  get: function () {
    return path.join(this.output, this.destPath);
  }
});

// 生成目标的绝对路径
Object.defineProperty(Module.prototype, 'destAbsPathWithHash', {
  get: function () {
    return path.join(this.output, this.destPathWithHash);
  }
});

// 源目录的相对路径
Object.defineProperty(Module.prototype, 'srcPath', {
  writable: true,
  value: null
});

// 源目录的绝对路径
Object.defineProperty(Module.prototype, 'srcAbsPath', {
  get: function () {
    return path.join(this.cwd, this.srcPath);
  }
});

// 是否启用hash
Object.defineProperty(Module.prototype, 'useHash', {
  get: function () {
    var roadConfig = this.moduleOptions.road;
    return this.options.hash && (_.isUndefined(roadConfig.useHash) || roadConfig.useHash);
  }
});

// hash值,最好是在parse修改完内容后获取
Object.defineProperty(Module.prototype, 'hash', {
  get: function () {
    this._hash = this._hash || mutil.hash(this.contents);
    return this._hash;
  },
  set: function (hash) {
    this._hash = hash;
  }
});

Object.defineProperty(Module.prototype, 'url', {
  get: function () {
    var domain = this.moduleOptions.road.domain || this.options.domain;

    if (domain) {
      domain = /\/$/.test(domain) ? domain : (domain + '/');
      return url.resolve(domain, this.destPathWithHash);
    } else {
      return null;
    }
  }
});

Object.defineProperty(Module.prototype, 'urlWithoutHash', {
  get: function () {
    var domain = this.moduleOptions.road.domain || this.options.domain;

    if (domain) {
      domain = /\/$/.test(domain) ? domain : (domain + '/');
      return url.resolve(domain, this.destPath);
    } else {
      return null;
    }
  }
});

Object.defineProperty(Module.prototype, 'charset', {
  get: function () {
    return this.moduleOptions.road.encoding || 'utf8';
  }
});

Object.defineProperty(Module.prototype, 'cwd', {
  get: function () {
    return this.options.cwd;
  }
});

Object.defineProperty(Module.prototype, 'output', {
  get: function () {
    return path.resolve(this.options.output);
  }
});

Object.defineProperty(Module.prototype, 'liveReloadPort', {
  get: function () {
    return this.options.liveReloadPort;
  }
});

// 是否打包了
Object.defineProperty(Module.prototype, 'packed', {
  writable: true,
  value: false
});

// 最终要产出的内容
Object.defineProperty(Module.prototype, 'destContents', {
  writable: true,
  value: null
});

// 话唠模式
Object.defineProperty(Module.prototype, 'verbase', {
  get: function () {
    return this.options.verbase;
  },
  set: function (verbase) {
    this.options.verbase = verbase;
  }
});

module.exports = Module;
<commit_msg>设置任务执行的超时时间为半分钟<commit_after>var _ = require('lodash');
var async = require('async');
var chalk = require('chalk');
var fs = require('fs-extra');
var mutil = require('miaow-util');
var path = require('path');
var Q = require('q');
var temp = require('temp');
var url = require('url');

temp.track();

/**
 * 模块
 *
 * 模块是处理文件的单元,每个文件都被抽象成模块
 *
 * @param {String} srcPath 待处理的文件对象或是路径
 * @param {Object} options 配置信息
 * @param {Cache} cache 缓存组件
 * @param {Buffer} [contents] 文件内容
 * @constructor
 */
function Module(srcPath, options, cache, contents) {
  this.srcPath = mutil.relative('', srcPath);
  this.contents = contents || fs.readFileSync(path.resolve(options.cwd, srcPath));

  this.options = options;
  this.cache = cache;

  // 依赖的模块列表
  this.dependList = [];

  // 被依赖的模块列表
  this.dependedList = [];

  // 需要打包的模块列表
  this.packedModules = [];

  // 获取一些模块配置
  var moduleOptions = this.moduleOptions = {};
  _.each(['road', 'tasks'], function (name) {
    moduleOptions[name] = getModuleOption(options, 'module.' + name, srcPath);
  });

  function getModuleOption(options, path, relativeFilePath) {
    return _.find(_.result(options, path) || [], function (option) {
        return option.test.test(relativeFilePath);
      }) || {};
  }
}

Module.get = function (srcPath, options, cache, contents) {
  var module = cache.get(srcPath);
  if (!module) {
    module = new Module(srcPath, options, cache, contents);

    // 添加缓存
    cache.add(module);
  }

  return module;
};

/**
 * 执行任务
 *
 * @param cb
 */
Module.prototype.runTasks = function (cb) {
  var tasks = this.moduleOptions.tasks.plugins;

  if (tasks) {
    var module = this;
    mutil.execPlugins(
      this,
      tasks,
      {timeout: 30e3},
      function (err) {
        if (err && !err.fileName) {
          err.fileName = module.srcAbsPath;
        }

        cb(err);
      }
    );
  } else {
    cb();
  }
};

/**
 * 生成文件
 *
 * @param cb
 */
Module.prototype.dest = function (cb) {
  var module = this;

  // 默认生成不带hash的文件
  var writePathList = _.uniq([
    this.destAbsPath,
    this.destAbsPathWithHash
  ]);

  // 设置编码
  var encoding = this.charset;

  // 生成文件
  this.getContents(function (err, contents) {
    if (err) {
      return cb(err);
    }

    async.each(writePathList, function (writePath, cb) {
      mutil.dest(writePath, contents, encoding, cb);
    }, function (err) {
      if (err) {
        return cb(err);
      }

      // 将contents写入临时文件,免得在内存中占用空间
      // 删除destContents引用,节省内存占用
      try {
        var tempPath = temp.openSync().path;
        fs.writeFileSync(tempPath, module.contents);
        module.contents = tempPath;
        module.destContents = null;
      } catch (e) {
      }

      cb();
    });
  });
};

/**
 * 获取生成文件用得内容
 *
 * 首先查看destContents是否有内容,如果有内容就直接使用,因为可能是压缩任务直接读取的缓存
 * 如果destContents没有内容,就查看是否需要打包,如果需要打包就通过打包配置返回内容
 * 如果以上都没有,就返回contents
 *
 * @param cb
 * @returns {*}
 */
Module.prototype.getContents = function (cb) {
  var module = this;

  if (this.destContents) {
    return cb(null, this.destContents);
  } else if (this.packed && this.packedModules.length > 0) {
    async.mapSeries(_.uniq(this.packedModules), function (srcPath, cb) {
      var packedModule = Module.get(srcPath, module.options, module.cache);

      packedModule.compile().then(function (packedModule) {
        cb(null, packedModule.contents.toString());
      }, cb);
    }, function (err, contentsList) {
      if (err) {
        return cb(err);
      }

      contentsList = contentsList.concat(module.contents.toString());

      return cb(null, new Buffer(contentsList.join('\n')));
    });
  } else {
    return cb(null, this.contents);
  }
};

Module.prototype.getCachedContents = function (cb) {
  this.cache.getCachedContent(this.srcPath, this.hash, cb);
};

Module.prototype.getCachedContentsSync = function () {
  return this.cache.getCachedContentSync(this.srcPath, this.hash);
};

Module.prototype.compile = function () {

  if (this.__compilePromise__) {
    return this.__compilePromise__;
  }

  var module = this;

  this.__compilePromise__ = Q.Promise(function (fullfill, reject) {
    if (module.verbase) {
      mutil.log('编译开始 ' + chalk.green.underline.bold(module.srcPath));
    }

    async.eachSeries([
      'runTasks',
      'dest'
    ], function (task, cb) {
      module[task](cb);
    }, function (err) {
      if (err) {
        if (module.verbase) {
          mutil.log('编译失败 ' + chalk.red.underline.bold(module.srcPath));
        }

        return reject(err);
      }

      if (module.verbase) {
        mutil.log('编译成功 ' + chalk.green.underline.bold(module.srcPath));
      }

      fullfill(module);
    });
  });

  return this.__compilePromise__;
};

/**
 * 删除自己
 *
 * 主要是删除自己产生的文件, 并删除缓存中的信息
 */
Module.prototype.destroy = function () {
  try {
    fs.removeSync(this.destAbsPath);
    fs.removeSync(this.destAbsPathWithHash);
  } catch (e) {
  }

  // 删除依赖和被依赖关系
  var module = this;
  var cache = this.cache;
  // 删除依赖关系
  this.dependList.forEach(function (dependSrcPath) {
    var dependModule = cache.get(dependSrcPath);
    dependModule && module.unDepend(dependModule);
  });

  // 删除被依赖关系
  this.dependedList.forEach(function (dependedSrcPath) {
    var dependedModule = cache.get(dependedSrcPath);
    dependedModule && dependedModule.unDepend(module);
  });

  this.contents = null;
  this.destContents = null;

  this.cache.remove(this.srcPath);
};

/**
 * 获取对应路径的已编译好的模块
 *
 * @param {String} relative 相对路径
 * @param {Function} cb
 */
Module.prototype.getModule = function (relative, cb) {
  var resolve = {};
  var basedir = path.dirname(this.srcAbsPath);
  if (_.isObject(relative)) {
    resolve = relative.resolve;
    basedir = relative.basedir || basedir;
    relative = relative.relative;
  }

  var srcPath;
  try {
    srcPath = mutil.resolve(
      relative,
      basedir,
      _.extend({}, this.options.resolve, resolve)
    );
  } catch (err) {
    return cb(err);
  }

  srcPath = mutil.relative(this.options.cwd, srcPath);

  var cycleError;
  if ((cycleError = this.checkCycleDepend(srcPath))) {
    return cb(cycleError);
  }

  var module = Module.get(srcPath, this.options, this.cache);

  // 添加依赖信息
  this.depend(module);

  module.compile().then(_.partial(cb, null), cb);
};

/**
 * 创建模块
 *
 * @param {String} relativePath 相对路径
 * @param {Buffer} contents 内容
 * @param cb
 */
Module.prototype.createModule = function (relativePath, contents, cb) {
  var srcAbsPath = path.resolve(path.dirname(this.srcAbsPath), relativePath);
  var srcPath = mutil.relative(this.cwd, srcAbsPath);

  var cycleError;
  if ((cycleError = this.checkCycleDepend(srcPath))) {
    return cb(cycleError);
  }

  var module = Module.get(srcPath, this.options, this.cache, contents);

  // 添加依赖信息
  this.depend(module);

  module.compile().then(_.partial(cb, null), cb);
};

/**
 * 依赖其他模块
 *
 * @param {Module} module 被依赖的模块
 */
Module.prototype.depend = function (module) {
  if (this.dependList.indexOf(module.srcPath) === -1) {
    this.dependList.push(module.srcPath);
  }

  if (module.dependedList.indexOf(this.srcPath) === -1) {
    module.dependedList.push(this.srcPath);
  }
};

Module.prototype.unDepend = function (module) {
  this.dependList = _.remove(this.dependList, module.srcPath);
  module.dependedList = _.remove(module.dependedList, this.srcPath);
};

Module.prototype.checkCycleDepend = function (srcPath) {
  // 如果出现循环依赖
  var cache = this.cache;

  function check(module, srcPath) {
    if (module.srcPath === srcPath) {
      return [module.srcPath];
    }

    var cycledList = [];
    module.dependedList.some(function (depend) {
      cycledList = check(cache.get(depend), srcPath);

      if (cycledList && cycledList.length) {
        cycledList.push(module.srcPath);
        return true;
      }
    });

    return cycledList;
  }

  var cycledList = check(this, srcPath);

  if (cycledList.length) {
    cycledList.push(srcPath);
    return new Error(srcPath + '被循环依赖了, 依赖链为: ' + cycledList.join(' <- '));
  }
};

// 生成目标的相对路径
Object.defineProperty(Module.prototype, 'destPath', {
  get: function () {
    var roadConfig = this.moduleOptions.road;
    var destPath = this.srcPath;

    // 判断是否修改生成文件的相对路径
    if (roadConfig.release) {
      destPath = destPath.replace(roadConfig.test, roadConfig.release);
    }

    return destPath;
  }
});

// 生成目标的相对路径并且应用了hash版本号
Object.defineProperty(Module.prototype, 'destPathWithHash', {
  get: function () {
    var destPathWithHash = this.destPath;

    if (this.useHash) {
      var hash = this.hash.slice(0, this.options.hash);
      var hashConcat = this.options.hashConcat;
      destPathWithHash = destPathWithHash.replace(/\.[^\.]+$/, function (ext) {
        return hashConcat + hash + ext;
      });
    }

    return destPathWithHash;
  }
});

// 文件内容
Object.defineProperty(Module.prototype, 'contents', {
  get: function () {
    if (_.isString(this.__contents__)) {
      return fs.readFileSync(this.__contents__);
    } else {
      return this.__contents__;
    }
  },

  set: function (contents) {
    this.__contents__ = contents;
  }
});

// 生成目标的绝对路径
Object.defineProperty(Module.prototype, 'destAbsPath', {
  get: function () {
    return path.join(this.output, this.destPath);
  }
});

// 生成目标的绝对路径
Object.defineProperty(Module.prototype, 'destAbsPathWithHash', {
  get: function () {
    return path.join(this.output, this.destPathWithHash);
  }
});

// 源目录的相对路径
Object.defineProperty(Module.prototype, 'srcPath', {
  writable: true,
  value: null
});

// 源目录的绝对路径
Object.defineProperty(Module.prototype, 'srcAbsPath', {
  get: function () {
    return path.join(this.cwd, this.srcPath);
  }
});

// 是否启用hash
Object.defineProperty(Module.prototype, 'useHash', {
  get: function () {
    var roadConfig = this.moduleOptions.road;
    return this.options.hash && (_.isUndefined(roadConfig.useHash) || roadConfig.useHash);
  }
});

// hash值,最好是在parse修改完内容后获取
Object.defineProperty(Module.prototype, 'hash', {
  get: function () {
    this._hash = this._hash || mutil.hash(this.contents);
    return this._hash;
  },
  set: function (hash) {
    this._hash = hash;
  }
});

Object.defineProperty(Module.prototype, 'url', {
  get: function () {
    var domain = this.moduleOptions.road.domain || this.options.domain;

    if (domain) {
      domain = /\/$/.test(domain) ? domain : (domain + '/');
      return url.resolve(domain, this.destPathWithHash);
    } else {
      return null;
    }
  }
});

Object.defineProperty(Module.prototype, 'urlWithoutHash', {
  get: function () {
    var domain = this.moduleOptions.road.domain || this.options.domain;

    if (domain) {
      domain = /\/$/.test(domain) ? domain : (domain + '/');
      return url.resolve(domain, this.destPath);
    } else {
      return null;
    }
  }
});

Object.defineProperty(Module.prototype, 'charset', {
  get: function () {
    return this.moduleOptions.road.encoding || 'utf8';
  }
});

Object.defineProperty(Module.prototype, 'cwd', {
  get: function () {
    return this.options.cwd;
  }
});

Object.defineProperty(Module.prototype, 'output', {
  get: function () {
    return path.resolve(this.options.output);
  }
});

Object.defineProperty(Module.prototype, 'liveReloadPort', {
  get: function () {
    return this.options.liveReloadPort;
  }
});

// 是否打包了
Object.defineProperty(Module.prototype, 'packed', {
  writable: true,
  value: false
});

// 最终要产出的内容
Object.defineProperty(Module.prototype, 'destContents', {
  writable: true,
  value: null
});

// 话唠模式
Object.defineProperty(Module.prototype, 'verbase', {
  get: function () {
    return this.options.verbase;
  },
  set: function (verbase) {
    this.options.verbase = verbase;
  }
});

module.exports = Module;
<|endoftext|>


<commit_before>'use strict';

(function() {
  angular.module('ncsaas')
    .controller('ResourceListController', ['resourcesService', ResourceListController]);

  function ResourceListController(resourcesService) {
    var vm = this;

    vm.list = {};

    // resource operations
    vm.stopResource = stopResource;
    vm.startResource = startResource;
    vm.restartResource = restartResource;
    vm.deleteResource = deleteResource;
    vm.isOperationAvailable = isOperationAvailable;

    // search
    vm.searchInput = '';
    vm.search = search;

    // pagination
    vm.changePageSize = changePageSize;
    vm.changePage = changePage;
    vm.getNumber = getNumber;
    vm.pageSizes = [1,5,10,15,20];
    vm.currentPageSize = resourcesService.pageSize;
    vm.pages = resourcesService.pages ? resourcesService.pages : 5;
    vm.currentPage = resourcesService.page;

    getResourceList();

    function getResourceList() {
      resourcesService.getResourcesList().then(function(response) {
        vm.pages = resourcesService.pages;
        vm.list = response;
      });
    }

    resourcesService.getResourcesList().then(function(response) {
      vm.list = response;
    });

    function stopResource(uuid) {
      resourcesService.stopResource(uuid);
    }

    function startResource(uuid) {
      resourcesService.startResource(uuid);
    }

    function restartResource(uuid) {
      resourcesService.restartResource(uuid);
    }

    function deleteResource(uuid, index) {
      var confirmDelete = confirm('Confirm resource deletion?');
      if (confirmDelete) {
        resourcesService.deleteResource(uuid).then(function(response){
          vm.list.splice(index, 1);
        });
      } else {
        alert('Resource was not deleted.');
      }
    }

    function search() {
      resourcesService.getResourcesList({hostname: vm.searchInput}).then(function(response) {
        vm.list = response;
      });
    }

    function changePageSize(pageSize) {
      vm.currentPageSize = pageSize;
      vm.currentPage = 1;
      resourcesService.page = 1;
      resourcesService.pageSize = pageSize;
      getResourceList();
    }

    function changePage(page) {
      vm.currentPage = page;
      resourcesService.page = page;
      getResourceList();
    }

    function getNumber(num) {
      return new Array(num);
    }

    function isOperationAvailable(resource, operation) {
      var availableOperations = resourcesService.getAvailableOperations(resource);
      operation = operation.toLowerCase();
      return availableOperations.indexOf(operation) !== -1;
    }

  }

})();

(function() {
  angular.module('ncsaas')
    .controller('ResourceAddController',
      ['$state', 'resourcesService', 'servicesService', 'projectsService', 'keysService', 'templatesService',
      ResourceAddController]);

  function ResourceAddController(
      $state, resourcesService, servicesService, projectsService, keysService, templatesService) {
    var vm = this;

    // Resource add process:
    // 0. User has to choose back-end. Currently this step is not active because we have only one back-end.
    // 1. User has to choose project. Method setProject has to be called, because services are initiated based on
    // projects
    // 2. User has to choose service. Method setService has to be called, because flavors and templates are initialized
    // based on services
    // 3. User has to choose flavor, template, ssh key and other resource attributes.

    vm.showFlavors = false;
    vm.showTemplates = false;

    vm.serviceList = {};
    vm.flavorList = {};
    vm.keyList = {};
    vm.projectList = {};
    vm.templateList = {};
    vm.setService = setService;
    vm.setTemplate = setTemplate;
    vm.setFlavor = setFlavor;
    vm.setProject = setProject;
    vm.resource = resourcesService.createResource();
    vm.save = save;
    vm.cancel = cancel;
    vm.errors = {};
    vm.selectedProject = null;

    function activate() {
      // projects
      projectsService.getProjectList().then(function(response) {
        vm.projectList = response;
      });
      // keys
      keysService.getCurrentUserKeyList().then(function(response) {
        vm.keyList = response;
      });
    }

    function setService(service) {
      vm.flavorList = service.flavors;
      templatesService.getTemplateList(service.uuid).then(function(response) {
        vm.templateList = response;
      });
      vm.selectedService = service;
      vm.showTemplates = true;
    }

    function setTemplate(tamplate) {
      vm.resource.template = tamplate.url;
      vm.selectedTemplate = tamplate;
      vm.showFlavors = true;
    }

    function setFlavor(flavor) {
      vm.resource.flavor = flavor.url;
      vm.selectedFlavor = flavor;
    }

    function setProject(project) {
      vm.resource.project = project.url;
      // services
      servicesService.getServiceList({project: project.uuid}).then(function(response) {
        vm.serviceList = response;
      });
    }

    function save() {
      vm.resource.$save(success, error);

      function success(response) {
        $state.go('resources');
      }

      function error(response) {
        vm.errors = response.data;
      }
    }

    function cancel() {
      $state.go('resources');
    }

    activate();

  }
})();
<commit_msg>Change pagination size (saas-166)<commit_after>'use strict';

(function() {
  angular.module('ncsaas')
    .controller('ResourceListController', ['resourcesService', ResourceListController]);

  function ResourceListController(resourcesService) {
    var vm = this;

    vm.list = {};

    // resource operations
    vm.stopResource = stopResource;
    vm.startResource = startResource;
    vm.restartResource = restartResource;
    vm.deleteResource = deleteResource;
    vm.isOperationAvailable = isOperationAvailable;

    // search
    vm.searchInput = '';
    vm.search = search;

    // pagination
    vm.changePageSize = changePageSize;
    vm.changePage = changePage;
    vm.getNumber = getNumber;
    vm.pageSizes = [5, 10, 20, 50];
    vm.currentPageSize = resourcesService.pageSize;
    vm.pages = resourcesService.pages ? resourcesService.pages : 5;
    vm.currentPage = resourcesService.page;

    getResourceList();

    function getResourceList() {
      resourcesService.getResourcesList().then(function(response) {
        vm.pages = resourcesService.pages;
        vm.list = response;
      });
    }

    resourcesService.getResourcesList().then(function(response) {
      vm.list = response;
    });

    function stopResource(uuid) {
      resourcesService.stopResource(uuid);
    }

    function startResource(uuid) {
      resourcesService.startResource(uuid);
    }

    function restartResource(uuid) {
      resourcesService.restartResource(uuid);
    }

    function deleteResource(uuid, index) {
      var confirmDelete = confirm('Confirm resource deletion?');
      if (confirmDelete) {
        resourcesService.deleteResource(uuid).then(function(response){
          vm.list.splice(index, 1);
        });
      } else {
        alert('Resource was not deleted.');
      }
    }

    function search() {
      resourcesService.getResourcesList({hostname: vm.searchInput}).then(function(response) {
        vm.list = response;
      });
    }

    function changePageSize(pageSize) {
      vm.currentPageSize = pageSize;
      vm.currentPage = 1;
      resourcesService.page = 1;
      resourcesService.pageSize = pageSize;
      getResourceList();
    }

    function changePage(page) {
      vm.currentPage = page;
      resourcesService.page = page;
      getResourceList();
    }

    function getNumber(num) {
      return new Array(num);
    }

    function isOperationAvailable(resource, operation) {
      var availableOperations = resourcesService.getAvailableOperations(resource);
      operation = operation.toLowerCase();
      return availableOperations.indexOf(operation) !== -1;
    }

  }

})();

(function() {
  angular.module('ncsaas')
    .controller('ResourceAddController',
      ['$state', 'resourcesService', 'servicesService', 'projectsService', 'keysService', 'templatesService',
      ResourceAddController]);

  function ResourceAddController(
      $state, resourcesService, servicesService, projectsService, keysService, templatesService) {
    var vm = this;

    // Resource add process:
    // 0. User has to choose back-end. Currently this step is not active because we have only one back-end.
    // 1. User has to choose project. Method setProject has to be called, because services are initiated based on
    // projects
    // 2. User has to choose service. Method setService has to be called, because flavors and templates are initialized
    // based on services
    // 3. User has to choose flavor, template, ssh key and other resource attributes.

    vm.showFlavors = false;
    vm.showTemplates = false;

    vm.serviceList = {};
    vm.flavorList = {};
    vm.keyList = {};
    vm.projectList = {};
    vm.templateList = {};
    vm.setService = setService;
    vm.setTemplate = setTemplate;
    vm.setFlavor = setFlavor;
    vm.setProject = setProject;
    vm.resource = resourcesService.createResource();
    vm.save = save;
    vm.cancel = cancel;
    vm.errors = {};
    vm.selectedProject = null;

    function activate() {
      // projects
      projectsService.getProjectList().then(function(response) {
        vm.projectList = response;
      });
      // keys
      keysService.getCurrentUserKeyList().then(function(response) {
        vm.keyList = response;
      });
    }

    function setService(service) {
      vm.flavorList = service.flavors;
      templatesService.getTemplateList(service.uuid).then(function(response) {
        vm.templateList = response;
      });
      vm.selectedService = service;
      vm.showTemplates = true;
    }

    function setTemplate(tamplate) {
      vm.resource.template = tamplate.url;
      vm.selectedTemplate = tamplate;
      vm.showFlavors = true;
    }

    function setFlavor(flavor) {
      vm.resource.flavor = flavor.url;
      vm.selectedFlavor = flavor;
    }

    function setProject(project) {
      vm.resource.project = project.url;
      // services
      servicesService.getServiceList({project: project.uuid}).then(function(response) {
        vm.serviceList = response;
      });
    }

    function save() {
      vm.resource.$save(success, error);

      function success(response) {
        $state.go('resources');
      }

      function error(response) {
        vm.errors = response.data;
      }
    }

    function cancel() {
      $state.go('resources');
    }

    activate();

  }
})();
<|endoftext|>


<commit_before>const assert = require('assert'),
      Roast = require('../build/roast')

describe('Roast', () => {

  it('works', () => {
    const Repo = Roast.createRepo({
      users: {
        id: {type: Roast.integer, null: false, default: Roast.autoIncrement},
        firstName: {type: Roast.string, null: false},
        lastName: {type: Roast.string},
        age: {type: Roast.integer, default: 0}
      },
      comments: {
        id: {type: Roast.string, null: false, default: Roast.uuid},
        body: {type: Roast.string, null: false},
        user_id: {type: Roast.integer, null: false}
      }
    })

    // All methods throw if the given table doesn't exist

    const tableError = /Table doesn't exist 'pages'/

    assert.throws(() => {
      Repo.all('pages')
    }, tableError)

    assert.throws(() => {
      Repo.one('pages')
    }, tableError)

    assert.throws(() => {
      Repo.get('pages')
    }, tableError)

    assert.throws(() => {
      Repo.insert('pages', {})
    }, tableError)

    assert.throws(() => {
      Repo.update('pages', 1, {})
    }, tableError)

    assert.throws(() => {
      Repo.delete('pages', 1)
    }, tableError)

    assert.deepEqual([], Repo.all('users'))

    assert.throws(() => {
      Repo.insert('users', {})
    }, /Record invalid/)

    let userA = Repo.insert('users', {firstName: 'Mitch'})
    let userB = Repo.insert('users', {firstName: 'Bob'})
    let userC = Repo.insert('users', {firstName: 'Bob', id: 5})

    // Insert works
    assert.equal(1, userA.id)
    assert.equal('Mitch', userA.firstName)
    assert.equal(0, userA.age)
    assert.equal(2, userB.id)
    assert.equal(5, userC.id)

    let commentA = Repo.insert('comments', {body: "my comment", user_id: 1})
    let commentB = Repo.insert('comments', {body: "my comment", user_id: 1})

    // Roast.uuid assigns a random UUID
    assert.equal(36, commentA.id.length)
    assert.notEqual(commentA.id, commentB.id)

    // ALL returns all records
    assert.equal(3, Repo.all('users').length)

    // ALL can filter records
    assert.equal(2, Repo.all('users', u => u.firstName == 'Bob').length)
    assert.equal(0, Repo.all('users', u => u.firstName == 'John').length)

    // ONE throws if there is not exactly 1 result
    assert.throws(() => {
      Repo.one('users')
    }, /Expected one, but found 3 records/)
    assert.throws(() => {
      Repo.one('users', u => u.firstName == 'Bob')
    }, /Expected one, but found 2 records/)

    // ONE allows filtering
    assert.deepEqual({age: 0, firstName: "Mitch", id: 1}, Repo.one('users', u => u.firstName == 'Mitch'))

    // GET gets a record by id
    assert.deepEqual(commentA, Repo.get('comments', commentA.id))

    // GET throws when not found
    assert.throws(() => {
      Repo.get('comments', 'not-an-id')
    }, /Record not found/)

    // UPDATE updates the given fields
    Repo.update('comments', commentA.id, {body: 'New body'})
    assert.equal('New body', Repo.get('comments', commentA.id).body)

    // UPDATE applies defaults
    Repo.update('users', userA.id, {age: null})
    assert.equal(0, Repo.get('users', userA.id).age)

    // UPDATE throws if updated record is invalid
    assert.throws(() => {
      Repo.update('users', userA.id, {age: "not an int"})
    }, /Record invalid/)

    // DELETE deletes a record by id
    Repo.delete('users', userC.id)
    assert.equal(2, Repo.all('users').length)

    // DELETE throws if the record doesn't exist
    assert.throws(() => {
      Repo.delete('users', userC.id)
    }, /Record not found/)

  })

})<commit_msg>Remove transaction related functionality.<commit_after>const assert = require('assert'),
      Roast = require('../build/roast')

describe('Roast', () => {

  it('works', () => {
    const Repo = Roast.createRepo({
      users: {
        id: {type: Roast.integer, null: false, default: Roast.autoIncrement},
        firstName: {type: Roast.string, null: false},
        lastName: {type: Roast.string},
        age: {type: Roast.integer, default: 0}
      },
      comments: {
        id: {type: Roast.string, null: false, default: Roast.uuid},
        body: {type: Roast.string, null: false},
        user_id: {type: Roast.integer, null: false}
      }
    })

    // All methods throw if the given table doesn't exist

    const tableError = /Table doesn't exist 'pages'/

    assert.throws(() => {
      Repo.all('pages')
    }, tableError)

    assert.throws(() => {
      Repo.one('pages')
    }, tableError)

    assert.throws(() => {
      Repo.get('pages')
    }, tableError)

    assert.throws(() => {
      Repo.insert('pages', {})
    }, tableError)

    assert.throws(() => {
      Repo.update('pages', 1, {})
    }, tableError)

    assert.throws(() => {
      Repo.delete('pages', 1)
    }, tableError)

    assert.deepEqual([], Repo.all('users'))

    assert.throws(() => {
      Repo.insert('users', {})
    }, /Record invalid/)

    let userA = Repo.insert('users', {firstName: 'Mitch'})
    let userB = Repo.insert('users', {firstName: 'Bob'})
    let userC = Repo.insert('users', {firstName: 'Bob', id: 5})

    // Insert works
    assert.equal(1, userA.id)
    assert.equal('Mitch', userA.firstName)
    assert.equal(0, userA.age)
    assert.equal(2, userB.id)
    assert.equal(5, userC.id)

    let commentA = Repo.insert('comments', {body: "my comment", user_id: 1})
    let commentB = Repo.insert('comments', {body: "my comment", user_id: 1})

    // Roast.uuid assigns a random UUID
    assert.equal(36, commentA.id.length)
    assert.notEqual(commentA.id, commentB.id)

    // ALL returns all records
    assert.equal(3, Repo.all('users').length)

    // ALL can filter records
    assert.equal(2, Repo.all('users', u => u.firstName == 'Bob').length)
    assert.equal(0, Repo.all('users', u => u.firstName == 'John').length)

    // ONE throws if there is not exactly 1 result
    assert.throws(() => {
      Repo.one('users')
    }, /Expected one, but found 3 records/)
    assert.throws(() => {
      Repo.one('users', u => u.firstName == 'Bob')
    }, /Expected one, but found 2 records/)

    // ONE allows filtering
    assert.deepEqual({age: 0, firstName: "Mitch", id: 1}, Repo.one('users', u => u.firstName == 'Mitch'))

    // GET gets a record by id
    assert.deepEqual(commentA, Repo.get('comments', commentA.id))

    // GET throws when not found
    assert.throws(() => {
      Repo.get('comments', 'not-an-id')
    }, /Record not found/)

    // UPDATE updates the given fields
    Repo.update('comments', commentA.id, {body: 'New body'})
    assert.equal('New body', Repo.get('comments', commentA.id).body)

    // UPDATE applies defaults
    Repo.update('users', userA.id, {age: null})
    assert.equal(0, Repo.get('users', userA.id).age)

    // UPDATE throws if updated record is invalid
    assert.throws(() => {
      Repo.update('users', userA.id, {age: "not an int"})
    }, /Record invalid/)

    // DELETE deletes a record by id
    Repo.delete('users', userC.id)
    assert.equal(2, Repo.all('users').length)

    // DELETE throws if the record doesn't exist
    assert.throws(() => {
      Repo.delete('users', userC.id)
    }, /Record not found/)

    let one = {a: 1, b: 2}
    let two = {...one}
    two.a = 5
    assert.equal(1, one.a)

  })

})<|endoftext|>


<commit_before>/**
 * Copyright (c) ActiveState 2014 - ALL RIGHTS RESERVED.
 */

'use strict';

var Config = require('../config/config-defaults');
var PackageJSON = require('../package');
var Lactate = require('lactate');
var Npm = require('npm');
var FS = require('fs');

var Optimist = require('optimist')
.usage('Usage: $0 -p <port> -a <external_dns> -c <file cache dir>')
.describe({
    server_address: 'The external DNS name this mirror should serve on',
    bind_address: 'The local interface bind address',
    cache_dir: 'The full directory path the cache directory (no trailing slash)',
    http_port: 'The HTTP port for the lazy mirror to listen on',
    config: 'The path to the JSON configuration file',
    cache_expiry: 'Expire the upstream registry cache assets on this value (ms)',
    cache_mem: 'The maxmium size in MB of registry data to keep in memory. A larger allocation reduces disk hits and improves performance',
    http_enabled: 'Enable the HTTP server on -p, this is true if neither --http_enabled or --https_enabled are supplied',
    https_enabled: 'Enable the HTTPS server on --https_port',
    https_key: 'The path to the private SSL key',
    https_cert: 'The path to the private SSL certificate',
    https_port: 'The HTTPS port (requires --https_enabled)',
    http_proxy: 'Specify a HTTP proxy to traverse before making outbound requests',
    https_proxy: 'Specify a HTTPS proxy to traverse before making outbound requests',
    package_blacklist: 'Full path to a JSON configuration file of blacklisted packages',
    permit_stale_resources: 'Continue to serve stale resources if the upstream registry cannot be contacted',
    real_external_port: 'If this mirror is behind a proxy, set this flag to the real external port for client connections',
    upstream_host: 'The upstream registry host',
    upstream_port: 'The default upstream registry port',
    upstream_db_path: 'The default upstream registry database path, default: none (requires a leading slash)',
    upstream_use_https: 'Use HTTPS only when proxying to the upstream registry',
    upstream_verify_ssl: 'Verify the upstream registry\'s SSL certificates'
})
.default({
    'server_address': 'localhost',
    'bind_address': '127.0.0.1',
    'cache_dir': '/tmp/files',
    'http_port': 2000,
    'cache_expiry': 24 * 60 * 60 * 1000, // 24 Hours
    'cache_mem': 200, // MB
    'https_port': 443,
    'upstream_host': 'registry.npmjs.org',
    'upstream_port': 80,
    'upstream_use_https': false,
    'upstream_verify_ssl': false
})
.alias({
    'server_address': 'a',
    'bind_address': 'b',
    'cache_dir': 'c',
    'http_port': 'p',
    'config': 'C'
});

var Argv = Optimist.argv,
    config = {};

/* CLI specific */
if (Argv.h) {
    console.log(Optimist.help());
    process.exit();

} else if (Argv.v) {
    console.log('npm-lazy-mirror: ' + PackageJSON.version);
    process.exit();

} else if (Argv.C || Argv.config) {
    Config = JSON.parse(FS.readFileSync((Argv.C || Argv.config)));
}

/* Local server options */
config.httpPort = Argv.p || Argv.port || Config.http_port;
config.serverAddress = Argv.a || Argv.server_address || Config.server_address;
config.bindAddress = Argv.b || Argv.bind_address || Config.bind_address;
config.httpEnabled = Argv.http_enabled || Config.http_enabled;

/* Local server HTTPS options */
config.httpsPort = Argv.https_port || Config.https_port;
config.httpsEnabled = Argv.https_enabled || Config.https_enabled;

if (!config.httpEnabled && !config.httpsEnabled) {
    config.httpEnabled = true;
}

config.realExternalPort = Argv.real_external_port || (config.httpsEnabled ? config.httpsPort : config.httpPort);

/* Logging */
config.logLevel = Argv.log_level || Config.log_level || 'info';

config.httpsKey = Argv.https_key || Config.https_key || null;
config.httpsCert = Argv.https_cert || Config.https_cert || null;

/* Upstream Registry */
config.upstreamHost = Argv.upstream_host || Config.upstream_host;
config.upstreamPort = Argv.upstream_port || Config.upstream_port;
config.upstreamUseHttps = Argv.upstream_use_https || Config.upstream_use_https;
config.upstreamVerifySSL = Argv.upstream_verify_ssl || Config.upstream_verify_ssl;
config.upstreamDBPath = Argv.upstream_db_path || Config.upstream_db_path || '';

/* Caching options */
config.cache = {};
config.cacheDir = Argv.c || Argv.cache_dir || Config.cache_dir;
config.cacheExpiry = Argv.cache_expiry || Config.cache_expiry
config.cacheMem = Argv.cache_mem || Config.cache_mem
config.cacheOptions = {
    cache: {
        expire: 60 * 60,
        max_keys: 500,
        max_size: config.cache_mem
    }
};
config.cachePermitStale = Argv.permit_stale_resources || Config.permit_stale_resources || false;

/* HTTP/S proxy */
config.getProxyConfig = function(cb) {
    Npm.load(function(err, npm) {
        if (err) { return (err); }
        return cb(null, {
            httpProxy: Argv.http_proxy || Config.http_proxy || Npm.config.get('proxy') || process.env.HTTP_PROXY,
            httpsProxy: Argv.https_proxy || Config.https_proxy || Npm.config.get('https-proxy') || process.env.HTTPS_PROXY
        });
    });
};

/* Package Blacklist */
config.packageBlacklist = (function() {
    if (Argv.package_blacklist || Config.package_blacklist) {
        return require(Argv.package_blacklist || Config.package_blacklist);
    }
})();

module.exports = config;
<commit_msg>Add description for log_level option<commit_after>/**
 * Copyright (c) ActiveState 2014 - ALL RIGHTS RESERVED.
 */

'use strict';

var Config = require('../config/config-defaults');
var PackageJSON = require('../package');
var Lactate = require('lactate');
var Npm = require('npm');
var FS = require('fs');

var Optimist = require('optimist')
.usage('Usage: $0 -p <port> -a <external_dns> -c <file cache dir>')
.describe({
    server_address: 'The external DNS name this mirror should serve on',
    bind_address: 'The local interface bind address',
    cache_dir: 'The full directory path the cache directory (no trailing slash)',
    http_port: 'The HTTP port for the lazy mirror to listen on',
    config: 'The path to the JSON configuration file',
    cache_expiry: 'Expire the upstream registry cache assets on this value (ms)',
    cache_mem: 'The maxmium size in MB of registry data to keep in memory. A larger allocation reduces disk hits and improves performance',
    http_enabled: 'Enable the HTTP server on -p, this is true if neither --http_enabled or --https_enabled are supplied',
    https_enabled: 'Enable the HTTPS server on --https_port',
    https_key: 'The path to the private SSL key',
    https_cert: 'The path to the private SSL certificate',
    https_port: 'The HTTPS port (requires --https_enabled)',
    http_proxy: 'Specify a HTTP proxy to traverse before making outbound requests',
    https_proxy: 'Specify a HTTPS proxy to traverse before making outbound requests',
    package_blacklist: 'Full path to a JSON configuration file of blacklisted packages',
    permit_stale_resources: 'Continue to serve stale resources if the upstream registry cannot be contacted',
    real_external_port: 'If this mirror is behind a proxy, set this flag to the real external port for client connections',
    upstream_host: 'The upstream registry host',
    upstream_port: 'The default upstream registry port',
    upstream_db_path: 'The default upstream registry database path, default: none (requires a leading slash)',
    upstream_use_https: 'Use HTTPS only when proxying to the upstream registry',
    upstream_verify_ssl: 'Verify the upstream registry\'s SSL certificates',
    log_level: 'Logging level'
})
.default({
    'server_address': 'localhost',
    'bind_address': '127.0.0.1',
    'cache_dir': '/tmp/files',
    'http_port': 2000,
    'cache_expiry': 24 * 60 * 60 * 1000, // 24 Hours
    'cache_mem': 200, // MB
    'https_port': 443,
    'upstream_host': 'registry.npmjs.org',
    'upstream_port': 80,
    'upstream_use_https': false,
    'upstream_verify_ssl': false,
    'log_level': 'info'
})
.alias({
    'server_address': 'a',
    'bind_address': 'b',
    'cache_dir': 'c',
    'http_port': 'p',
    'config': 'C'
});

var Argv = Optimist.argv,
    config = {};

/* CLI specific */
if (Argv.h) {
    console.log(Optimist.help());
    process.exit();

} else if (Argv.v) {
    console.log('npm-lazy-mirror: ' + PackageJSON.version);
    process.exit();

} else if (Argv.C || Argv.config) {
    Config = JSON.parse(FS.readFileSync((Argv.C || Argv.config)));
}

/* Local server options */
config.httpPort = Argv.p || Argv.port || Config.http_port;
config.serverAddress = Argv.a || Argv.server_address || Config.server_address;
config.bindAddress = Argv.b || Argv.bind_address || Config.bind_address;
config.httpEnabled = Argv.http_enabled || Config.http_enabled;

/* Local server HTTPS options */
config.httpsPort = Argv.https_port || Config.https_port;
config.httpsEnabled = Argv.https_enabled || Config.https_enabled;

if (!config.httpEnabled && !config.httpsEnabled) {
    config.httpEnabled = true;
}

config.realExternalPort = Argv.real_external_port || (config.httpsEnabled ? config.httpsPort : config.httpPort);

/* Logging */
config.logLevel = Argv.log_level || Config.log_level;

config.httpsKey = Argv.https_key || Config.https_key || null;
config.httpsCert = Argv.https_cert || Config.https_cert || null;

/* Upstream Registry */
config.upstreamHost = Argv.upstream_host || Config.upstream_host;
config.upstreamPort = Argv.upstream_port || Config.upstream_port;
config.upstreamUseHttps = Argv.upstream_use_https || Config.upstream_use_https;
config.upstreamVerifySSL = Argv.upstream_verify_ssl || Config.upstream_verify_ssl;
config.upstreamDBPath = Argv.upstream_db_path || Config.upstream_db_path || '';

/* Caching options */
config.cache = {};
config.cacheDir = Argv.c || Argv.cache_dir || Config.cache_dir;
config.cacheExpiry = Argv.cache_expiry || Config.cache_expiry
config.cacheMem = Argv.cache_mem || Config.cache_mem
config.cacheOptions = {
    cache: {
        expire: 60 * 60,
        max_keys: 500,
        max_size: config.cache_mem
    }
};
config.cachePermitStale = Argv.permit_stale_resources || Config.permit_stale_resources || false;

/* HTTP/S proxy */
config.getProxyConfig = function(cb) {
    Npm.load(function(err, npm) {
        if (err) { return (err); }
        return cb(null, {
            httpProxy: Argv.http_proxy || Config.http_proxy || Npm.config.get('proxy') || process.env.HTTP_PROXY,
            httpsProxy: Argv.https_proxy || Config.https_proxy || Npm.config.get('https-proxy') || process.env.HTTPS_PROXY
        });
    });
};

/* Package Blacklist */
config.packageBlacklist = (function() {
    if (Argv.package_blacklist || Config.package_blacklist) {
        return require(Argv.package_blacklist || Config.package_blacklist);
    }
})();

module.exports = config;
<|endoftext|>


<commit_before>import React, { Component } from 'react';

export default class Cuisine extends Component {
    render() {
        return(

Mutfak

Cuisine

Turkish Meze

Turkish Meze consists of a wide variety of small plates & can be treated like an appitizer. Common meze dishes include sliced melon, strained yogurt with herbs, eggplant salad, and fried calamari.

Döner Kebab

The poster boy of Turkish cuisine, the döner kebab is a world-famous Turkish kebab usually consisting of lamb cooked on a vertical rotisserie.

Türk yemeği

Turkish food

They say the history of a country can be seen in its food, & Turkish food is certainly no exception. The Greeks, Persians, Arabs, & other groups have all left their mark to form what is one of the most unique yet familiar cuisines in the world. A meal in Turkey can consist of anything from kebabs with massive swaths of meat to stuffed vegetables. Popular beverages are Turkish tea & rakı, a clear alcoholic drink from in the Balkans. Turkish delight & baklava are Turkey's most famous desserts. Dig in!

Baklava

Adana Kebab

Rakı

Turkish Delight

Turkish delight, or 'lokum' in Turkish, is a variety of desserts made from sugar and gel. You can find a plethora of different flavors including pistachio, walnut & cinnamon.

Dolma

Dolma is a family of stuffed vegetable dishes that can be found all over the Balkans, Middle East, & Central Asia. Common vegetables to stuff include tomato, pepper, onion, zucchini, eggplant, and garlic.

Simit

Simit is a circular bread with sesame seeds & is the Turkish equivalent of a bagel. Its texture, size, & sweetness varies by region.

Kokoreç

Kokoreç is a dish consisting of lamb or goat intestines wrapped around either seasoned meat or bread. In Turkey it's served mostly as fast-food.

        );
    }
}
<commit_msg>Adjusted bootstrap for smaller screens<commit_after>import React, { Component } from 'react';

export default class Cuisine extends Component {
    render() {
        return(

Mutfak

Cuisine

Turkish Meze

Turkish Meze consists of a wide variety of small plates & can be treated like an appitizer. Common meze dishes include sliced melon, strained yogurt with herbs, eggplant salad, and fried calamari.

Döner Kebab

The poster boy of Turkish cuisine, the döner kebab is a world-famous Turkish kebab usually consisting of lamb cooked on a vertical rotisserie.

Türk yemeği

Turkish food

They say the history of a country can be seen in its food, & Turkish food is certainly no exception. The Greeks, Persians, Arabs, & other groups have all left their mark to form what is one of the most unique yet familiar cuisines in the world. A meal in Turkey can consist of anything from kebabs with massive swaths of meat to stuffed vegetables. Popular beverages are Turkish tea & rakı, a clear alcoholic drink from in the Balkans. Turkish delight & baklava are Turkey's most famous desserts. Dig in!

Baklava

Adana Kebab

Rakı

Turkish Delight

Turkish delight, or 'lokum' in Turkish, is a variety of desserts made from sugar and gel. You can find a plethora of different flavors including pistachio, walnut & cinnamon.

Dolma

Dolma is a family of stuffed vegetable dishes that can be found all over the Balkans, Middle East, & Central Asia. Common vegetables to stuff include tomato, pepper, onion, zucchini, eggplant, and garlic.

Simit

Simit is a circular bread with sesame seeds & is the Turkish equivalent of a bagel. Its texture, size, & sweetness varies by region.

Kokoreç

Kokoreç is a dish consisting of lamb or goat intestines wrapped around either seasoned meat or bread. In Turkey it's served mostly as fast-food.

        );
    }
}
<|endoftext|>


<commit_before>var redis = require("redis");
var async = require("async");

var CONST = require("./constants");
var srv = require("./server");
var time = require("./time");

/*
 * buitlt-in event emitter for bus events.
 */
var EventEmitter = require("events").EventEmitter,
	emitter = new EventEmitter();
var cli_sub = null;
var cli_pub = null;
var redis_channel_name = "msg_bus";

/*
 * Connect client for incoming messages.
 */
function connect_sub_client(config, ret_handler){

	cli_sub = redis.createClient(config.redisport, config.redishost);
	cli_sub.max_attempts = CONST.REDIS_MAX_ATTEMPTS();

	cli_sub.on("connect",function(){

		cli_sub.subscribe(redis_channel_name);
	});

	cli_sub.on("subscribe",function(channel){

		ret_handler(null);
	});

	cli_sub.on("message", function(channel, message_str){

		var message = JSON.parse(message_str);
		emitter.emit( "ev_msgbus_" + message.msg_type, message.data);
	})

	cli_sub.on("error", function(){

		if(cli_sub.attempts == cli_sub.max_attempts)
			ret_handler("error connecting redis");
	});

}

/*
 * Connect client for outgoing messages.
 */
function connect_pub_client(config, ret_handler){

	cli_pub = redis.createClient(config.redisport, config.redishost);
	cli_pub.max_attempts = CONST.REDIS_MAX_ATTEMPTS();

	cli_pub.on("connect",function(){

		ret_handler(null);
	});

	cli_pub.on("error", function(){

		if(cli_pub.attempts == cli_pub.max_attempts)
			ret_handler("error connecting redis");
	});
}

/*
 * Connect pub and sub clients to the bus.
 */
exports.connect = function( config, ret_handler ){

	config = config || {};
	config.redisport = config.redisport || 6379;
	config.redishost = config.redishost || "localhost";

	async.parallel([
		function(callback){

				connect_pub_client(config,function(err){

					callback(err);
				});
		},
		function(callback){

				connect_sub_client(config,function(err){

					callback(err);
				});
		}
	],  function(err){

		if(err && ret_handler)
			ret_handler(err);
		else if(err)
			console.error("!! Redis connection dropped");

	});

}

/*
 * Close connections to redis bus
 */
exports.close  = function(){

	cli_pub.end();
	cli_sub.end();
}

/*
 * publish data to redis bus.
 */
exports.publish = function( data ){

	var data_str = JSON.stringify(data);
	cli_pub.publish( redis_channel_name, data_str);

}

//ev_type: ev_msgbus_dummy
exports.on = function( ev_type, ret_handler ){

	emitter.on(ev_type, function( data ){

		ret_handler( {
						ev_type: ev_type,
						ev_tstamp: time.now(),
						ev_data:data
					 });
	});

}

<commit_msg>Added disconnection logic.<commit_after>var redis = require("redis");
var async = require("async");

var CONST = require("./constants");
var srv = require("./server");
var time = require("./time");

/*
 * buitlt-in event emitter for bus events.
 */
var EventEmitter = require("events").EventEmitter,
	emitter = new EventEmitter();
var cli_sub = null;
var cli_pub = null;
var redis_channel_name = "msg_bus";

/*
 * Connect client for incoming messages.
 */
function connect_sub_client(config, ret_handler){

	cli_sub = redis.createClient(config.redisport, config.redishost);
	cli_sub.max_attempts = CONST.REDIS_MAX_ATTEMPTS();

	cli_sub.on("connect",function(){

		cli_sub.subscribe(redis_channel_name);
	});

	cli_sub.on("subscribe",function(channel){

		cli_sub.max_attempts = null;
		if(!srv.config.app.bus)
			ret_handler(null);
	});

	cli_sub.on("message", function(channel, message_str){

		var message = JSON.parse(message_str);
		emitter.emit( "ev_msgbus_" + message.msg_type, message.data);
	})

	cli_sub.on("error", function(){

		if(cli_sub.attempts == cli_sub.max_attempts)
			ret_handler("error connecting redis");
	});

}

/*
 * Connect client for outgoing messages.
 */
function connect_pub_client(config, ret_handler){

	cli_pub = redis.createClient(config.redisport, config.redishost);
	cli_pub.max_attempts = CONST.REDIS_MAX_ATTEMPTS();

	cli_pub.on("connect",function(){

		cli_pub.max_attempts = null;
		if(!srv.config.app.bus)
			ret_handler(null);
	});

	cli_pub.on("error", function(){

		if(cli_pub.attempts === cli_pub.max_attempts)
			ret_handler("error connecting redis");
	});
}

/*
 * Connect pub and sub clients to the bus.
 */
exports.connect = function( config, ret_handler ){

	config = config || {};
	config.redisport = config.redisport || 6379;
	config.redishost = config.redishost || "localhost";

	async.series([
		function(callback){

				connect_pub_client(config,function(err){

					callback(err);
				});
		},
		function(callback){

				connect_sub_client(config,function(err){

					callback(err);
				});
		}
	],  function(err){

		if(ret_handler)
			ret_handler(err);
		else if(err){
			console.error("!!Error connecting redis");
		}
	});

}

/*
 * Close connections to redis bus
 */
exports.close  = function(){

	cli_pub && cli_pub.end();
	cli_sub && cli_sub.end();
}

/*
 * publish data to redis bus.
 */
exports.publish = function( data ){

	var data_str = JSON.stringify(data);
	cli_pub.publish( redis_channel_name, data_str);

}

//ev_type: ev_msgbus_dummy
exports.on = function( ev_type, ret_handler ){

	emitter.on(ev_type, function( data ){

		ret_handler( {
						ev_type: ev_type,
						ev_tstamp: time.now(),
						ev_data:data
					 });
	});

}

<|endoftext|>


<commit_before>var test = require('tap').test;
var insert = require('../lib/insert');
var chunky = require('chunky');

test('insert headers', function (t) {
    t.plan(2 * 50);
    var msg = [
        'POST / HTTP/1.1',
        'Host: beep',
        '',
        'sound=boop'
    ].join('\r\n');

    for (var i = 0; i < 50; i++) {
        var bufs = chunky(msg);
        t.equal(bufs.map(String).join(''), msg);

        var s = insert({ headers: { foo : 'bar', baz : 'quux' } });
        var data = '';
        s.on('data', function (buf) { data += buf });
        s.on('end', function () {
            t.equal(data, [
                'POST / HTTP/1.1',
                'Host: beep',
                'foo: bar',
                'baz: quux',
                '',
                'sound=boop'
            ].join('\r\n'));
        });

        for (var j = 0; j < bufs.length; j++) {
            s.write(bufs[j]);
        }
        s.end();
    }
});
<commit_msg>add checks for CRLF and LF<commit_after>var test = require('tap').test;
var insert = require('../lib/insert');
var chunky = require('chunky');

test('insert headers CRLF', function (t) {
    t.plan(2 * 50);
    var msg = [
        'POST / HTTP/1.1',
        'Host: beep',
        '',
        'sound=boop'
    ].join('\r\n');

    for (var i = 0; i < 50; i++) {
        var bufs = chunky(msg);
        t.equal(bufs.map(String).join(''), msg);

        var s = insert({ headers: { foo : 'bar', baz : 'quux' } });
        var data = '';
        s.on('data', function (buf) { data += buf });
        s.on('end', function () {
            t.equal(data, [
                'POST / HTTP/1.1',
                'Host: beep',
                'foo: bar',
                'baz: quux',
                '',
                'sound=boop'
            ].join('\r\n'));
        });

        for (var j = 0; j < bufs.length; j++) {
            s.write(bufs[j]);
        }
        s.end();
    }
});

test('insert headers LF', function (t) {
    t.plan(2 * 50);
    var msg = [
        'POST / HTTP/1.1',
        'Host: beep',
        '',
        'sound=boop'
    ].join('\n');

    for (var i = 0; i < 50; i++) {
        var bufs = chunky(msg);
        t.equal(bufs.map(String).join(''), msg);

        var s = insert({ headers: { foo : 'bar', baz : 'quux' } });
        var data = '';
        s.on('data', function (buf) { data += buf });
        s.on('end', function () {
            t.equal(data, [
                'POST / HTTP/1.1',
                'Host: beep',
                'foo: bar',
                'baz: quux',
                '',
                'sound=boop'
            ].join('\n'));
        });

        for (var j = 0; j < bufs.length; j++) {
            s.write(bufs[j]);
        }
        s.end();
    }
});
<|endoftext|>


<commit_before>//
//  We need to load cssstyle's parsers.js, but its location differs
//  between node 4 and node 5, so check which one we have.
//

var fs = require('fs');

var PARSERS = 'jsdom/node_modules/cssstyle/lib/parsers.js';  // node 4 hierarchy
try {fs.accessSync(PARSERS, fs.F_OK)} catch (e) {
  PARSERS = 'cssstyle/lib/parsers.js';  // node 5 heirarchy
}

//
//  Patch for CSSStyleDeclaration padding property so that it sets/clears
//  the Top, Right, Bottom, and Left properties (and also validates the
//  padding value)
//
var PADDING = (function () {
  var parsers = require(PARSERS);
  var TYPES = parsers.TYPES;

  var isValid = function (v) {
    var type = parsers.valueType(v);
    return type === TYPES.LENGTH || type === TYPES.PERCENT;
  };

  var parser = function (v) {
    return parsers.parseMeasurement(v);
  }

  var mySetter = parsers.implicitSetter('padding', '', isValid, parser);
  var myGlobal = parsers.implicitSetter('padding', '', function () {return true}, function (v) {return v});

  return {
    set: function (v) {
      if (typeof v === "number") v = String(v);
      if (typeof v !== "string") return;
      var V = v.toLowerCase();
      switch (V) {
       case 'inherit':
       case 'initial':
       case 'unset':
       case '':
        myGlobal.call(this, V);
        break;

       default:
        mySetter.call(this, v);
        break;
      }
    },
    get: function () {
      return this.getPropertyValue('padding');
    },
    enumerable: true,
    configurable: true
  };
})();

//
//  Patch for CSSStyleDeclaration margin property so that it sets/clears
//  the Top, Right, Bottom, and Left properties (and also validates the
//  margin value)
//
var MARGIN = (function () {
  var parsers = require(PARSERS);
  var TYPES = parsers.TYPES;

  var isValid = function (v) {
    if (v.toLowerCase() === "auto") return true;
    var type = parsers.valueType(v);
    return type === TYPES.LENGTH || type === TYPES.PERCENT;
  };

  var parser = function (v) {
    var V = v.toLowerCase();
    if (V === "auto") return V;
    return parsers.parseMeasurement(v);
  }

  var mySetter = parsers.implicitSetter('margin', '', isValid, parser);
  var myGlobal = parsers.implicitSetter('margin', '', function () {return true}, function (v) {return v});

  return {
    set: function (v) {
      if (typeof v === "number") v = String(v);
      if (typeof v !== "string") return;
      var V = v.toLowerCase();
      switch (V) {
       case 'inherit':
       case 'initial':
       case 'unset':
       case '':
        myGlobal.call(this, V);
        break;

       default:
        mySetter.call(this, v);
        break;
      }
    },
    get: function () {
      return this.getPropertyValue('margin');
    },
    enumerable: true,
    configurable: true
  };
})();

//
//  Patch jsdom functions
//
exports.patch = function (jsdom) {
  var document = jsdom('');
  var window = document.defaultView;
  //
  //  Fix setting of style attributes so shorthands work properly.
  //
  var div = document.createElement("div");
  div.style.border = "1px solid black";
  if (div.style.border !== "1px solid black") {
    var INIT = window.HTMLElement._init;
    window.HTMLElement._init = function () {
      INIT.apply(this,arguments);
      var that = this;
      this.style._onChange = function (csstext) {
        if (!that._settingCssText) {
          that._settingCssText = true;
          that.setAttribute('style', csstext);
          that._settingCssText = false;
        }
      };
    }
  }
  //
  //  Add missing nodeName to Attr (after jsdom 7.1.0, it is no longer defined)
  //  since this is used in mml2jax.
  //
  if (!("nodeName" in window.Attr.prototype)) {
    Object.defineProperties(window.Attr.prototype,{
      nodeName: {get: function() {return this.name}}
    });
  }
  //
  //  Fix CSSStyleDeclaration properties that are broken (padding, margin)
  //
  div.style.paddingTop = "10px";
  div.style.padding = "1px";
  if (div.style.paddingTop !== "1px") {
    var core = require("jsdom/lib/jsdom/level1/core");
    Object.defineProperties(core.CSSStyleDeclaration.prototype,{
      padding: PADDING,
      margin: MARGIN
    });
  }
}<commit_msg>Add more patches for padding and margin (see chad3814/CSSStyleDeclaration#37)<commit_after>//
//  We need to load cssstyle's parsers.js, but its location differs
//  between node 4 and node 5, so check which one we have.
//

var fs = require('fs');

var PARSERS = 'jsdom/node_modules/cssstyle/lib/parsers.js';  // node 4 hierarchy
try {fs.accessSync(PARSERS, fs.F_OK)} catch (e) {
  PARSERS = 'cssstyle/lib/parsers.js';  // node 5 heirarchy
}

//
//  Companion to implicitSetter, but for the individual parts.
//  This sets the individual value, and checks to see if all four
//  sub-parts are set.  If so, it sets the shorthand version and removes
//  the individual parts from the cssText.
//
var subImplicitSetter = function (prefix, part, isValid, parser) {
  var property = prefix + '-' + part;
  var subparts = [prefix+"-top", prefix+"-right", prefix+"-bottom", prefix+"-left"];

  return function (v) {
    if (typeof v === 'number') v = v.toString();
    if (typeof v !== 'string') return undefined;
    if (!isValid(v)) return undefined;
    v = parser(v);
    this._setProperty(property,v);
    var parts = [];
    for (var i = 0; i < 4; i++) {
      if (this._values[subparts[i]] == null || this._values[subparts[i]] === '') break;
      parts.push(this._values[subparts[i]]);
    }
    if (parts.length === 4) {
      for (i = 0; i < 4; i++) {
        this.removeProperty(subparts[i]);
        this._values[subparts[i]] = parts[i];
      }
      this._setProperty(prefix,parts.join(" "));
    }
    return v;
  };
};

//
//  Patch for CSSStyleDeclaration padding property so that it sets/clears
//  the Top, Right, Bottom, and Left properties (and also validates the
//  padding value)
//
var PADDING = (function () {
  var parsers = require(PARSERS);
  var TYPES = parsers.TYPES;

  var isValid = function (v) {
    var type = parsers.valueType(v);
    return type === TYPES.LENGTH || type === TYPES.PERCENT;
  };

  var parser = function (v) {
    return parsers.parseMeasurement(v);
  };

  var mySetter = parsers.implicitSetter('padding', '', isValid, parser);
  var myGlobal = parsers.implicitSetter('padding', '', function () {return true}, function (v) {return v});

  return {
    definition: {
      set: function (v) {
        if (typeof v === "number") v = String(v);
        if (typeof v !== "string") return;
        var V = v.toLowerCase();
        switch (V) {
         case 'inherit':
         case 'initial':
         case 'unset':
         case '':
          myGlobal.call(this, V);
          break;

         default:
          mySetter.call(this, v);
          break;
        }
      },
      get: function () {
        return this.getPropertyValue('padding');
      },
      enumerable: true,
      configurable: true
    },
    isValid: isValid,
    parser: parser
  };
})();

//
//  Patch for CSSStyleDeclaration margin property so that it sets/clears
//  the Top, Right, Bottom, and Left properties (and also validates the
//  margin value)
//
var MARGIN = (function () {
  var parsers = require(PARSERS);
  var TYPES = parsers.TYPES;

  var isValid = function (v) {
    if (v.toLowerCase() === "auto") return true;
    var type = parsers.valueType(v);
    return type === TYPES.LENGTH || type === TYPES.PERCENT;
  };

  var parser = function (v) {
    var V = v.toLowerCase();
    if (V === "auto") return V;
    return parsers.parseMeasurement(v);
  };

  var mySetter = parsers.implicitSetter('margin', '', isValid, parser);
  var myGlobal = parsers.implicitSetter('margin', '', function () {return true}, function (v) {return v});

  return {
    definition: {
      set: function (v) {
        if (typeof v === "number") v = String(v);
        if (typeof v !== "string") return;
        var V = v.toLowerCase();
        switch (V) {
         case 'inherit':
         case 'initial':
         case 'unset':
         case '':
          myGlobal.call(this, V);
          break;

         default:
          mySetter.call(this, v);
          break;
        }
      },
      get: function () {
        return this.getPropertyValue('margin');
      },
      enumerable: true,
      configurable: true
    },
    isValid: isValid,
    parser: parser
  };
})();

//
//  Patch jsdom functions
//
exports.patch = function (jsdom) {
  var document = jsdom('');
  var window = document.defaultView;
  //
  //  Fix setting of style attributes so shorthands work properly.
  //
  var div = document.createElement("div");
  div.style.border = "1px solid black";
  if (div.style.border !== "1px solid black") {
    var INIT = window.HTMLElement._init;
    window.HTMLElement._init = function () {
      INIT.apply(this,arguments);
      var that = this;
      this.style._onChange = function (csstext) {
        if (!that._settingCssText) {
          that._settingCssText = true;
          that.setAttribute('style', csstext);
          that._settingCssText = false;
        }
      };
    }
  }
  //
  //  Add missing nodeName to Attr (after jsdom 7.1.0, it is no longer defined)
  //  since this is used in mml2jax.
  //
  if (!("nodeName" in window.Attr.prototype)) {
    Object.defineProperties(window.Attr.prototype,{
      nodeName: {get: function() {return this.name}}
    });
  }
  //
  //  Fix CSSStyleDeclaration properties that are broken (padding, margin)
  //
  div.style.paddingTop = "10px";
  div.style.padding = "1px";
  if (div.style.paddingTop !== "1px") {
    var core = require("jsdom/lib/jsdom/level1/core");
    Object.defineProperties(core.CSSStyleDeclaration.prototype,{
      padding: PADDING.definition,
      margin: MARGIN.definition
    });
  }
  div.style.padding = "1px 2px 3px 4px";
  div.style.paddingTop = "10px";
  if (div.style.padding !== "10px 2px 3px 4px") {
    var core = require("jsdom/lib/jsdom/level1/core");
    Object.defineProperties(core.CSSStyleDeclaration.prototype,{
      marginTop: {
        set: subImplicitSetter('margin', 'top', MARGIN.isValid, MARGIN.parser),
        get: function () {
          return this.getPropertyValue('margin-top');
        }
      },
      marginRight: {
        set: subImplicitSetter('margin', 'right', MARGIN.isValid, MARGIN.parser),
        get: function () {
          return this.getPropertyValue('margin-right');
        }
      },
      marginBottom: {
        set: subImplicitSetter('margin', 'bottom', MARGIN.isValid, MARGIN.parser),
        get: function () {
          return this.getPropertyValue('margin-bottom');
        }
      },
      marginLeft: {
        set: subImplicitSetter('margin', 'left', MARGIN.isValid, MARGIN.parser),
        get: function () {
          return this.getPropertyValue('margin-left');
        }
      },
      paddingTop: {
        set: subImplicitSetter('padding', 'top', PADDING.isValid, PADDING.parser),
        get: function () {
          return this.getPropertyValue('padding-top');
        }
      },
      paddingRight: {
        set: subImplicitSetter('padding', 'right', PADDING.isValid, PADDING.parser),
        get: function () {
          return this.getPropertyValue('padding-right');
        }
      },
      paddingBottom: {
        set: subImplicitSetter('padding', 'bottom', PADDING.isValid, PADDING.parser),
        get: function () {
          return this.getPropertyValue('padding-bottom');
        }
      },
      paddingLeft: {
        set: subImplicitSetter('padding', 'left', PADDING.isValid, PADDING.parser),
        get: function () {
          return this.getPropertyValue('padding-left');
        }
      }
    });
  }
}
<|endoftext|>


<commit_before>myApp.factory('ComicVine', ['$rootScope', '$http', '$q', 'DateUtils', '$filter',
    function($rootScope, $http, $q, DateUtils, $filter) {

        var resultsPerPage = 100;
        var comicResults = [];

        var baseComicVineUrl = "http://www.comicvine.com/api/";
        var comicDateQuery = "&filter=store_date:";

        var constructURL = function(queryType, options) {
            var queryUrl = baseComicVineUrl;

            if (queryType === "comic") {
                queryUrl += "issues/?format=jsonp&json_callback=JSON_CALLBACK";
            } else if (queryType === "series") {
                queryUrl += "series/?format=jsonp&json_callback=JSON_CALLBACK";
            }
            if (options.offset) {
                queryUrl += "&offset=" + options.offset;
            }

            if (options.dateRange) {
                var dateRange = options.dateRange;
                queryUrl += comicDateQuery + dateRange.firstDate.getFullYear() + "-" + (dateRange.firstDate.getUTCMonth() + 1) + "-" +
                    dateRange.firstDate.getUTCDate() + "|" + dateRange.lastDate.getFullYear() + "-" + (dateRange.lastDate.getUTCMonth() + 1) +
                    "-" + dateRange.lastDate.getUTCDate() + "&";
            } else if (options.query) {
                queryUrl += options.query + "&";
            } else if (options.resourceURI) {
                queryUrl = options.resourceURI + "?";
            } else {
                // shouldn't ever get here
            }

            var deferred = $q.defer();
            $http.get("config/config.json").then(function successCallback(response) {
                queryUrl += "&api_key=" + response.data.COMIC_VINE_API_KEY;
                deferred.resolve(queryUrl);
            }, function errorCallback(response) {
                $rootScope.errorMessage = response.statusText;
            });
            return deferred.promise;
        };

        var queryComics = function(queryUrl) {
            // console.log(queryUrl); //logging query URL
            var deferred = $q.defer();
            $http.jsonp(queryUrl).then(function successCallback(response) {
                deferred.resolve(response);
            }, function errorCallback(response) {
                deferred.resolve(response.statusText);
            });
            return deferred.promise;
        };

        var parseComics = function(comics) {
            for (var i = 0; i < comics.results.length; i++) {
                var comic = comics.results[i];
                comic.series = comic.volume;
                comic.series.name = comic.series.name + " ";
                comic.series.resourceURI = comic.api_detail_url;
                comic.issueNumber = comic.issue_number;
                var imageUrl = comic.image.super_url;
                comic.thumbnail = {
                    extension: imageUrl.substr(imageUrl.lastIndexOf('.') + 1),
                    path: imageUrl.substr(0, imageUrl.lastIndexOf('.'))
                };
                comicResults.push(comic);
            }
            console.log(comicResults);
        };

        var loadComicDataForWeek = function(dateRange, offset) {
            var promise = constructURL("comic", { "dateRange": dateRange, "offset": offset }).then(queryComics).then(function(response) {
                offset += 100;
                var numTotalResults = response.data.number_of_total_results;
                console.log(numTotalResults);
                console.log(response);
                parseComics(response.data);
                if ((offset) > numTotalResults) {
                    return comicResults;
                } else {
                    return loadComicDataForWeek(dateRange, offset);
                }
            });
            return promise;
        };

        var myObject = {
            getComicDataForWeek: function(dateRange) {
                return loadComicDataForWeek(dateRange, 0);
            }
        };

        return myObject;
    }
]);
<commit_msg>Fixed an issue with comic vine where the array of returned results was never cleared<commit_after>myApp.factory('ComicVine', ['$rootScope', '$http', '$q', 'DateUtils', '$filter',
    function($rootScope, $http, $q, DateUtils, $filter) {

        var resultsPerPage = 100;
        var comicResults = [];

        var baseComicVineUrl = "http://www.comicvine.com/api/";
        var comicDateQuery = "&filter=store_date:";

        var constructURL = function(queryType, options) {
            var queryUrl = baseComicVineUrl;

            if (queryType === "comic") {
                queryUrl += "issues/?format=jsonp&json_callback=JSON_CALLBACK";
            } else if (queryType === "series") {
                queryUrl += "series/?format=jsonp&json_callback=JSON_CALLBACK";
            }
            if (options.offset) {
                queryUrl += "&offset=" + options.offset;
            }

            if (options.dateRange) {
                var dateRange = options.dateRange;
                queryUrl += comicDateQuery + dateRange.firstDate.getFullYear() + "-" + (dateRange.firstDate.getUTCMonth() + 1) + "-" +
                    dateRange.firstDate.getUTCDate() + "|" + dateRange.lastDate.getFullYear() + "-" + (dateRange.lastDate.getUTCMonth() + 1) +
                    "-" + dateRange.lastDate.getUTCDate() + "&";
            } else if (options.query) {
                queryUrl += options.query + "&";
            } else if (options.resourceURI) {
                queryUrl = options.resourceURI + "?";
            } else {
                // shouldn't ever get here
            }

            var deferred = $q.defer();
            $http.get("config/config.json").then(function successCallback(response) {
                queryUrl += "&api_key=" + response.data.COMIC_VINE_API_KEY;
                deferred.resolve(queryUrl);
            }, function errorCallback(response) {
                $rootScope.errorMessage = response.statusText;
            });
            return deferred.promise;
        };

        var queryComics = function(queryUrl) {
            // console.log(queryUrl); //logging query URL
            var deferred = $q.defer();
            $http.jsonp(queryUrl).then(function successCallback(response) {
                deferred.resolve(response);
            }, function errorCallback(response) {
                deferred.resolve(response.statusText);
            });
            return deferred.promise;
        };

        var parseComics = function(comics) {
            for (var i = 0; i < comics.results.length; i++) {
                var comic = comics.results[i];
                comic.series = comic.volume;
                comic.series.name = comic.series.name + " ";
                comic.series.resourceURI = comic.api_detail_url;
                comic.issueNumber = comic.issue_number;
                var imageUrl = comic.image.super_url;
                comic.thumbnail = {
                    extension: imageUrl.substr(imageUrl.lastIndexOf('.') + 1),
                    path: imageUrl.substr(0, imageUrl.lastIndexOf('.'))
                };
                comicResults.push(comic);
            }
            console.log(comicResults);
        };

        var loadComicDataForWeek = function(dateRange, offset) {
            var promise = constructURL("comic", { "dateRange": dateRange, "offset": offset }).then(queryComics).then(function(response) {
                offset += 100;
                var numTotalResults = response.data.number_of_total_results;
                parseComics(response.data);
                if ((offset) > numTotalResults) {
                    var returnedComics = comicResults;
                    comicResults = [];
                    return returnedComics;
                } else {
                    return loadComicDataForWeek(dateRange, offset);
                }
            });
            return promise;
        };

        var myObject = {
            getComicDataForWeek: function(dateRange) {
                return loadComicDataForWeek(dateRange, 0);
            }
        };

        return myObject;
    }
]);
<|endoftext|>