<commit_before>import exponent from "./exponent";
import formatGroup from "./formatGroup";
import formatSpecifier from "./formatSpecifier";
import formatTypes from "./formatTypes";
import {prefixExponent} from "./formatPrefixAuto";

var prefixes = ["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];

function identity(x) {
  return x;
}

export default function(locale) {
  var group = locale.grouping && locale.thousands ? formatGroup(locale.grouping, locale.thousands) : identity,
      currency = locale.currency,
      decimal = locale.decimal;

  function newFormat(specifier) {
    specifier = formatSpecifier(specifier);

    var fill = specifier.fill,
        align = specifier.align,
        sign = specifier.sign,
        symbol = specifier.symbol,
        zero = specifier.zero,
        width = specifier.width,
        comma = specifier.comma,
        precision = specifier.precision,
        type = specifier.type;

    // Compute the prefix and suffix.
    // For SI-prefix, the suffix is lazily computed.
    var prefix = symbol === "$" ? currency[0] : symbol === "#" && /[boxX]/.test(type) ? "0" + type.toLowerCase() : "",
        suffix = symbol === "$" ? currency[1] : /[%p]/.test(type) ? "%" : "";

    // What format function should we use?
    // Is this an integer type?
    // Can this type generate exponential notation?
    var formatType = formatTypes[type],
        maybeSuffix = !type || /[defgprs%]/.test(type);

    // Set the default precision if not specified,
    // or clamp the specified precision to the supported range.
    // For significant precision, it must be in [1, 21].
    // For fixed precision, it must be in [0, 20].
    precision = precision == null ? (type ? 6 : 12)
        : /[gprs]/.test(type) ? Math.max(1, Math.min(21, precision))
        : Math.max(0, Math.min(20, precision));

    function format(value) {
      var valuePrefix = prefix,
          valueSuffix = suffix,
          i, n, c;

      if (type === "c") {
        valueSuffix = formatType(value) + valueSuffix;
        value = "";
      } else {
        value = +value;

        // Convert negative to positive, and compute the prefix.
        // Note that -0 is not less than 0, but 1 / -0 is!
        var valueNegative = (value < 0 || 1 / value < 0) && (value *= -1, true);

        // Perform the initial formatting.
        value = formatType(value, precision);

        // If the original value was negative, it may be rounded to zero during
        // formatting; treat this as (positive) zero.
        if (valueNegative) {
          i = -1, n = value.length;
          valueNegative = false;
          while (++i < n) {
            if (c = value.charCodeAt(i), (48 < c && c < 58)
                || (type === "x" && 96 < c && c < 103)
                || (type === "X" && 64 < c && c < 71)) {
              valueNegative = true;
              break;
            }
          }
        }

        // Compute the prefix and suffix.
        valuePrefix = (valueNegative ? (sign === "(" ? sign : "-") : sign === "-" || sign === "(" ? "" : sign) + valuePrefix;
        valueSuffix = valueSuffix + (type === "s" ? prefixes[8 + prefixExponent / 3] : "") + (valueNegative && sign === "(" ? ")" : "");

        // Break the formatted value into the integer “value” part that can be
        // grouped, and fractional or exponential “suffix” part that is not.
        if (maybeSuffix) {
          i = -1, n = value.length;
          while (++i < n) {
            if (c = value.charCodeAt(i), 48 > c || c > 57) {
              valueSuffix = (c === 46 ? decimal + value.slice(i + 1) : value.slice(i)) + valueSuffix;
              value = value.slice(0, i);
              break;
            }
          }
        }
      }

      // If the fill character is not "0", grouping is applied before padding.
      if (comma && !zero) value = group(value, Infinity);

      // Compute the padding.
      var length = valuePrefix.length + value.length + valueSuffix.length,
          padding = length < width ? new Array(width - length + 1).join(fill) : "";

      // If the fill character is "0", grouping is applied after padding.
      if (comma && zero) value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = "";

      // Reconstruct the final output based on the desired alignment.
      switch (align) {
        case "<": return valuePrefix + value + valueSuffix + padding;
        case "=": return valuePrefix + padding + value + valueSuffix;
        case "^": return padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length);
      }
      if (locale.numerals) {
        var numerals = locale.numerals;
        return numeralReplacer( numerals, padding + valuePrefix +  value + valueSuffix);
      }
      return padding + valuePrefix +  value + valueSuffix;

    }

    format.toString = function() {
      return specifier + "";
    };

    return format;
  }

  function formatPrefix(specifier, value) {
    var f = newFormat((specifier = formatSpecifier(specifier), specifier.type = "f", specifier)),
        e = Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3,
        k = Math.pow(10, -e),
        prefix = prefixes[8 + e / 3];
    return function(value) {
      return f(k * value) + prefix;
    };
  }

  function numeralReplacer(numerals, number) {
    return number.replace(/[0-9]/g, (function (i) {
        return numerals[+i];
    }));
 }

  return {
    format: newFormat,
    formatPrefix: formatPrefix
  };
}
<commit_msg>remove spaces<commit_after>import exponent from "./exponent";
import formatGroup from "./formatGroup";
import formatSpecifier from "./formatSpecifier";
import formatTypes from "./formatTypes";
import {prefixExponent} from "./formatPrefixAuto";

var prefixes = ["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];

function identity(x) {
  return x;
}

export default function(locale) {
  var group = locale.grouping && locale.thousands ? formatGroup(locale.grouping, locale.thousands) : identity,
      currency = locale.currency,
      decimal = locale.decimal;

  function newFormat(specifier) {
    specifier = formatSpecifier(specifier);

    var fill = specifier.fill,
        align = specifier.align,
        sign = specifier.sign,
        symbol = specifier.symbol,
        zero = specifier.zero,
        width = specifier.width,
        comma = specifier.comma,
        precision = specifier.precision,
        type = specifier.type;

    // Compute the prefix and suffix.
    // For SI-prefix, the suffix is lazily computed.
    var prefix = symbol === "$" ? currency[0] : symbol === "#" && /[boxX]/.test(type) ? "0" + type.toLowerCase() : "",
        suffix = symbol === "$" ? currency[1] : /[%p]/.test(type) ? "%" : "";

    // What format function should we use?
    // Is this an integer type?
    // Can this type generate exponential notation?
    var formatType = formatTypes[type],
        maybeSuffix = !type || /[defgprs%]/.test(type);

    // Set the default precision if not specified,
    // or clamp the specified precision to the supported range.
    // For significant precision, it must be in [1, 21].
    // For fixed precision, it must be in [0, 20].
    precision = precision == null ? (type ? 6 : 12)
        : /[gprs]/.test(type) ? Math.max(1, Math.min(21, precision))
        : Math.max(0, Math.min(20, precision));

    function format(value) {
      var valuePrefix = prefix,
          valueSuffix = suffix,
          i, n, c;

      if (type === "c") {
        valueSuffix = formatType(value) + valueSuffix;
        value = "";
      } else {
        value = +value;

        // Convert negative to positive, and compute the prefix.
        // Note that -0 is not less than 0, but 1 / -0 is!
        var valueNegative = (value < 0 || 1 / value < 0) && (value *= -1, true);

        // Perform the initial formatting.
        value = formatType(value, precision);

        // If the original value was negative, it may be rounded to zero during
        // formatting; treat this as (positive) zero.
        if (valueNegative) {
          i = -1, n = value.length;
          valueNegative = false;
          while (++i < n) {
            if (c = value.charCodeAt(i), (48 < c && c < 58)
                || (type === "x" && 96 < c && c < 103)
                || (type === "X" && 64 < c && c < 71)) {
              valueNegative = true;
              break;
            }
          }
        }

        // Compute the prefix and suffix.
        valuePrefix = (valueNegative ? (sign === "(" ? sign : "-") : sign === "-" || sign === "(" ? "" : sign) + valuePrefix;
        valueSuffix = valueSuffix + (type === "s" ? prefixes[8 + prefixExponent / 3] : "") + (valueNegative && sign === "(" ? ")" : "");

        // Break the formatted value into the integer “value” part that can be
        // grouped, and fractional or exponential “suffix” part that is not.
        if (maybeSuffix) {
          i = -1, n = value.length;
          while (++i < n) {
            if (c = value.charCodeAt(i), 48 > c || c > 57) {
              valueSuffix = (c === 46 ? decimal + value.slice(i + 1) : value.slice(i)) + valueSuffix;
              value = value.slice(0, i);
              break;
            }
          }
        }
      }

      // If the fill character is not "0", grouping is applied before padding.
      if (comma && !zero) value = group(value, Infinity);

      // Compute the padding.
      var length = valuePrefix.length + value.length + valueSuffix.length,
          padding = length < width ? new Array(width - length + 1).join(fill) : "";

      // If the fill character is "0", grouping is applied after padding.
      if (comma && zero) value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = "";

      // Reconstruct the final output based on the desired alignment.
      switch (align) {
        case "<": return valuePrefix + value + valueSuffix + padding;
        case "=": return valuePrefix + padding + value + valueSuffix;
        case "^": return padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length);
      }
      if (locale.numerals) {
        var numerals = locale.numerals;
        return numeralReplacer( numerals, padding + valuePrefix +  value + valueSuffix);
      }
      return padding + valuePrefix +  value + valueSuffix;

    }

    format.toString = function() {
      return specifier + "";
    };

    return format;
  }

  function formatPrefix(specifier, value) {
    var f = newFormat((specifier = formatSpecifier(specifier), specifier.type = "f", specifier)),
        e = Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3,
        k = Math.pow(10, -e),
        prefix = prefixes[8 + e / 3];
    return function(value) {
      return f(k * value) + prefix;
    };
  }

  function numeralReplacer(numerals, number) {
    return number.replace(/[0-9]/g, (function (i) {
        return numerals[+i];
    }));
 }

  return {
    format: newFormat,
    formatPrefix: formatPrefix
  };
}
<|endoftext|>


<commit_before>/**
 * @file 日志打印器
 * @author lisfan <goolisfan@gmail.com>
 * @version 1.3.2
 * @licence MIT
 */

import validation from '@~lisfan/validation'

/**
 * 从`localStorage`的`LOGGER_RULES`键中读取**打印规则**配置，以便可以在生产环境开启日志打印调试
 */
const LOGGER_RULES = JSON.parse(global.localStorage.getItem('LOGGER_RULES')) || {}

/**
 * 从`localStorage`的`IS_DEV`键中读取是否为**开发环境**配置，以便可以在生产环境开启日志打印调试
 */
const IS_DEV = JSON.parse(global.localStorage.getItem('IS_DEV')) || process.env.NODE_ENV === 'development'

// 私有方法
const _actions = {
  /**
   * 打印器工厂函数
   * 查找ls中是否存在打印命名空间配置项，若存在，则进行替换覆盖
   * 判断是否存在子命名空间，依次判断子命名空间的长度
   *
   * @since 1.3.0
   *
   * @param {Logger} self - Logger实例
   * @param {string} method - 打印方法
   * @param {string} color - 颜色值，web安全色 http://www.w3school.com.cn/tiy/color.asp?color=LightGoldenRodYellow
   *
   * @returns {function}
   */
  logFactory(self, method, color) {
    return (...args) => {
      return _actions.logProxyRun(self, method, color, ...args)
    }
  },
  /**
   * 代理运行打印方法
   *
   * @since 1.3.0
   *
   * @param {Logger} self - Logger实例
   * @param {string} method - 打印方法
   * @param {string} color - 打印颜色，颜色值，web安全色 http://www.w3school.com.cn/tiy/color.asp?color=LightGoldenRodYellow
   * @param {...*} args - 其他参数
   *
   * @returns {Logger}
   */
  logProxyRun(self, method, color, ...args) {
    // 处于非激活状态的话则不输出日志
    if (!self.isActivated(method)) {
      return self
    }

    let formatStr = `%c[${self.$name}]:%c`

    // 遍历参数列表，找出dom元素，进行转换
    args = args.map((arg) => {
      return validation.isElement(arg)
        ? [arg]
        : arg
    })

    /* eslint-disable no-console */
    console[method](formatStr, `color: ${color}`, '', ...args)
    /* eslint-enable no-console */

    return self
  },
  /**
   * 代理运行console方法
   * [注] 内部会进行判断是否允许日志输出
   *
   * @since 1.3.0
   *
   * @param {Logger} self - Logger实例
   * @param {string} method - 打印方法
   * @param {...*} args - 其他参数
   *
   * @returns {Logger}
   */
  proxyRun(self, method, ...args) {
    /* eslint-disable no-console */
    self.isActivated(method) && console[method](...args)
    /* eslint-enable no-console */

    return self
  }
}

/**
 * @classdesc
 * 日志打印类
 *
 * @class
 */
class Logger {
  /**
   * 打印器命名空间规则配置项
   * - 可以配置整个命名空间是否输出日志
   * - 也可以配置命名空间下某个实例方法是否输出日志
   *
   * @since 1.2.0
   *
   * @static
   * @readonly
   * @memberOf Logger
   *
   * @property {object} rules - 打印器命名空间规则配置集合
   */
  static rules = LOGGER_RULES

  /**
   * 更改命名空间规则配置项
   * [注]从`localStorage`的`LOGGER_RULES`键中读取规则配置优先级最高，始终会覆盖其他规则
   *
   * @since 1.2.0
   *
   * @static
   *
   * @param {object} rules - 配置参数
   * @param {string} [rules.name] - 日志器命名空间
   * @param {boolean} [rules.debug] - 调试模式是否开启
   *
   * @returns {Logger}
   *
   * @example
   * // 定义规则
   * Logger.configRules = {
   *    utils-http:false // 整个utils-http不可打印输出
   *    utils-calc.log=true // utils-calc打印器的log方法不支持打印输出
   * }
   */
  static configRules(rules) {
    Logger.rules = {
      ...Logger.rules,
      ...rules,
      ...LOGGER_RULES,
    }

    return this
  }

  /**
   * 默认配置选项
   * 为了在生产环境能开启调试模式
   * 提供了从localStorage获取默认配置项的措施
   *
   * @since 1.0.0
   *
   * @static
   * @readonly
   * @memberOf Logger
   *
   * @property {string} name='logger' - 日志器命名空间，默认为'logger'
   * @property {boolean} debug=true - 调试模式是否开启，默认开启
   */
  static options = {
    name: 'logger',
    debug: true,
  }

  /**
   * 更新默认配置选项
   *
   * @since 1.0.0
   *
   * @static
   *
   * @param {object} options - 配置参数
   * @param {string} [options.name='logger'] - 日志器命名空间
   * @param {boolean} [options.debug=true] - 调试模式是否开启
   *
   * @returns {Logger}
   */
  static config(options) {
    // 以内置配置为优先
    Logger.options = {
      ...Logger.options,
      ...options
    }

    return this
  }

  /**
   * 构造函数
   *
   * @param {object} [options] - 实例配置选项，若参数为`string`类型，则表示设定为`options.name`的值
   * @param {string} [options.name='logger'] - 日志器命名空间
   * @param {boolean} [options.debug=true] - 调试模式是否开启
   */
  constructor(options) {
    this.$options = validation.isString(options)
      ? {
        ...Logger.options,
        name: options
      }
      : {
        ...Logger.options,
        ...options
      }
  }

  /**
   * 实例的配置项
   *
   * @since 1.0.0
   *
   * @readonly
   *
   * @returns {object}
   */
  $options = undefined

  /**
   * 获取实例的命名空间配置项
   *
   * @since 1.1.0
   *
   * @readonly
   *
   * @returns {string}
   */
  get $name() {
    return this.$options.name
  }

  /**
   * 获取实例的调试模式配置项
   *
   * @since 1.1.0
   *
   * @returns {string}
   */
  get $debug() {
    return this.$options.debug
  }

  /**
   * 检测当前是否调试模式是否激活：可以打印日志
   *
   * @since 1.1.0
   *
   * @param {string} [method] - 若指定了该参数，则精确检测具体的实例方法
   *
   * @returns {boolean}
   */
  isActivated(method) {
    // 如果不是开发模式
    if (!IS_DEV) {
      return false
    }

    // 以子命名空间的状态优先
    let status = Logger.rules[this.$name]
    // 先判断其子命名空间的状态

    // 如果存在放法名，则判断子命名空间
    // 当前方法名存在子命名空间里且明确设置为false时，则不打印
    // 当前子命名空间如果明确false，则不打印
    if (method) {
      const subStatus = Logger.rules[`${this.$name}.${method}`]

      if (validation.isBoolean(subStatus)) status = subStatus
    }

    // 如果明确指定该命名空间不开启日志打印，则不打印
    if (status === false) {
      return false
    }

    // 最后才判断实例是否禁用了调试
    if (!this.$debug) {
      return false
    }

    return true
  }

  /**
   * 创建一个指定颜色的打印方法
   *
   * @since 1.1.0
   *
   * @param {string} color - 颜色值
   *
   * @returns {Function}
   */
  color(color) {
    return _actions.logFactory(this, 'log', `${color}`)
  }

  /**
   * 启用日志输出
   *
   * @since 1.1.0
   *
   * @returns {Logger}
   */
  enable() {
    this.$options.debug = true

    return this
  }

  /**
   * 禁用日志输出
   *
   * @since 1.1.0
   *
   * @returns {Logger}
   */
  disable() {
    this.$options.debug = false

    return this
  }

  /**
   * 常规日志打印
   *
   * @since 1.0.0
   *
   * @param {...*} args - 任意数据
   *
   * @returns {Logger}
   */
  log(...args) {
    return _actions.logProxyRun(this, 'log', 'lightseagreen', ...args)
  }

  /**
   * 警告日志打印
   *
   * @since 1.0.0
   *
   * @param {...*} args - 任意数据
   *
   * @returns {Logger}
   */
  warn(...args) {
    return _actions.logProxyRun(this, 'warn', 'goldenrod', ...args)
  }

  /**
   * 调用栈日志打印
   *
   * @since 1.0.1
   *
   * @param {...*} args - 任意数据
   *
   * @returns {Logger}
   */
  trace(...args) {
    return _actions.logProxyRun(this, 'trace', 'lightseagreen', ...args)
  }

  /**
   * 错误日志打印，同时会抛出错误，阻塞后续逻辑
   *
   * @since 1.0.0
   *
   * @param {...*} args - 参数列表
   *
   * @throws Error - 抛出错误提示
   */
  error(...args) {
    const message = args.map((value) => {
      return value.toString()
    }).join(' ')

    throw new Error(message)
  }

  /**
   * log的同名方法，使用方法请参考{@link Logger#log}
   *
   * @since 1.1.0
   *
   * @see Logger#log
   *
   * @param {...*} args - 任意数据
   *
   * @returns {Logger}
   */
  info(...args) {
    return this.log(...args)
  }

  /**
   * log的同名方法，使用方法请参考{@link Logger#log}
   *
   * @since 1.1.0
   *
   * @see Logger#log
   *
   * @param {...*} args - 任意数据
   *
   * @returns {Logger}
   */
  debug(...args) {
    return this.log(...args)
  }

  /**
   * 区别于console.table
   * - 对象或数组类型数据以表格的方式打印
   * - 若非这两种数据类型，则调用log方法打印
   *
   * @since 1.1.0
   *
   * @param {*} data - 任意数据
   *
   * @returns {Logger}
   */
  table(data) {
    return validation.isArray(data) && validation.isPlainObject(data)
      ? this.log(data)
      : _actions.proxyRun(this, 'table', data)
  }

  /**
   * 打印纯对象数据
   *
   * @since 1.1.0
   *
   * @param {...*} args - 任意数据
   *
   * @returns {Logger}
   */
  dir(...args) {
    return _actions.proxyRun(this, 'dir', ...args)
  }

  /**
   * 打印纯对象数据
   *
   * @since 1.1.0
   *
   * @param {...*} args - 任意数据
   *
   * @returns {Logger}
   */
  dirxml(...args) {
    return _actions.proxyRun(this, 'dirxml', ...args)
  }

  /**
   * 创建一个组，接下来所有的打印内容，都会包裹在组内，直到调用groupEnd()方法结束，退出组
   *
   * @since 1.1.0
   *
   * @param {string} label - 标签名称
   *
   * @returns {Logger}
   */
  group(label) {
    return _actions.proxyRun(this, 'group', label)
  }

  /**
   * 类似group()方法，区别在于调用该方法后打印的内容都是折叠的，需要手动展开
   *
   * @since 1.1.0
   *
   * @param {string} label - 标签名称
   *
   * @returns {Logger}
   */
  groupCollapsed(label) {
    return _actions.proxyRun(this, 'groupCollapsed', label)
  }

  /**
   * 关闭组
   *
   * @since 1.1.0
   *
   * @returns {Logger}
   */
  groupEnd() {
    return _actions.proxyRun(this, 'groupEnd')
  }

  /**
   * 统计被执行的次数
   *
   * @since 1.1.0
   *
   * @param {string} label - 标签名称
   *
   * @returns {Logger}
   */
  count(label) {
    return _actions.proxyRun(this, 'count', label)
  }

  /**
   * 开始设置一个timer追踪操作任意的消耗时间，直到调用timeEnd()结束追踪，消耗时间单位为毫秒
   *
   * @since 1.1.0
   *
   * @param {string} label - 标签名称
   *
   * @returns {Logger}
   */
  time(label) {
    return _actions.proxyRun(this, 'time', label)
  }

  /**
   * 结束追踪
   *
   * @since 1.1.0
   *
   * @returns {Logger}
   */
  timeEnd() {
    return _actions.proxyRun(this, 'timeEnd')
  }

  /**
   * 结束追踪
   *
   * @since 1.1.0
   *
   * @returns {Logger}
   */
  timeStamp(...args) {
    return _actions.proxyRun(this, 'timeStamp', ...args)
  }

  /**
   * 开始记录一个性能分析简报，直到调用profileEnd()结束记录
   *
   * @since 1.1.0
   *
   * @param {string} label - 标签名称
   *
   * @returns {Logger}
   */
  profile(label) {
    return _actions.proxyRun(this, 'profile', label)
  }

  /**
   * 结束记录
   *
   * @since 1.1.0
   *
   * @returns {Logger}
   */
  profileEnd() {
    return _actions.proxyRun(this, 'profileEnd')
  }

  /**
   * 断言表达式，若结果为false，是抛出失败输出
   *
   * @since 1.1.0
   *
   * @param {boolean}  assertion - 表达式
   * @param {...*} args - 断言失败输出
   *
   * @returns {Logger}
   */
  assert(assertion, ...args) {
    return _actions.proxyRun(this, 'assert', assertion, ...args)
  }

  /**
   * 清空控制台
   *
   * @since 1.1.0
   *
   * @returns {Logger}
   */
  clear() {
    return _actions.proxyRun(this, 'clear')
  }
}

export default Logger
<commit_msg>docs: 更新jsdoc<commit_after>/**
 * @file 日志打印器
 * @author lisfan <goolisfan@gmail.com>
 * @version 1.3.2
 * @licence MIT
 */

import validation from '@~lisfan/validation'

/**
 * 从`localStorage`的`LOGGER_RULES`键中读取**打印规则**配置，以便可以在生产环境开启日志打印调试
 */
const LOGGER_RULES = JSON.parse(global.localStorage.getItem('LOGGER_RULES')) || {}

/**
 * 从`localStorage`的`IS_DEV`键中读取是否为**开发环境**配置，以便可以在生产环境开启日志打印调试
 */
const IS_DEV = JSON.parse(global.localStorage.getItem('IS_DEV')) || process.env.NODE_ENV === 'development'

// 私有方法
const _actions = {
  /**
   * 打印器工厂函数
   * 查找ls中是否存在打印命名空间配置项，若存在，则进行替换覆盖
   * 判断是否存在子命名空间，依次判断子命名空间的长度
   *
   * @since 1.3.0
   *
   * @param {Logger} self - Logger实例
   * @param {string} method - 打印方法
   * @param {string} color - 颜色值，web安全色 http://www.w3school.com.cn/tiy/color.asp?color=LightGoldenRodYellow
   *
   * @returns {function}
   */
  logFactory(self, method, color) {
    return (...args) => {
      return _actions.logProxyRun(self, method, color, ...args)
    }
  },
  /**
   * 代理运行打印方法
   *
   * @since 1.3.0
   *
   * @param {Logger} self - Logger实例
   * @param {string} method - 打印方法
   * @param {string} color - 打印颜色，颜色值，web安全色 http://www.w3school.com.cn/tiy/color.asp?color=LightGoldenRodYellow
   * @param {...*} args - 其他参数
   *
   * @returns {Logger}
   */
  logProxyRun(self, method, color, ...args) {
    // 处于非激活状态的话则不输出日志
    if (!self.isActivated(method)) {
      return self
    }

    let formatStr = `%c[${self.$name}]:%c`

    // 遍历参数列表，找出dom元素，进行转换
    args = args.map((arg) => {
      return validation.isElement(arg)
        ? [arg]
        : arg
    })

    /* eslint-disable no-console */
    console[method](formatStr, `color: ${color}`, '', ...args)
    /* eslint-enable no-console */

    return self
  },
  /**
   * 代理运行console方法
   * [注] 内部会进行判断是否允许日志输出
   *
   * @since 1.3.0
   *
   * @param {Logger} self - Logger实例
   * @param {string} method - 打印方法
   * @param {...*} args - 其他参数
   *
   * @returns {Logger}
   */
  proxyRun(self, method, ...args) {
    /* eslint-disable no-console */
    self.isActivated(method) && console[method](...args)
    /* eslint-enable no-console */

    return self
  }
}

/**
 * @classdesc 日志打印类
 *
 * @class
 */
class Logger {
  /**
   * 打印器命名空间规则配置项
   * - 可以配置整个命名空间是否输出日志
   * - 也可以配置命名空间下某个实例方法是否输出日志
   *
   * @since 1.2.0
   *
   * @static
   * @readonly
   * @memberOf Logger
   *
   * @type {object}
   * @property {object} rules - 打印器命名空间规则配置集合
   */
  static rules = LOGGER_RULES

  /**
   * 更改命名空间规则配置项
   * [注]从`localStorage`的`LOGGER_RULES`键中读取规则配置优先级最高，始终会覆盖其他规则
   *
   * @since 1.2.0
   *
   * @param {object} rules - 配置参数
   * @param {string} [rules.name] - 日志器命名空间
   * @param {boolean} [rules.debug] - 调试模式是否开启
   *
   * @returns {Logger}
   *
   * @example
   * // 定义规则
   * Logger.configRules = {
   *    utils-http:false // 整个utils-http不可打印输出
   *    utils-calc.log=true // utils-calc打印器的log方法不支持打印输出
   * }
   */
  static configRules(rules) {
    Logger.rules = {
      ...Logger.rules,
      ...rules,
      ...LOGGER_RULES,
    }

    return this
  }

  /**
   * 默认配置选项
   * 为了在生产环境能开启调试模式
   * 提供了从localStorage获取默认配置项的措施
   *
   * @since 1.0.0
   *
   * @static
   * @readonly
   * @memberOf Logger
   *
   * @type {object}
   * @property {string} name='logger' - 日志器命名空间，默认为'logger'
   * @property {boolean} debug=true - 调试模式是否开启，默认开启
   */
  static options = {
    name: 'logger',
    debug: true,
  }

  /**
   * 更新默认配置选项
   *
   * @since 1.0.0
   *
   * @see Logger.options
   *
   * @param {object} options - 配置选项见{@link Logger.options}
   *
   * @returns {Logger}
   */
  static config(options) {
    // 以内置配置为优先
    Logger.options = {
      ...Logger.options,
      ...options
    }

    return this
  }

  /**
   * 构造函数
   *
   * @see Logger.options
   *
   * @param {object} options - 配置选项见{@link Logger.options}，若参数为`string`类型，则表示设定为`options.name`的值
   */
  constructor(options) {
    this.$options = validation.isString(options)
      ? {
        ...Logger.options,
        name: options
      }
      : {
        ...Logger.options,
        ...options
      }
  }

  /**
   * 实例的配置项
   *
   * @since 1.0.0
   *
   * @readonly
   *
   * @type {object}
   */
  $options = undefined

  /**
   * 获取实例的命名空间配置项
   *
   * @since 1.1.0
   *
   * @getter
   * @readonly
   *
   * @type {string}
   */
  get $name() {
    return this.$options.name
  }

  /**
   * 获取实例的调试模式配置项
   *
   * @since 1.1.0
   *
   * @getter
   * @readonly
   *
   * @type {boolean}
   */
  get $debug() {
    return this.$options.debug
  }

  /**
   * 检测当前是否调试模式是否激活：可以打印日志
   *
   * @since 1.1.0
   *
   * @param {string} [method] - 若指定了该参数，则精确检测具体的实例方法
   *
   * @returns {boolean}
   */
  isActivated(method) {
    // 如果不是开发模式
    if (!IS_DEV) {
      return false
    }

    // 以子命名空间的状态优先
    let status = Logger.rules[this.$name]
    // 先判断其子命名空间的状态

    // 如果存在放法名，则判断子命名空间
    // 当前方法名存在子命名空间里且明确设置为false时，则不打印
    // 当前子命名空间如果明确false，则不打印
    if (method) {
      const subStatus = Logger.rules[`${this.$name}.${method}`]

      if (validation.isBoolean(subStatus)) status = subStatus
    }

    // 如果明确指定该命名空间不开启日志打印，则不打印
    if (status === false) {
      return false
    }

    // 最后才判断实例是否禁用了调试
    if (!this.$debug) {
      return false
    }

    return true
  }

  /**
   * 创建一个指定颜色的打印方法
   *
   * @since 1.1.0
   *
   * @param {string} color - 颜色值
   *
   * @returns {Function}
   */
  color(color) {
    return _actions.logFactory(this, 'log', `${color}`)
  }

  /**
   * 启用日志输出
   *
   * @since 1.1.0
   *
   * @returns {Logger}
   */
  enable() {
    this.$options.debug = true

    return this
  }

  /**
   * 禁用日志输出
   *
   * @since 1.1.0
   *
   * @returns {Logger}
   */
  disable() {
    this.$options.debug = false

    return this
  }

  /**
   * 常规日志打印
   *
   * @since 1.0.0
   *
   * @param {...*} args - 任意数据
   *
   * @returns {Logger}
   */
  log(...args) {
    return _actions.logProxyRun(this, 'log', 'lightseagreen', ...args)
  }

  /**
   * 警告日志打印
   *
   * @since 1.0.0
   *
   * @param {...*} args - 任意数据
   *
   * @returns {Logger}
   */
  warn(...args) {
    return _actions.logProxyRun(this, 'warn', 'goldenrod', ...args)
  }

  /**
   * 调用栈日志打印
   *
   * @since 1.0.1
   *
   * @param {...*} args - 任意数据
   *
   * @returns {Logger}
   */
  trace(...args) {
    return _actions.logProxyRun(this, 'trace', 'lightseagreen', ...args)
  }

  /**
   * 错误日志打印，同时会抛出错误，阻塞后续逻辑
   *
   * @since 1.0.0
   *
   * @param {...*} args - 参数列表
   *
   * @throws Error - 抛出错误提示
   */
  error(...args) {
    const message = args.map((value) => {
      return value.toString()
    }).join(' ')

    throw new Error(message)
  }

  /**
   * log的同名方法，使用方法请参考{@link Logger#log}
   *
   * @since 1.1.0
   *
   * @see Logger#log
   *
   * @param {...*} args - 任意数据
   *
   * @returns {Logger}
   */
  info(...args) {
    return this.log(...args)
  }

  /**
   * log的同名方法，使用方法请参考{@link Logger#log}
   *
   * @since 1.1.0
   *
   * @see Logger#log
   *
   * @param {...*} args - 任意数据
   *
   * @returns {Logger}
   */
  debug(...args) {
    return this.log(...args)
  }

  /**
   * 区别于console.table
   * - 对象或数组类型数据以表格的方式打印
   * - 若非这两种数据类型，则调用log方法打印
   *
   * @since 1.1.0
   *
   * @param {*} data - 任意数据
   *
   * @returns {Logger}
   */
  table(data) {
    return validation.isArray(data) && validation.isPlainObject(data)
      ? this.log(data)
      : _actions.proxyRun(this, 'table', data)
  }

  /**
   * 打印纯对象数据
   *
   * @since 1.1.0
   *
   * @param {...*} args - 任意数据
   *
   * @returns {Logger}
   */
  dir(...args) {
    return _actions.proxyRun(this, 'dir', ...args)
  }

  /**
   * 打印纯对象数据
   *
   * @since 1.1.0
   *
   * @param {...*} args - 任意数据
   *
   * @returns {Logger}
   */
  dirxml(...args) {
    return _actions.proxyRun(this, 'dirxml', ...args)
  }

  /**
   * 创建一个组，接下来所有的打印内容，都会包裹在组内，直到调用groupEnd()方法结束，退出组
   *
   * @since 1.1.0
   *
   * @param {string} label - 标签名称
   *
   * @returns {Logger}
   */
  group(label) {
    return _actions.proxyRun(this, 'group', label)
  }

  /**
   * 类似group()方法，区别在于调用该方法后打印的内容都是折叠的，需要手动展开
   *
   * @since 1.1.0
   *
   * @param {string} label - 标签名称
   *
   * @returns {Logger}
   */
  groupCollapsed(label) {
    return _actions.proxyRun(this, 'groupCollapsed', label)
  }

  /**
   * 关闭组
   *
   * @since 1.1.0
   *
   * @returns {Logger}
   */
  groupEnd() {
    return _actions.proxyRun(this, 'groupEnd')
  }

  /**
   * 统计被执行的次数
   *
   * @since 1.1.0
   *
   * @param {string} label - 标签名称
   *
   * @returns {Logger}
   */
  count(label) {
    return _actions.proxyRun(this, 'count', label)
  }

  /**
   * 开始设置一个timer追踪操作任意的消耗时间，直到调用timeEnd()结束追踪，消耗时间单位为毫秒
   *
   * @since 1.1.0
   *
   * @param {string} label - 标签名称
   *
   * @returns {Logger}
   */
  time(label) {
    return _actions.proxyRun(this, 'time', label)
  }

  /**
   * 结束追踪
   *
   * @since 1.1.0
   *
   * @returns {Logger}
   */
  timeEnd() {
    return _actions.proxyRun(this, 'timeEnd')
  }

  /**
   * 结束追踪
   *
   * @since 1.1.0
   *
   * @returns {Logger}
   */
  timeStamp(...args) {
    return _actions.proxyRun(this, 'timeStamp', ...args)
  }

  /**
   * 开始记录一个性能分析简报，直到调用profileEnd()结束记录
   *
   * @since 1.1.0
   *
   * @param {string} label - 标签名称
   *
   * @returns {Logger}
   */
  profile(label) {
    return _actions.proxyRun(this, 'profile', label)
  }

  /**
   * 结束记录
   *
   * @since 1.1.0
   *
   * @returns {Logger}
   */
  profileEnd() {
    return _actions.proxyRun(this, 'profileEnd')
  }

  /**
   * 断言表达式，若结果为false，是抛出失败输出
   *
   * @since 1.1.0
   *
   * @param {boolean}  assertion - 表达式
   * @param {...*} args - 断言失败输出
   *
   * @returns {Logger}
   */
  assert(assertion, ...args) {
    return _actions.proxyRun(this, 'assert', assertion, ...args)
  }

  /**
   * 清空控制台
   *
   * @since 1.1.0
   *
   * @returns {Logger}
   */
  clear() {
    return _actions.proxyRun(this, 'clear')
  }
}

export default Logger
<|endoftext|>


<commit_before>var Color = require('./colorize');
Level = {
  ERROR: 1,
  WARN: 2,
  INFO: 3,
  DEBUG: 4
};

var Logger = function() {
  this.level = Level.INFO;
  if (arguments.length > 0) {
    this.setLevel.apply(this, arguments);
  }
};

Logger.prototype.setLevel = function (logLevel) {
  switch (logLevel) {
    case 'error':
      this.level = Level.ERROR;
      break;
    case 'warn':
      this.level = Level.WARN;
      break;
    case 'info':
      this.level = Level.INFO;
      break;
    case 'debug':
      this.level = Level.DEBUG;
      break;
    default:
      console.warn('Unknown Log Level, Setting level to INFO');
      this.level = Level.INFO;
  }
}

Logger.prototype.debug = function () {
  Array.prototype.unshift.call(arguments, Level.DEBUG);
  this.log.apply(this, arguments);
}

Logger.prototype.info = function () {
  Array.prototype.unshift.call(arguments, Level.INFO);
  this.log.apply(this, arguments);
}

Logger.prototype.error = function () {
  Array.prototype.unshift.call(arguments, Level.ERROR);
  this.log.apply(this, arguments);
}

Logger.prototype.warn = function () {
  Array.prototype.unshift.call(arguments, Level.WARN);
  this.log.apply(this, arguments);
}

Logger.prototype.log = function () {
  var level = arguments[0];
  var messages = Array.prototype.slice.call(arguments, 1);
  if (messages.length == 1 && messages[0] === 'false') {
    return;
  }
  if (level <= this.level) {
    switch (level) {
      case Level.ERROR:
        console.error(Color.red('ERROR:    '), this.formatLines(messages).join(' '));
        break;
      case Level.WARN:
        console.warn(Color.yellow('WARN:     '), this.formatLines(messages).join(' '));
        break;
      case Level.DEBUG:
        console.warn('DEBUG:    ', this.formatLines(messages).join(' '));
        break;
      case Level.INFO:
        console.log('INFO:     ', this.formatLines(messages).join(' '));
        break;
    }
  }
}

Logger.prototype.formatLines = function (lines) {
  var newLines = [];
  for (var index = 0; index < lines.length; index++) {
    var multiline = lines[index].toString().split('\n');
    for (var subindex = 0; subindex < multiline.length; subindex++) {
      var prefix = subindex == 0 ? '' : '          ';
      var suffix = multiline.length > 1 ? '\n' : '';
      newLines.push(prefix + multiline[subindex] + suffix);
    }
  }
  return newLines;
}

module.exports = Logger
<commit_msg>Colorize Debug & Info Lines<commit_after>var Color = require('./colorize');
Level = {
  ERROR: 1,
  WARN: 2,
  INFO: 3,
  DEBUG: 4
};

var Logger = function() {
  this.level = Level.INFO;
  if (arguments.length > 0) {
    this.setLevel.apply(this, arguments);
  }
};

Logger.prototype.setLevel = function (logLevel) {
  switch (logLevel) {
    case 'error':
      this.level = Level.ERROR;
      break;
    case 'warn':
      this.level = Level.WARN;
      break;
    case 'info':
      this.level = Level.INFO;
      break;
    case 'debug':
      this.level = Level.DEBUG;
      break;
    default:
      console.warn('Unknown Log Level, Setting level to INFO');
      this.level = Level.INFO;
  }
}

Logger.prototype.debug = function () {
  Array.prototype.unshift.call(arguments, Level.DEBUG);
  this.log.apply(this, arguments);
}

Logger.prototype.info = function () {
  Array.prototype.unshift.call(arguments, Level.INFO);
  this.log.apply(this, arguments);
}

Logger.prototype.error = function () {
  Array.prototype.unshift.call(arguments, Level.ERROR);
  this.log.apply(this, arguments);
}

Logger.prototype.warn = function () {
  Array.prototype.unshift.call(arguments, Level.WARN);
  this.log.apply(this, arguments);
}

Logger.prototype.log = function () {
  var level = arguments[0];
  var messages = Array.prototype.slice.call(arguments, 1);
  if (messages.length == 1 && messages[0] === 'false') {
    return;
  }
  if (level <= this.level) {
    switch (level) {
      case Level.ERROR:
        console.error(Color.red('ERROR:    '), this.formatLines(messages).join(' '));
        break;
      case Level.WARN:
        console.warn(Color.yellow('WARN:     '), this.formatLines(messages).join(' '));
        break;
      case Level.DEBUG:
        console.warn(Color.blue('DEBUG:    '), this.formatLines(messages).join(' '));
        break;
      case Level.INFO:
        console.log(Color.blue('INFO:     '), this.formatLines(messages).join(' '));
        break;
    }
  }
}

Logger.prototype.formatLines = function (lines) {
  var newLines = [];
  for (var index = 0; index < lines.length; index++) {
    var multiline = lines[index].toString().split('\n');
    for (var subindex = 0; subindex < multiline.length; subindex++) {
      var prefix = subindex == 0 ? '' : '          ';
      var suffix = multiline.length > 1 ? '\n' : '';
      newLines.push(prefix + multiline[subindex] + suffix);
    }
  }
  return newLines;
}

module.exports = Logger
<|endoftext|>


<commit_before>

//----------------------------------------------------------------
// The imports
//----------------------------------------------------------------

/**
 * Colors
 *
 * @type {Object}
 */
let colors = require('colors/safe');

/**
 * Table
 * @type {Function}
 */
let Table = require('cli-table');

//================================================================
// The logger
//================================================================

/**
 * The logger.
 *
 * @type {Object}
 */
let logger = {

	/**
	 * Create a template processing log.
	 *
	 * @return {Object} The template processing log.
	 */
	createTemplateProcessingLog: function createTemplateProcessingLog() {
		return new TemplateProcessingLog();
	},

};

//----------------------------------------------------------------
// The template processing log
//----------------------------------------------------------------

/**
 * The TemplateProcessingLog type
 *
 */

/**
 * Create a template processing log.
 *
 * @constructor
 */
function TemplateProcessingLog() {
	this.templateFileLogs = [];
}

/**
 * Create and add a template file log.
 *
 * @param  {string} src    The source template file.
 * @param  {string} target The compiled target file.
 *
 * @return {Object}        The template file log.
 */
TemplateProcessingLog.prototype.addTemplateFileLog = function addTemplateFileLog(src, target) {
	var templateFileLog = new TemplateFileLog(src, target);
	this.templateFileLogs.push(templateFileLog);
	return templateFileLog;
};

/**
 * Return a string representing the template processing log.
 *
 * @return {string} The string representing the template processing log.
 */
TemplateProcessingLog.prototype.toString = function toString() {
	let page = new Table({
		chars: {
			'top-mid': '',
			'left-mid': '',
			'right-mid': '',
			'bottom-mid': '',
			'mid': '',
			'middle': '',
			'mid-mid': '',
		},
		style: {},
	});
	page.push([
		colors.bold('Template processing'.toUpperCase())
	]);
	if (this.templateFileLogs.length) {
		for (var i = 0; i < this.templateFileLogs.length; ++i) {
			page.push(['']);
			page.push([
				this.templateFileLogs[i].toString()
			]);
		}
	}
	else {
		page.push(['']);
		page.push(['No template file.']);
	}
	return page.toString();
};

/**
 * Print the template processing log to console.
 *
 */
TemplateProcessingLog.prototype.print = function print() {
	console.log('');
	console.log(this.toString());
	console.log('');
};

/**
 * The TemplateFileLog type
 *
 */

/**
 * Create a template file log.
 *
 * @constructor
 *
 * @param       {string} src    The source template file.
 * @param       {string} target The compiled target file.
 */
function TemplateFileLog(src, target) {
	this.templateFile = {
		source: src,
		target: target
	};
	this.isCompilationPerfect = true;
	this.templateTagLogs = new Table({
		chars: {
			'top-mid': '',
			'bottom-mid': '',
			'middle': '',
			'mid-mid': '',
		},
		style: {},
	});
}

/**
 * Add a template tag log.
 *
 * @param {string} tag      The template tag.
 * @param {string} [result] The compiled tag.
 */
TemplateFileLog.prototype.addTemplateTagLog = function addTemplateTagLog(tag, result) {
	let templateTagLog = new TemplateTagLog(tag, result);
	this.isCompilationPerfect = this.isCompilationPerfect && templateTagLog.isCompiled();
	this.templateTagLogs.push(
		templateTagLog.toTableRow()
	);
};

/**
 * Return a string representing the template file log.
 *
 * @return {string} The string representing the template file log.
 */
TemplateFileLog.prototype.toString = function toString() {
	let block = new Table({
		chars: {
			'top-mid': '',
			'left-mid': '',
			'right-mid': '',
			'bottom-mid': '',
			'mid': '',
			'middle': '',
			'mid-mid': '',
		},
		style: {},
	});
	let color = this.isCompilationPerfect ? 'green' : 'magenta';
	block.push(['Source: ' + colors[color].bold(this.templateFile.source)]);
	block.push(['Target: ' + colors[color].bold(this.templateFile.target)]);
	block.push([this.templateTagLogs.toString()]);
	return block.toString();
};

/**
 * The TemplateTagLog type
 *
 */

/**
 * Create a template tag log.
 *
 * @constructor
 *
 * @param       {string} tag      The template tag.
 * @param       {string} [result] The compiled tag.
 */
function TemplateTagLog(tag, result) {
	this.templateTag = tag;
	this.compiledTag = result;
}

/**
 * Determine whether the template tag is compiled or not.
 *
 * @return {boolean} True if the template tag is compiled, otherwise false.
 */
TemplateTagLog.prototype.isCompiled = function isCompiled() {
	return typeof this.compiledTag !== 'undefined';
};

/**
 * Return a table row representing the template tag log.
 *
 * @return {string[]} The table row representing the template tag log.
 */
TemplateTagLog.prototype.toTableRow = function toTableRow() {
	if (this.isCompiled()) {
		return [
			colors.blue.bold('' + this.templateTag),
			' -> ',
			colors.green.bold('' + this.compiledTag),
		];
	}
	return [
		colors.magenta.bold('' + this.templateTag),
		'',
		'',
	];
};

//----------------------------------------------------------------
// The exports
//----------------------------------------------------------------

/**
 * The logger.
 *
 * @type {Object}
 */
module.exports = logger;
<commit_msg>Add a timestamp to the logging of the template processing<commit_after>

//----------------------------------------------------------------
// The imports
//----------------------------------------------------------------

/**
 * Colors
 *
 * @type {Object}
 */
let colors = require('colors/safe');

/**
 * Table
 * @type {Function}
 */
let Table = require('cli-table');

//================================================================
// The logger
//================================================================

/**
 * The logger.
 *
 * @type {Object}
 */
let logger = {

	/**
	 * Create a template processing log.
	 *
	 * @return {Object} The template processing log.
	 */
	createTemplateProcessingLog: function createTemplateProcessingLog() {
		return new TemplateProcessingLog();
	},

};

//----------------------------------------------------------------
// The template processing log
//----------------------------------------------------------------

/**
 * The TemplateProcessingLog type
 *
 */

/**
 * Create a template processing log.
 *
 * @constructor
 */
function TemplateProcessingLog() {
	this.templateFileLogs = [];
}

/**
 * Create and add a template file log.
 *
 * @param  {string} src    The source template file.
 * @param  {string} target The compiled target file.
 *
 * @return {Object}        The template file log.
 */
TemplateProcessingLog.prototype.addTemplateFileLog = function addTemplateFileLog(src, target) {
	var templateFileLog = new TemplateFileLog(src, target);
	this.templateFileLogs.push(templateFileLog);
	return templateFileLog;
};

/**
 * Return a string representing the template processing log.
 *
 * @return {string} The string representing the template processing log.
 */
TemplateProcessingLog.prototype.toString = function toString() {
	let page = new Table({
		chars: {
			'top-mid': '',
			'left-mid': '',
			'right-mid': '',
			'bottom-mid': '',
			'mid': '',
			'middle': '',
			'mid-mid': '',
		},
		style: {},
	});
	page.push([
		colors.bold('Template processing'.toUpperCase())
	]);
	page.push([
		new Date().toLocaleString()
	]);
	if (this.templateFileLogs.length) {
		for (var i = 0; i < this.templateFileLogs.length; ++i) {
			page.push(['']);
			page.push([
				this.templateFileLogs[i].toString()
			]);
		}
	}
	else {
		page.push(['']);
		page.push(['No template file.']);
	}
	return page.toString();
};

/**
 * Print the template processing log to console.
 *
 */
TemplateProcessingLog.prototype.print = function print() {
	console.log('');
	console.log(this.toString());
	console.log('');
};

/**
 * The TemplateFileLog type
 *
 */

/**
 * Create a template file log.
 *
 * @constructor
 *
 * @param       {string} src    The source template file.
 * @param       {string} target The compiled target file.
 */
function TemplateFileLog(src, target) {
	this.templateFile = {
		source: src,
		target: target
	};
	this.isCompilationPerfect = true;
	this.templateTagLogs = new Table({
		chars: {
			'top-mid': '',
			'bottom-mid': '',
			'middle': '',
			'mid-mid': '',
		},
		style: {},
	});
}

/**
 * Add a template tag log.
 *
 * @param {string} tag      The template tag.
 * @param {string} [result] The compiled tag.
 */
TemplateFileLog.prototype.addTemplateTagLog = function addTemplateTagLog(tag, result) {
	let templateTagLog = new TemplateTagLog(tag, result);
	this.isCompilationPerfect = this.isCompilationPerfect && templateTagLog.isCompiled();
	this.templateTagLogs.push(
		templateTagLog.toTableRow()
	);
};

/**
 * Return a string representing the template file log.
 *
 * @return {string} The string representing the template file log.
 */
TemplateFileLog.prototype.toString = function toString() {
	let block = new Table({
		chars: {
			'top-mid': '',
			'left-mid': '',
			'right-mid': '',
			'bottom-mid': '',
			'mid': '',
			'middle': '',
			'mid-mid': '',
		},
		style: {},
	});
	let color = this.isCompilationPerfect ? 'green' : 'magenta';
	block.push(['Source: ' + colors[color].bold(this.templateFile.source)]);
	block.push(['Target: ' + colors[color].bold(this.templateFile.target)]);
	block.push([this.templateTagLogs.toString()]);
	return block.toString();
};

/**
 * The TemplateTagLog type
 *
 */

/**
 * Create a template tag log.
 *
 * @constructor
 *
 * @param       {string} tag      The template tag.
 * @param       {string} [result] The compiled tag.
 */
function TemplateTagLog(tag, result) {
	this.templateTag = tag;
	this.compiledTag = result;
}

/**
 * Determine whether the template tag is compiled or not.
 *
 * @return {boolean} True if the template tag is compiled, otherwise false.
 */
TemplateTagLog.prototype.isCompiled = function isCompiled() {
	return typeof this.compiledTag !== 'undefined';
};

/**
 * Return a table row representing the template tag log.
 *
 * @return {string[]} The table row representing the template tag log.
 */
TemplateTagLog.prototype.toTableRow = function toTableRow() {
	if (this.isCompiled()) {
		return [
			colors.blue.bold('' + this.templateTag),
			' -> ',
			colors.green.bold('' + this.compiledTag),
		];
	}
	return [
		colors.magenta.bold('' + this.templateTag),
		'',
		'',
	];
};

//----------------------------------------------------------------
// The exports
//----------------------------------------------------------------

/**
 * The logger.
 *
 * @type {Object}
 */
module.exports = logger;
<|endoftext|>


<commit_before>Vue.filter("itemURL", function(item)
{

    var urlContent = item.itemDescription.urlContent.split("/");
    var i          = urlContent.length - 1;

    return "/" + urlContent[i] + "/" + item.itemBase.id + "/" + item.variationBase.id;

});
<commit_msg>FIX itemURL filter for items not having a URLContent<commit_after>Vue.filter("itemURL", function(item)
{

    var urlContent = item.itemDescription.urlContent.split("/");
    var i          = urlContent.length - 1;

    if (urlContent[i].length > 0)
    {
        return "/" + urlContent[i] + "/" + item.itemBase.id + "/" + item.variationBase.id;
    }
    return "/" + item.itemBase.id + "/" + item.variationBase.id;

});
<|endoftext|>


<commit_before>'use strict';

var fs, parse, Language, self;

fs = require('fs');
parse = require('csv-parse');
Language = require('../models/language.js');

self = module.exports = {
  getLanguages: function (req, res, next) {
    Language.find({'name': /.*/},
      function (err, languages) {
        if (err) {
          req.flash('adminMsg', err);
          res.redirect('/');

        } else {
          if (!languages) {
            req.flash('adminMsg', 'No languages found.');
            res.redirect('/');

         } else {
            res.render('languages.ejs', {
              languages: languages,
              title: 'Languages that Have Modules',
              message: req.flash('langMsg')
           });
          }
        }
    });
  },
  addLanguage: function(req, res, next) {
    var form,langName, lessons;

    form = req.body;
    langName = form.name;

    section = form['x-coord'];
    y = form['y-coord'];
    locationTitle = form.title;
    locationId = locationTitle.toLowerCase();
    descriptionText = form.description;
    linkUrl = form['link-url'];
    linkText = form['link-text'];
    category = form.category;
    imgNames = form.images;

    // Images need to be in form of an array
    if (typeof imgNames === 'string') {
      if (imgNames === '') {
        imgNames = [];
      } else {
        imgNames = [imgNames];
      }
    }

    newLocation = {
      id: locationId,
      title: locationTitle,
      description: {
        images: imgNames,
        text: descriptionText,
        link: {
          text: linkText,
          url: linkUrl
        }
      },
      category: category,
      x: x,
      y: y,
      pin: 'circular',
      fill: 'red'
    };

    Mapa.findOne({'id': mapId},
      function (err, map) {
        if (err) {
          req.flash('mapMsg', err);
          res.redirect('/admin/mapas/' + mapId);

        } else {
          if (!map) {
            req.flash('mapMsg', 'No se encontró ese mapa.');
            res.redirect('/admin/mapas');

          } else {
            map.locations.push(newLocation);

            map.save(function(err) {
              if (err) {
                req.flash('mapMsg', err);
                res.redirect('/admin/mapas/' + mapId + '/puntos/agregar');

              } else {
                req.flash('mapMsg', 'Se agregó el punto nuevo.');
                res.redirect('/admin/mapas/' + mapId);
              }
            });
          }
        }
    });
  },
  getModules: function (req, res, next) {
    var langName, modules, modulesLength, i, module;

    langName = req.eduLanguage;
    // descArray = [];

    Language.findOne({'name': langName}, function (err, language) {
      if (err) {
        req.flash('langMsg', err);
        res.redirect('/admin/languages');

      } else {
        if (!language) {
          req.flash('langMsg', 'Language not found.');
          res.redirect('/admin/languages');
        } else {

          // Build description string from location description object,
          // so it will play nice with mapplic plugin
          modules = language.modules;
          // modulesLength = modules.length;

          // for (i = 0; i < modulesLength; i++) {
          //   module = modules[i];
            // descString = '
';
            // desc = location.description;
            // imgs = desc.images;
            // imgsLength = imgs.length;

            // for (j = 0; j < imgsLength; j++) {
            //   descString += '';
            // }

            // descString += '
' + desc.text;

            // if (desc.link) {
            //   descString += ' ' + desc.link.text + '
';
            // } else {
            //   descString += '
';
            // }

            // map.locations[i].description = descString;
          // }

          // Object formatted according to mapplic
          // mapplicObj = {
          //   mapwidth: 640,
          //   mapheight: 600,
          //   categories: [
          //     {
          //       id: 'naturaleza',
          //       title: 'Naturaleza',
          //       color: '#4cd3b8',
          //       show: true
          //     },
          //     {
          //       id: 'servicios',
          //       title: 'Servicios',
          //       color: '#80D316',
          //       show: true
          //     },
          //     {
          //       id: 'ciudades',
          //       title: 'Ciudades',
          //       color: '#63aa9c',
          //       show: true
          //     }
          //   ],
          //   levels: [map]
          // };

          res.render('modules.ejs', {
            modules: modules,
            title: 'Available Learning Modules',
            message: req.flash('moduleMsg')
          });
        }
      }
    });//.lean(); //'lean' so Mongoose returns raw JS object, which can be modified
  },
  addModule: function (req, res, next) {
    var moduleName, form, section, lessons;

    moduleName = req.eduModule;
    form = req.body;
    section = form['x-coord'];
    y = form['y-coord'];
    locationTitle = form.title;
    locationId = locationTitle.toLowerCase();
    descriptionText = form.description;
    linkUrl = form['link-url'];
    linkText = form['link-text'];
    category = form.category;
    imgNames = form.images;

    // Images need to be in form of an array
    if (typeof imgNames === 'string') {
      if (imgNames === '') {
        imgNames = [];
      } else {
        imgNames = [imgNames];
      }
    }

    newLocation = {
      id: locationId,
      title: locationTitle,
      description: {
        images: imgNames,
        text: descriptionText,
        link: {
          text: linkText,
          url: linkUrl
        }
      },
      category: category,
      x: x,
      y: y,
      pin: 'circular',
      fill: 'red'
    };

    Mapa.findOne({'id': mapId},
      function (err, map) {
        if (err) {
          req.flash('mapMsg', err);
          res.redirect('/admin/mapas/' + mapId);

        } else {
          if (!map) {
            req.flash('mapMsg', 'No se encontró ese mapa.');
            res.redirect('/admin/mapas');

          } else {
            map.locations.push(newLocation);

            map.save(function(err) {
              if (err) {
                req.flash('mapMsg', err);
                res.redirect('/admin/mapas/' + mapId + '/puntos/agregar');

              } else {
                req.flash('mapMsg', 'Se agregó el punto nuevo.');
                res.redirect('/admin/mapas/' + mapId);
              }
            });
          }
        }
    });
  },
  getLocation: function (req, res, next) {
    var mapId, locationId, i, thisLocation;

    mapId = req.map;
    locationId = req.location;

    Mapa.findOne({'id': mapId}, function(err, map) {
      if (err) {
        req.flash('mapMsg', err);
        res.redirect('/admin/mapas');

      } else {
        if (!map) {
          req.flash('mapMsg', 'No se encontró el mapa.');
          res.redirect('/admin/mapas');

        } else {
          i = 0;
          while (map.locations[i].id !== locationId &&
            i < map.locations.length) {
            i++
          }

          thisLocation = map.locations[i];

          res.render('admin-punto-editar.ejs', {
            title: 'Editar punto',
            x: thisLocation.x,
            y: thisLocation.y,
            locationTitle: thisLocation.title,
            description: thisLocation.description.text,
            linkText: thisLocation.description.link.text,
            linkUrl: thisLocation.description.link.url,
            category: thisLocation.category,
            images: thisLocation.description.images
          });
        }
      }
    });
  },
  editLocation: function (req, res, next) {
    var mapId, locationId, form, locationTitle, newLocationId, descriptionText,
      linkUrl, linkText, category, imgNames, keyArray, key, keyString, i,
      modifyLocation, x, y, locationImages, j, removed, k;

    mapId = req.map;
    locationId = req.location;
    form = req.body;
    locationTitle = form.title;
    newLocationId = locationTitle.toLowerCase();
    descriptionText = form.description;
    linkUrl = form['link-url'];
    linkText = form['link-text'];
    category = form.category;
    imgNames = form.images;

    // Images need to be in form of an array
    if (typeof imgNames === 'string') {
      if (imgNames === '') {
        imgNames = [];
      } else {
        imgNames = [imgNames];
      }
    }

    keyArray = [];

    // Create array of checked image names to remove from location images
    for (key in form) {
      if (key.search('remove-') >= 0) {
        keyString = key.slice(7);
        keyArray.push(keyString);
      }
    }

    Mapa.findOne({'id': mapId},
      function (err, map) {
        if (err) {
          req.flash('mapMsg', err);
          res.redirect('/admin/mapas');

        } else {
          if (!map) {
            req.flash('mapMsg', 'No se encontró ese mapa.');
            res.redirect('/admin/mapas');

          } else {
            i = 0;
            while (map.locations[i].id !== locationId &&
              i < map.locations.length) {
              i++
            }

            modifyLocation = map.locations[i];

            x = modifyLocation.x
            y = modifyLocation.y
            locationImages = modifyLocation.description.images;

            for (j = 0; j < locationImages.length; j++) {
              removed = false

              // Check location images array for removed images
              for (k = 0; k < keyArray.length; k++) {
                if (keyArray[k] === locationImages[j]) {
                  keyArray.splice(k, 1);
                  k--;
                  removed = true
                }
              }

              // If an image wasn't removed, add it to the new images array
              if (!removed) {imgNames.push(locationImages[j]);}
            }

            // Modifying location object with dot notation, because Mongoose
            // doesn't like literal notation
            modifyLocation.id = newLocationId;
            modifyLocation.title = locationTitle;
            modifyLocation.category = category;
            modifyLocation.description.images = imgNames;
            modifyLocation.description.text = descriptionText;
            modifyLocation.description.link.text = linkText;
            modifyLocation.description.link.url = linkUrl;

            map.save(function(err) {
              if (err) {
                req.flash('mapMsg', err);
                res.redirect('/admin/mapas/' + mapId + '/puntos/' +
                  locationId + '/editar');

              } else {
                req.flash('mapMsg', 'Se revisó el punto.');
                res.redirect('/admin/mapas/' + mapId);
              }
            });
          }
        }
    });
  },
  removeLocation: function (req, res, next) {
    var mapId, locId, i, locationsLength;

    mapId = req.map;
    locId = req.location;

    Mapa.findOne({'id': mapId},
      function (err, map) {
        if (err) {
          req.flash('mapMsg', err);
          res.redirect('/admin/mapas/' + mapId);

        } else {
          if (!map) {
            req.flash('mapMsg', 'No se encontró ese mapa.');
            res.redirect('/admin/mapas');

          } else {
            i = 0;
            while (map.locations[i].id !== locId && i < map.locations.length) {
              i++;
            }
            map.locations[i].remove();

            map.save(function(err) {
              if (err) {
                req.flash('mapMsg', err);
                res.redirect('/admin/mapas/' + mapId);

              } else {
                req.flash('mapMsg', 'Se borró el punto.');
                res.redirect('/admin/mapas/' + mapId);
              }
            });
          }
        }
    });
  },
  uploadData: function(req, res, next) {
    var parser, i, thisData, langName, thisSection, thisModule, langObject,
      langArray, modules, moduleLength, j, match, item;

    langObject = {};
    langArray = [];

    parser = parse({delimiter: ',', columns: true}, function(err, data){

      for (i = 0; i < data.length; i++) {
        thisData = data[i];
        langName = thisData.language-name;
        thisSection = thisData.module-section;
        thisModule = {
          index: thisData.module-index,
          section: thisSection,
          reception: {text: thisData.reception-text},
          textInput: {
            options: [{
              text: thisData.textInput-option-text,
              correct: thisData.textInput-option-correct
            }]
          },
          voiceInput: {text: thisData.voiceInput-text}
        };

        if (langObject[langName]) {
          if (langObject[langName][thisSection]) {
            modules = langObject[langName][thisSection];
            moduleLength = modules.length;

            for (j = 0; j < moduleLength; j++) {
              match = false;

              if (modules[j].index === thisModule.index) {
                langObject[langName][thisSection][j].options.push(thisModule.options[0]);
                match = true;
                break;
              }
            }

            if (!match) {
              langObject[langName][thisSection].push(thisModule);
            }

          } else {
            langObject[langName][thisSection] = [thisModule];
          }

        } else {
          langObject[langName] = {name: langName};
          langObject[langName][thisSection] = [thisModule];
        }
      }

      for (item in langObject) {
        langArray.push(langObject[item]);
      }

      Language.create(langArray, function(err, languages) {
        if (err) {
          console.log(err);
        }

        console.log(languages);
      });

      res.send('uploaded');
    });

    fs.createReadStream(__dirname + '/model-data.csv').pipe(parser);
  }
};<commit_msg>debug data upload<commit_after>'use strict';

var fs, parse, Language, self;

fs = require('fs');
parse = require('csv-parse');
Language = require('../models/language.js');

self = module.exports = {
  getLanguages: function (req, res, next) {
    Language.find({'name': /.*/},
      function (err, languages) {
        if (err) {
          req.flash('adminMsg', err);
          res.redirect('/');

        } else {
          if (!languages) {
            req.flash('adminMsg', 'No languages found.');
            res.redirect('/');

         } else {
            res.render('languages.ejs', {
              languages: languages,
              title: 'Languages that Have Modules',
              message: req.flash('langMsg')
           });
          }
        }
    });
  },
  addLanguage: function(req, res, next) {
    var form,langName, lessons;

    form = req.body;
    langName = form.name;

    section = form['x-coord'];
    y = form['y-coord'];
    locationTitle = form.title;
    locationId = locationTitle.toLowerCase();
    descriptionText = form.description;
    linkUrl = form['link-url'];
    linkText = form['link-text'];
    category = form.category;
    imgNames = form.images;

    // Images need to be in form of an array
    if (typeof imgNames === 'string') {
      if (imgNames === '') {
        imgNames = [];
      } else {
        imgNames = [imgNames];
      }
    }

    newLocation = {
      id: locationId,
      title: locationTitle,
      description: {
        images: imgNames,
        text: descriptionText,
        link: {
          text: linkText,
          url: linkUrl
        }
      },
      category: category,
      x: x,
      y: y,
      pin: 'circular',
      fill: 'red'
    };

    Mapa.findOne({'id': mapId},
      function (err, map) {
        if (err) {
          req.flash('mapMsg', err);
          res.redirect('/admin/mapas/' + mapId);

        } else {
          if (!map) {
            req.flash('mapMsg', 'No se encontró ese mapa.');
            res.redirect('/admin/mapas');

          } else {
            map.locations.push(newLocation);

            map.save(function(err) {
              if (err) {
                req.flash('mapMsg', err);
                res.redirect('/admin/mapas/' + mapId + '/puntos/agregar');

              } else {
                req.flash('mapMsg', 'Se agregó el punto nuevo.');
                res.redirect('/admin/mapas/' + mapId);
              }
            });
          }
        }
    });
  },
  getModules: function (req, res, next) {
    var langName, modules, modulesLength, i, module;

    langName = req.eduLanguage;
    // descArray = [];

    Language.findOne({'name': langName}, function (err, language) {
      if (err) {
        req.flash('langMsg', err);
        res.redirect('/admin/languages');

      } else {
        if (!language) {
          req.flash('langMsg', 'Language not found.');
          res.redirect('/admin/languages');
        } else {

          // Build description string from location description object,
          // so it will play nice with mapplic plugin
          modules = language.modules;
          // modulesLength = modules.length;

          // for (i = 0; i < modulesLength; i++) {
          //   module = modules[i];
            // descString = '
';
            // desc = location.description;
            // imgs = desc.images;
            // imgsLength = imgs.length;

            // for (j = 0; j < imgsLength; j++) {
            //   descString += '';
            // }

            // descString += '
' + desc.text;

            // if (desc.link) {
            //   descString += ' ' + desc.link.text + '
';
            // } else {
            //   descString += '
';
            // }

            // map.locations[i].description = descString;
          // }

          // Object formatted according to mapplic
          // mapplicObj = {
          //   mapwidth: 640,
          //   mapheight: 600,
          //   categories: [
          //     {
          //       id: 'naturaleza',
          //       title: 'Naturaleza',
          //       color: '#4cd3b8',
          //       show: true
          //     },
          //     {
          //       id: 'servicios',
          //       title: 'Servicios',
          //       color: '#80D316',
          //       show: true
          //     },
          //     {
          //       id: 'ciudades',
          //       title: 'Ciudades',
          //       color: '#63aa9c',
          //       show: true
          //     }
          //   ],
          //   levels: [map]
          // };

          res.render('modules.ejs', {
            modules: modules,
            title: 'Available Learning Modules',
            message: req.flash('moduleMsg')
          });
        }
      }
    });//.lean(); //'lean' so Mongoose returns raw JS object, which can be modified
  },
  addModule: function (req, res, next) {
    var moduleName, form, section, lessons;

    moduleName = req.eduModule;
    form = req.body;
    section = form['x-coord'];
    y = form['y-coord'];
    locationTitle = form.title;
    locationId = locationTitle.toLowerCase();
    descriptionText = form.description;
    linkUrl = form['link-url'];
    linkText = form['link-text'];
    category = form.category;
    imgNames = form.images;

    // Images need to be in form of an array
    if (typeof imgNames === 'string') {
      if (imgNames === '') {
        imgNames = [];
      } else {
        imgNames = [imgNames];
      }
    }

    newLocation = {
      id: locationId,
      title: locationTitle,
      description: {
        images: imgNames,
        text: descriptionText,
        link: {
          text: linkText,
          url: linkUrl
        }
      },
      category: category,
      x: x,
      y: y,
      pin: 'circular',
      fill: 'red'
    };

    Mapa.findOne({'id': mapId},
      function (err, map) {
        if (err) {
          req.flash('mapMsg', err);
          res.redirect('/admin/mapas/' + mapId);

        } else {
          if (!map) {
            req.flash('mapMsg', 'No se encontró ese mapa.');
            res.redirect('/admin/mapas');

          } else {
            map.locations.push(newLocation);

            map.save(function(err) {
              if (err) {
                req.flash('mapMsg', err);
                res.redirect('/admin/mapas/' + mapId + '/puntos/agregar');

              } else {
                req.flash('mapMsg', 'Se agregó el punto nuevo.');
                res.redirect('/admin/mapas/' + mapId);
              }
            });
          }
        }
    });
  },
  getLocation: function (req, res, next) {
    var mapId, locationId, i, thisLocation;

    mapId = req.map;
    locationId = req.location;

    Mapa.findOne({'id': mapId}, function(err, map) {
      if (err) {
        req.flash('mapMsg', err);
        res.redirect('/admin/mapas');

      } else {
        if (!map) {
          req.flash('mapMsg', 'No se encontró el mapa.');
          res.redirect('/admin/mapas');

        } else {
          i = 0;
          while (map.locations[i].id !== locationId &&
            i < map.locations.length) {
            i++
          }

          thisLocation = map.locations[i];

          res.render('admin-punto-editar.ejs', {
            title: 'Editar punto',
            x: thisLocation.x,
            y: thisLocation.y,
            locationTitle: thisLocation.title,
            description: thisLocation.description.text,
            linkText: thisLocation.description.link.text,
            linkUrl: thisLocation.description.link.url,
            category: thisLocation.category,
            images: thisLocation.description.images
          });
        }
      }
    });
  },
  editLocation: function (req, res, next) {
    var mapId, locationId, form, locationTitle, newLocationId, descriptionText,
      linkUrl, linkText, category, imgNames, keyArray, key, keyString, i,
      modifyLocation, x, y, locationImages, j, removed, k;

    mapId = req.map;
    locationId = req.location;
    form = req.body;
    locationTitle = form.title;
    newLocationId = locationTitle.toLowerCase();
    descriptionText = form.description;
    linkUrl = form['link-url'];
    linkText = form['link-text'];
    category = form.category;
    imgNames = form.images;

    // Images need to be in form of an array
    if (typeof imgNames === 'string') {
      if (imgNames === '') {
        imgNames = [];
      } else {
        imgNames = [imgNames];
      }
    }

    keyArray = [];

    // Create array of checked image names to remove from location images
    for (key in form) {
      if (key.search('remove-') >= 0) {
        keyString = key.slice(7);
        keyArray.push(keyString);
      }
    }

    Mapa.findOne({'id': mapId},
      function (err, map) {
        if (err) {
          req.flash('mapMsg', err);
          res.redirect('/admin/mapas');

        } else {
          if (!map) {
            req.flash('mapMsg', 'No se encontró ese mapa.');
            res.redirect('/admin/mapas');

          } else {
            i = 0;
            while (map.locations[i].id !== locationId &&
              i < map.locations.length) {
              i++
            }

            modifyLocation = map.locations[i];

            x = modifyLocation.x
            y = modifyLocation.y
            locationImages = modifyLocation.description.images;

            for (j = 0; j < locationImages.length; j++) {
              removed = false

              // Check location images array for removed images
              for (k = 0; k < keyArray.length; k++) {
                if (keyArray[k] === locationImages[j]) {
                  keyArray.splice(k, 1);
                  k--;
                  removed = true
                }
              }

              // If an image wasn't removed, add it to the new images array
              if (!removed) {imgNames.push(locationImages[j]);}
            }

            // Modifying location object with dot notation, because Mongoose
            // doesn't like literal notation
            modifyLocation.id = newLocationId;
            modifyLocation.title = locationTitle;
            modifyLocation.category = category;
            modifyLocation.description.images = imgNames;
            modifyLocation.description.text = descriptionText;
            modifyLocation.description.link.text = linkText;
            modifyLocation.description.link.url = linkUrl;

            map.save(function(err) {
              if (err) {
                req.flash('mapMsg', err);
                res.redirect('/admin/mapas/' + mapId + '/puntos/' +
                  locationId + '/editar');

              } else {
                req.flash('mapMsg', 'Se revisó el punto.');
                res.redirect('/admin/mapas/' + mapId);
              }
            });
          }
        }
    });
  },
  removeLocation: function (req, res, next) {
    var mapId, locId, i, locationsLength;

    mapId = req.map;
    locId = req.location;

    Mapa.findOne({'id': mapId},
      function (err, map) {
        if (err) {
          req.flash('mapMsg', err);
          res.redirect('/admin/mapas/' + mapId);

        } else {
          if (!map) {
            req.flash('mapMsg', 'No se encontró ese mapa.');
            res.redirect('/admin/mapas');

          } else {
            i = 0;
            while (map.locations[i].id !== locId && i < map.locations.length) {
              i++;
            }
            map.locations[i].remove();

            map.save(function(err) {
              if (err) {
                req.flash('mapMsg', err);
                res.redirect('/admin/mapas/' + mapId);

              } else {
                req.flash('mapMsg', 'Se borró el punto.');
                res.redirect('/admin/mapas/' + mapId);
              }
            });
          }
        }
    });
  },
  uploadData: function(req, res, next) {
    var parser, i, thisData, langName, thisSection, thisModule, langObject,
      langArray, modules, moduleLength, j, moduleMatch, lessonMatch, lessons, lessonsLength,
      k, item;

    langObject = {};
    langArray = [];

    parser = parse({delimiter: ',', columns: true}, function(err, data){

      for (i = 0; i < data.length; i++) {
        thisData = data[i];
        langName = thisData['language-name'];
        thisSection = thisData['module-section'];
        thisModule = {
          index: thisData['module-index'],
          section: thisSection,
          lessons: [{
            reception: {text: thisData['reception-text']},
            textInput: {
              options: [{
                text: thisData['textInput-option-text'],
                correct: thisData['textInput-option-correct']
              }]
            },
            voiceInput: {text: thisData['voiceInput-text']}
          }]
        };

        if (langObject[langName]) {
          if (langObject[langName][thisSection]) {
            modules = langObject[langName][thisSection];
            moduleLength = modules.length;
            moduleMatch = false;

            for (j = 0; j < moduleLength; j++) {
              if (modules[j].index === thisModule.index) {
                moduleMatch = true;
                lessonMatch = false;
                lessons = modules[j].lessons;
                lessonsLength = lessons.length;

                for (k = 0; k < lessonsLength; k++) {
                  if (lessons[k].reception.text === thisModule.lessons[0].reception.text) {
                    lessonMatch = true;
                    langObject[langName][thisSection][j].lessons[k].textInput.options.push(
                      thisModule.lessons[0].textInput.options[0]
                    );
                    break;
                  }
                }

                if (!lessonMatch) {
                  langObject[langName][thisSection][j].lessons.push(thisModule.lessons[0]);
                }
                break;
              }
            }

            if (!moduleMatch) {
              langObject[langName][thisSection].push(thisModule);
            }

          } else {
            langObject[langName][thisSection] = [thisModule];
          }

        } else {
          langObject[langName] = {name: langName};
          langObject[langName][thisSection] = [thisModule];
        }
      }

      for (item in langObject) {
        langArray.push(langObject[item]);
      }

      Language.create(langArray, function(err, languages) {
        if (err) {
          console.log(err);
        }

        console.log(languages);
      });

      res.send('uploaded');
    });

    fs.createReadStream(__dirname + '/model-data.csv').pipe(parser);
  }
};<|endoftext|>


<commit_before>exports.match = require('./match');
exports.invokeHandler = require('./invokeHandler');
exports.getRoutes = require('../lib/index.js').getRoutes;
<commit_msg>Removed unused "getRoutes" method<commit_after>exports.match = require('./match');
exports.invokeHandler = require('./invokeHandler');
<|endoftext|>


<commit_before>var express = require('express');
var router = express.Router();
var bodyParser = require('body-parser');

var redis = require('redis');
var client = redis.createClient(6379, "192.168.99.100"); //creates a new client

client.on('connect', function() {
    console.log('connected to redis');
});

var links = {};

links['joephilly'] = [{
	title: "JoePhilly's first link",
	url: "http://www.google.com"
},
{
	title: "JoePhilly's second link",
	url: "http://www.cuil.com"
}];

links['jbase'] = {
	title: "Jbase's link",
	url: "http://www.yahoo.com"
};

links['phil'] = {
	title: "Phil's link",
	url: "http://www.bing.com"
};

/* GET default. */
router.get('/', function(req, res, next) {
  res.send('Welcome to the API');
});

/* GET all links. */
router.get('/links', function(req, res, next) {
  client.get('favorite', function(err, reply){
  	res.send(reply);
  })
});

/* GET a user's links. */
router.get('/links/:user', function(req, res, next) {
  res.send(links[req.params.user]);
});

router.post('/links', function(req, res, next){
	console.log(req.body.favorite);
	client.set('favorite', req.body.favorite);
	res.send('Ok');
});

module.exports = router;
<commit_msg>Adding a mixture of test data and installation data to the redis db<commit_after>var express = require('express');
var router = express.Router();
var bodyParser = require('body-parser');

var redis = require('redis');

var client = redis.createClient(6379, "192.168.99.100"); //creates a new client
client.on('connect', function() { console.log('connected to redis'); });
client.flushdb(function (err, success) {});
client.set('next_user_id', 1, redis.print);
client.hset('users:1', 'username', 'admin', redis.print);
client.hset('logins:admin', "id", 1, redis.print);
client.incr('next_user_id', function (err, reply) {});
client.zadd('links:1', (new Date).getTime(), "http://expira.link");
client.zadd('links:1', (new Date).getTime(), "http://google.com");

client.zrevrangebyscore([ 'links:1', 9999999999999, 0 ], function (err, response) {
    console.log('response: ' + response);
});

var links = {};

links['joephilly'] = [{
	title: "JoePhilly's first link",
	url: "http://www.google.com"
},
{
	title: "JoePhilly's second link",
	url: "http://www.cuil.com"
}];

links['jbase'] = {
	title: "Jbase's link",
	url: "http://www.yahoo.com"
};

links['phil'] = {
	title: "Phil's link",
	url: "http://www.bing.com"
};

/* GET default. */
router.get('/', function(req, res, next) {
  res.send('Welcome to the API');
});

/* GET all links. */
router.get('/links', function(req, res, next) {
  client.get('favorite', function(err, reply){
  	res.send(reply);
  })
});

/* GET a user's links. */
router.get('/links/:user', function(req, res, next) {
  res.send(links[req.params.user]);
});

router.post('/links', function(req, res, next){
	console.log(req.body.favorite);
	client.set('favorite', req.body.favorite);
	res.send('Ok');
});

module.exports = router;
<|endoftext|>


<commit_before>'use strict';

var async = require('async');
var openVeoAPI = require('@openveo/api');
var db = openVeoAPI.applicationStorage.getDatabase();

module.exports.update = function(callback) {
  process.logger.info('Publish 2.0.0 migration launched.');

  // Prefix collection with the module name : publish
  db.renameCollection('properties', 'publish_properties', function(error, value) {
    if (error) {
      callback(error);
      return;
    }
  });
  db.renameCollection('configurations', 'publish_configurations', function(error, value) {
    if (error) {
      callback(error);
      return;
    }
  });
  db.renameCollection('videos', 'publish_videos', function(error, value) {
    if (error) {
      callback(error);
      return;
    }
  });

  // Rename permissions names
  db.get('core_roles', {}, null, null, function(error, value) {
    if (error) {
      callback(error);
      return;
    }

    // No need to change anything
    if (!value || !value.length) callback();

    var permissions = [];

    value.forEach(function(role) {
      if (role.permissions) {
        permissions = [];
        role['permissions'].forEach(function(permission) {
          switch(permission) {
            case 'create-property':
              permissions.push('publish-add-properties');
              break;
            case 'update-property':
              permissions.push('publish-update-properties');
              break;
            case 'delete-property':
              permissions.push('publish-delete-properties');
              break;
            case 'create-video':
              permissions.push('publish-add-videos');
              break;
            case 'update-video':
              permissions.push('publish-update-videos');
              break;
            case 'delete-video':
              permissions.push('publish-delete-videos');
              break;
            case 'access-videos-page':
              permissions.push('publish-access-videos-page');
              break;
            case 'access-properties-page':
              permissions.push('publish-access-properties-page');
              break;
            case 'access-categories-page':
              permissions.push('publish-access-categories-page');
              break;
            case 'access-watcher-page':
              permissions.push('publish-access-watcher-page');
              break;
            case 'manage-watcher':
              permissions.push('publish-manage-watcher');
              break;
            case 'access-conf-page':
              permissions.push('publish-access-conf-page');
              break;
            case 'manage-publish-config':
              permissions.push('publish-manage-publish-config');
              break;
            case 'publish-video':
              permissions.push('publish-publish-videos');
              break;
            case 'chapter-video':
              permissions.push('publish-chapter-videos');
              break;
            case 'retry-video':
              permissions.push('publish-retry-videos');
              break;
            case 'upload-video':
              permissions.push('publish-upload-videos');
              break;
            default:
              permissions.push(permission);
              break;
          }
        });

        db.update('core_roles', {id: role.id}, {permissions: permissions}, function(error) {
          if (error) {
            callback(error);
            return;
          }
        });
      }
    });
  });

  db.get('publish_videos', {}, null, null, function(error, value) {
    if (error) {
      callback(error);
      return;
    }

    // No need to change anything
    if (!value || !value.length) callback();

    else {
      var series = [];

      value.forEach(function(video) {
        if (video.files) {

          // backup files property in sources property
          if (!video.sources) {
            series.push(function(callback) {
              db.update('publish_videos', {id: video.id}, {sources: {files: video.files}}, function(error) {
                callback(error);
              });
            });
          }

          // delete files property
          if (video.files) {
            series.push(function(callback) {
              db.removeProp('publish_videos', 'files', {id: video.id}, function(error) {
                callback(error);
              });
            });
          }
        }
      });

      async.series(series, function(error) {
        if (error) {
          callback(error);
          return;
        }
        process.logger.info('Publish 2.0.0 migration done.');
        callback();
      });
    }
  });
};
<commit_msg>Update migration to prefix thumbnail video url with publish<commit_after>'use strict';

var async = require('async');
var openVeoAPI = require('@openveo/api');
var db = openVeoAPI.applicationStorage.getDatabase();

module.exports.update = function(callback) {
  process.logger.info('Publish 2.0.0 migration launched.');

  // Prefix collection with the module name : publish
  db.renameCollection('properties', 'publish_properties', function(error, value) {
    if (error) {
      callback(error);
      return;
    }
  });
  db.renameCollection('configurations', 'publish_configurations', function(error, value) {
    if (error) {
      callback(error);
      return;
    }
  });
  db.renameCollection('videos', 'publish_videos', function(error, value) {
    if (error) {
      callback(error);
      return;
    }
  });

  // Rename permissions names
  db.get('core_roles', {}, null, null, function(error, value) {
    if (error) {
      callback(error);
      return;
    }

    // No need to change anything
    if (!value || !value.length) callback();

    var permissions = [];

    value.forEach(function(role) {
      if (role.permissions) {
        permissions = [];
        role['permissions'].forEach(function(permission) {
          switch(permission) {
            case 'create-property':
              permissions.push('publish-add-properties');
              break;
            case 'update-property':
              permissions.push('publish-update-properties');
              break;
            case 'delete-property':
              permissions.push('publish-delete-properties');
              break;
            case 'create-video':
              permissions.push('publish-add-videos');
              break;
            case 'update-video':
              permissions.push('publish-update-videos');
              break;
            case 'delete-video':
              permissions.push('publish-delete-videos');
              break;
            case 'access-videos-page':
              permissions.push('publish-access-videos-page');
              break;
            case 'access-properties-page':
              permissions.push('publish-access-properties-page');
              break;
            case 'access-categories-page':
              permissions.push('publish-access-categories-page');
              break;
            case 'access-watcher-page':
              permissions.push('publish-access-watcher-page');
              break;
            case 'manage-watcher':
              permissions.push('publish-manage-watcher');
              break;
            case 'access-conf-page':
              permissions.push('publish-access-conf-page');
              break;
            case 'manage-publish-config':
              permissions.push('publish-manage-publish-config');
              break;
            case 'publish-video':
              permissions.push('publish-publish-videos');
              break;
            case 'chapter-video':
              permissions.push('publish-chapter-videos');
              break;
            case 'retry-video':
              permissions.push('publish-retry-videos');
              break;
            case 'upload-video':
              permissions.push('publish-upload-videos');
              break;
            default:
              permissions.push(permission);
              break;
          }
        });

        db.update('core_roles', {id: role.id}, {permissions: permissions}, function(error) {
          if (error) {
            callback(error);
            return;
          }
        });
      }
    });
  });

  db.get('publish_videos', {}, null, null, function(error, value) {
    if (error) {
      callback(error);
      return;
    }

    // No need to change anything
    if (!value || !value.length) callback();

    else {
      var series = [];

      value.forEach(function(video) {
        if (video.files) {

          // backup files property in sources property
          if (!video.sources) {
            series.push(function(callback) {
              db.update('publish_videos', {id: video.id}, {sources: {files: video.files}}, function(error) {
                callback(error);
              });
            });
          }

          // delete files property
          if (video.files) {
            series.push(function(callback) {
              db.removeProp('publish_videos', 'files', {id: video.id}, function(error) {
                callback(error);
              });
            });
          }
        }

        // prefix thumbnail video url with publish
        if (video.thumbnail && video.thumbnail.indexOf('/publish/') == -1) {
          series.push(function(callback) {
            db.update('publish_videos', {id: video.id}, {thumbnail: '/publish/' + video.thumbnail}, function(error) {
              callback(error);
            });
          });
        }
      });

      async.series(series, function(error) {
        if (error) {
          callback(error);
          return;
        }
        process.logger.info('Publish 2.0.0 migration done.');
        callback();
      });
    }
  });
};
<|endoftext|>


<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

var EventEmitter = require('events').EventEmitter;
var inherits = require('util').inherits;
var parallel = require('run-parallel');
var TypedError = require('error/typed');
var util = require('util');

var EndpointAlreadyDefinedError = TypedError({
    type: 'endpoint-already-defined',
    message: 'endpoint {endpoint} already defined on service {service}',
    service: null,
    endpoint: null,
    oldHandler: null,
    newHandler:  null
});

var InvalidHandlerError = TypedError({
    type: 'invalid-handler',
    message: 'invalid handler function'
});

function TChannelEndpointHandler(serviceName) {
    if (!(this instanceof TChannelEndpointHandler)) {
        return new TChannelEndpointHandler(serviceName);
    }
    var self = this;
    EventEmitter.call(self);
    self.serviceName = serviceName;
    self.endpoints = Object.create(null);
    self.type = 'tchannel.endpoint-handler';
}
inherits(TChannelEndpointHandler, EventEmitter);

TChannelEndpointHandler.prototype.register = function register(name, handler) {
    var self = this;
    if (self.endpoints[name] !== undefined) {
        throw EndpointAlreadyDefinedError({
            service: self.serviceName,
            endpoint: name,
            oldHandler: self.endpoints[name],
            newHandler: handler
        });
    }
    if (typeof handler !== 'function') {
        throw InvalidHandlerError();
    }
    self.endpoints[name] = handler;
    return handler;
};

TChannelEndpointHandler.prototype.handleRequest = function handleRequest(req, buildResponse) {
    var self = this;
    if (req.streamed) {
        req.arg1.onValueReady(function arg1Ready(err, arg1) {
            if (err) {
                // TODO: log error
                sendError('UnexpectedError', util.format(
                    'error accumulating arg1: %s: %s',
                    err.constructor.name, err.message));
            } else {
                handleArg1(arg1);
            }
        });
    } else {
        handleArg1(req.arg1);
    }

    function handleArg1(arg1) {
        var name = String(arg1);
        var handler = self.endpoints[name];
        self.emit('handle.endpoint', name, handler);
        if (!handler) {
            sendError('BadRequest', util.format(
                'no such endpoint service=%j endpoint=%j',
                req.service, name));
        } else if (handler.canStream) {
            handler(req, buildResponse);
        } else if (req.streamed) {
            parallel({
                arg2: req.arg2.onValueReady,
                arg3: req.arg3.onValueReady
            }, argsDone);
        } else {
            compatHandle(handler, req);
        }

        function argsDone(err, args) {
            if (err) {
                // TODO: log error
                sendError('UnexpectedError', util.format(
                    'error accumulating arg2/arg3: %s: %s',
                    err.constructor.name, err.message));
            } else {
                compatHandle(handler, args);
            }
        }

        function compatHandle(handler, args) {
            var res = buildResponse({streamed: false});
            handler(req, res, args.arg2, args.arg3);
        }
    }

    function sendError(code, mess) {
        var res = buildResponse({streamed: false});
        res.sendError(code, mess);
    }
};

module.exports = TChannelEndpointHandler;
<commit_msg>endpoint-handler: drop already defined error<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

var EventEmitter = require('events').EventEmitter;
var inherits = require('util').inherits;
var parallel = require('run-parallel');
var TypedError = require('error/typed');
var util = require('util');

var InvalidHandlerError = TypedError({
    type: 'invalid-handler',
    message: 'invalid handler function'
});

function TChannelEndpointHandler(serviceName) {
    if (!(this instanceof TChannelEndpointHandler)) {
        return new TChannelEndpointHandler(serviceName);
    }
    var self = this;
    EventEmitter.call(self);
    self.serviceName = serviceName;
    self.endpoints = Object.create(null);
    self.type = 'tchannel.endpoint-handler';
}
inherits(TChannelEndpointHandler, EventEmitter);

TChannelEndpointHandler.prototype.register = function register(name, handler) {
    var self = this;
    if (typeof handler !== 'function') {
        throw InvalidHandlerError();
    }
    self.endpoints[name] = handler;
    return handler;
};

TChannelEndpointHandler.prototype.handleRequest = function handleRequest(req, buildResponse) {
    var self = this;
    if (req.streamed) {
        req.arg1.onValueReady(function arg1Ready(err, arg1) {
            if (err) {
                // TODO: log error
                sendError('UnexpectedError', util.format(
                    'error accumulating arg1: %s: %s',
                    err.constructor.name, err.message));
            } else {
                handleArg1(arg1);
            }
        });
    } else {
        handleArg1(req.arg1);
    }

    function handleArg1(arg1) {
        var name = String(arg1);
        var handler = self.endpoints[name];
        self.emit('handle.endpoint', name, handler);
        if (!handler) {
            sendError('BadRequest', util.format(
                'no such endpoint service=%j endpoint=%j',
                req.service, name));
        } else if (handler.canStream) {
            handler(req, buildResponse);
        } else if (req.streamed) {
            parallel({
                arg2: req.arg2.onValueReady,
                arg3: req.arg3.onValueReady
            }, argsDone);
        } else {
            compatHandle(handler, req);
        }

        function argsDone(err, args) {
            if (err) {
                // TODO: log error
                sendError('UnexpectedError', util.format(
                    'error accumulating arg2/arg3: %s: %s',
                    err.constructor.name, err.message));
            } else {
                compatHandle(handler, args);
            }
        }

        function compatHandle(handler, args) {
            var res = buildResponse({streamed: false});
            handler(req, res, args.arg2, args.arg3);
        }
    }

    function sendError(code, mess) {
        var res = buildResponse({streamed: false});
        res.sendError(code, mess);
    }
};

module.exports = TChannelEndpointHandler;
<|endoftext|>


<commit_before>'use strict';

module.exports = function (kind) {
	var colName = kind + 's', target = this.processingStep || this.businessProcess, first, snapshot;
	if (!this.businessProcesss.isClosed) {
		first = target[colName].applicable.first;
	} else {
		snapshot = this.businessProcess[colName].dataSnapshot.resolved;

		// Find first viewable document
		this.target[colName].applicable.some(function (upload) {
			var uploadKey = (kind === 'requirementUpload') ? upload.document.uniqueKey : upload.key;
			return snapshot.some(function (data) {
				if (data.uniqueKey === uploadKey) {
					first = upload;
					return true;
				}
			});
		});
	}
	if (!first) return;
	if (kind === 'requirementUpload') return first.document.uniqueKey;
	return first.key;
};
<commit_msg>Issue #1277. No need to snakelize businessProcess<commit_after>'use strict';

module.exports = function (kind) {
	var colName = kind + 's', target = this.processingStep || this.businessProcess, first, snapshot;
	if (!this.businessProcess.isClosed) {
		first = target[colName].applicable.first;
	} else {
		snapshot = this.businessProcess[colName].dataSnapshot.resolved;

		// Find first viewable document
		this.target[colName].applicable.some(function (upload) {
			var uploadKey = (kind === 'requirementUpload') ? upload.document.uniqueKey : upload.key;
			return snapshot.some(function (data) {
				if (data.uniqueKey === uploadKey) {
					first = upload;
					return true;
				}
			});
		});
	}
	if (!first) return;
	if (kind === 'requirementUpload') return first.document.uniqueKey;
	return first.key;
};
<|endoftext|>