<commit_before>'use strict';

// ---------------------------------------------------------------------------

const acx = require ('./acx.js');
const { ArgumentsRequired } = require ('./base/errors');

// ---------------------------------------------------------------------------

module.exports = class kuna extends acx {
    describe () {
        return this.deepExtend (super.describe (), {
            'id': 'kuna',
            'name': 'Kuna',
            'countries': [ 'UA' ],
            'rateLimit': 1000,
            'version': 'v2',
            'has': {
                'CORS': false,
                'fetchTickers': true,
                'fetchOpenOrders': true,
                'fetchMyTrades': true,
                'withdraw': false,
            },
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/1294454/31697638-912824fa-b3c1-11e7-8c36-cf9606eb94ac.jpg',
                'api': 'https://kuna.io',
                'www': 'https://kuna.io',
                'doc': 'https://kuna.io/documents/api',
                'fees': 'https://kuna.io/documents/api',
            },
            'fees': {
                'trading': {
                    'taker': 0.25 / 100,
                    'maker': 0.25 / 100,
                },
                'funding': {
                    'withdraw': {
                        'UAH': '1%',
                        'BTC': 0.001,
                        'BCH': 0.001,
                        'ETH': 0.01,
                        'WAVES': 0.01,
                        'GOL': 0.0,
                        'GBG': 0.0,
                        // 'RMC': 0.001 BTC
                        // 'ARN': 0.01 ETH
                        // 'R': 0.01 ETH
                        // 'EVR': 0.01 ETH
                    },
                    'deposit': {
                        // 'UAH': (amount) => amount * 0.001 + 5
                    },
                },
            },
        });
    }

    async fetchMarkets () {
        const quotes = [ 'btc', 'eth', 'eurs', 'gbg', 'uah' ];
        const pricePrecisions = {
            'UAH': 0,
        };
        let markets = [];
        let tickers = await this.publicGetTickers ();
        let ids = Object.keys (tickers);
        for (let i = 0; i < ids.length; i++) {
            let id = ids[i];
            for (let j = 0; j < quotes.length; j++) {
                let quoteId = quotes[j];
                if (id.indexOf (quoteId) > 0) {
                    let baseId = id.replace (quoteId, '');
                    let base = baseId.toUpperCase ();
                    let quote = quoteId.toUpperCase ();
                    base = this.commonCurrencyCode (base);
                    quote = this.commonCurrencyCode (quote);
                    let symbol = base + '/' + quote;
                    let precision = {
                        'amount': 6,
                        'price': this.safeInteger (pricePrecisions, quote, 6),
                    };
                    markets.push ({
                        'id': id,
                        'symbol': symbol,
                        'base': base,
                        'quote': quote,
                        'baseId': baseId,
                        'quoteId': quoteId,
                        'precision': precision,
                        'limits': {
                            'amount': {
                                'min': Math.pow (10, -precision['amount']),
                                'max': Math.pow (10, precision['amount']),
                            },
                            'price': {
                                'min': Math.pow (10, -precision['price']),
                                'max': Math.pow (10, precision['price']),
                            },
                            'cost': {
                                'min': undefined,
                                'max': undefined,
                            },
                        },
                    });
                    break;
                }
            }
        }
        return markets;
    }

    async fetchOrderBook (symbol, limit = undefined, params = {}) {
        await this.loadMarkets ();
        let market = this.market (symbol);
        let orderBook = await this.publicGetOrderBook (this.extend ({
            'market': market['id'],
        }, params));
        return this.parseOrderBook (orderBook, undefined, 'bids', 'asks', 'price', 'remaining_volume');
    }

    async fetchL3OrderBook (symbol, limit = undefined, params = {}) {
        return this.fetchOrderBook (symbol, limit, params);
    }

    async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
        if (symbol === undefined)
            throw new ArgumentsRequired (this.id + ' fetchOpenOrders requires a symbol argument');
        await this.loadMarkets ();
        let market = this.market (symbol);
        let orders = await this.privateGetOrders (this.extend ({
            'market': market['id'],
        }, params));
        // todo emulation of fetchClosedOrders, fetchOrders, fetchOrder
        // with order cache + fetchOpenOrders
        // as in BTC-e, Liqui, Yobit, DSX, Tidex, WEX
        return this.parseOrders (orders, market, since, limit);
    }

    parseTrade (trade, market = undefined) {
        let timestamp = this.parse8601 (trade['created_at']);
        let symbol = undefined;
        if (market)
            symbol = market['symbol'];
        let side = this.safeString (trade, 'side');
        if (side !== undefined) {
            let sideMap = {
                'ask': 'sell',
                'bid': 'buy',
            };
            side = this.safeString (sideMap, side);
        }
        let cost = this.safeFloat (trade, 'funds');
        let order = this.safeString (trade, 'order_id');
        return {
            'id': trade['id'].toString (),
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'symbol': symbol,
            'type': undefined,
            'side': side,
            'price': this.safeFloat (trade, 'price'),
            'amount': this.safeFloat (trade, 'volume'),
            'cost': cost,
            'order': order,
            'info': trade,
        };
    }

    async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets ();
        let market = this.market (symbol);
        let response = await this.publicGetTrades (this.extend ({
            'market': market['id'],
        }, params));
        return this.parseTrades (response, market, since, limit);
    }

    async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
        if (symbol === undefined)
            throw new ArgumentsRequired (this.id + ' fetchOpenOrders requires a symbol argument');
        await this.loadMarkets ();
        let market = this.market (symbol);
        let response = await this.privateGetTradesMy ({ 'market': market['id'] });
        return this.parseTrades (response, market, since, limit);
    }
};
<commit_msg>kuna fetchOrderBook fix #3929<commit_after>'use strict';

// ---------------------------------------------------------------------------

const acx = require ('./acx.js');
const { ArgumentsRequired } = require ('./base/errors');

// ---------------------------------------------------------------------------

module.exports = class kuna extends acx {
    describe () {
        return this.deepExtend (super.describe (), {
            'id': 'kuna',
            'name': 'Kuna',
            'countries': [ 'UA' ],
            'rateLimit': 1000,
            'version': 'v2',
            'has': {
                'CORS': false,
                'fetchTickers': true,
                'fetchOpenOrders': true,
                'fetchMyTrades': true,
                'withdraw': false,
            },
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/1294454/31697638-912824fa-b3c1-11e7-8c36-cf9606eb94ac.jpg',
                'api': 'https://kuna.io',
                'www': 'https://kuna.io',
                'doc': 'https://kuna.io/documents/api',
                'fees': 'https://kuna.io/documents/api',
            },
            'fees': {
                'trading': {
                    'taker': 0.25 / 100,
                    'maker': 0.25 / 100,
                },
                'funding': {
                    'withdraw': {
                        'UAH': '1%',
                        'BTC': 0.001,
                        'BCH': 0.001,
                        'ETH': 0.01,
                        'WAVES': 0.01,
                        'GOL': 0.0,
                        'GBG': 0.0,
                        // 'RMC': 0.001 BTC
                        // 'ARN': 0.01 ETH
                        // 'R': 0.01 ETH
                        // 'EVR': 0.01 ETH
                    },
                    'deposit': {
                        // 'UAH': (amount) => amount * 0.001 + 5
                    },
                },
            },
        });
    }

    async fetchMarkets () {
        const quotes = [ 'btc', 'eth', 'eurs', 'gbg', 'uah' ];
        const pricePrecisions = {
            'UAH': 0,
        };
        let markets = [];
        let tickers = await this.publicGetTickers ();
        let ids = Object.keys (tickers);
        for (let i = 0; i < ids.length; i++) {
            let id = ids[i];
            for (let j = 0; j < quotes.length; j++) {
                let quoteId = quotes[j];
                if (id.indexOf (quoteId) > 0) {
                    let baseId = id.replace (quoteId, '');
                    let base = baseId.toUpperCase ();
                    let quote = quoteId.toUpperCase ();
                    base = this.commonCurrencyCode (base);
                    quote = this.commonCurrencyCode (quote);
                    let symbol = base + '/' + quote;
                    let precision = {
                        'amount': 6,
                        'price': this.safeInteger (pricePrecisions, quote, 6),
                    };
                    markets.push ({
                        'id': id,
                        'symbol': symbol,
                        'base': base,
                        'quote': quote,
                        'baseId': baseId,
                        'quoteId': quoteId,
                        'precision': precision,
                        'limits': {
                            'amount': {
                                'min': Math.pow (10, -precision['amount']),
                                'max': Math.pow (10, precision['amount']),
                            },
                            'price': {
                                'min': Math.pow (10, -precision['price']),
                                'max': Math.pow (10, precision['price']),
                            },
                            'cost': {
                                'min': undefined,
                                'max': undefined,
                            },
                        },
                    });
                    break;
                }
            }
        }
        return markets;
    }

    async fetchL3OrderBook (symbol, limit = undefined, params = {}) {
        return this.fetchOrderBook (symbol, limit, params);
    }

    async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
        if (symbol === undefined)
            throw new ArgumentsRequired (this.id + ' fetchOpenOrders requires a symbol argument');
        await this.loadMarkets ();
        let market = this.market (symbol);
        let orders = await this.privateGetOrders (this.extend ({
            'market': market['id'],
        }, params));
        // todo emulation of fetchClosedOrders, fetchOrders, fetchOrder
        // with order cache + fetchOpenOrders
        // as in BTC-e, Liqui, Yobit, DSX, Tidex, WEX
        return this.parseOrders (orders, market, since, limit);
    }

    parseTrade (trade, market = undefined) {
        let timestamp = this.parse8601 (trade['created_at']);
        let symbol = undefined;
        if (market)
            symbol = market['symbol'];
        let side = this.safeString (trade, 'side');
        if (side !== undefined) {
            let sideMap = {
                'ask': 'sell',
                'bid': 'buy',
            };
            side = this.safeString (sideMap, side);
        }
        let cost = this.safeFloat (trade, 'funds');
        let order = this.safeString (trade, 'order_id');
        return {
            'id': trade['id'].toString (),
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'symbol': symbol,
            'type': undefined,
            'side': side,
            'price': this.safeFloat (trade, 'price'),
            'amount': this.safeFloat (trade, 'volume'),
            'cost': cost,
            'order': order,
            'info': trade,
        };
    }

    async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets ();
        let market = this.market (symbol);
        let response = await this.publicGetTrades (this.extend ({
            'market': market['id'],
        }, params));
        return this.parseTrades (response, market, since, limit);
    }

    async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
        if (symbol === undefined)
            throw new ArgumentsRequired (this.id + ' fetchOpenOrders requires a symbol argument');
        await this.loadMarkets ();
        let market = this.market (symbol);
        let response = await this.privateGetTradesMy ({ 'market': market['id'] });
        return this.parseTrades (response, market, since, limit);
    }
};
<|endoftext|>


<commit_before>
var L20n = {
  xul: {},
  cache: {},
  getContext: function(id) {
    return new L20n.Context(this.xul[id], this.cache)
  },
  hasContext: function(id) {
    return this.xul[id]?true:false;
  },
  createContext: function(id) {
    this.xul[id] = {'l20n': {}, 'data': {}};
    return new L20n.Context(this.xul[id], this.cache);
  },
}

L20n.Context = function(obj, cache) {
  this.obj = obj;
  this.curObj = this.obj['l20n'];
  this.cache = cache;
}

L20n.Context.prototype = {
  _getEntity: function(id, params) {
    var localObj;
    if (params) {
      localObj = {};
      for (var i in params) {
        localObj[i] = params[i];
      }
      localObj.__proto__ = this.curObj;
    } else {
      localObj = this.curObj;
    }
    return [localObj[id], localObj];
  },
  get: function(id, params) {
    let [entity, localObj] = this._getEntity(id, params);
    return localObj.getent(localObj, id)
  },
  getAttributes: function(id, params) {
    let attrs = {};
    let [entity, localObj] = this._getEntity(id, params);
    for (let i in entity._attrs) {
      if (typeof(entity._attrs[i])=='function') {
        attrs[i] = entity._attrs[i](localObj);
      } else {
        attrs[i] = entity._attrs[i];
      }
    }
    return attrs;
  },
  addReference: function(uri) {
 	var read = function(data) {
 	  eval(data);
 	}

    if (!this.cache[uri]) {
      var data = this._get_file(uri);
      this.cache[uri] = {}
      read.apply(this.cache[uri], Array(data))
    }
    var i;
    for (i in this.cache[uri]) {
      this.obj['l20n'][i] = this.cache[uri][i];
    }
  },
  set data(val) {
    this.obj['data'] = val;
    this.obj['data'].__proto__ = this.obj['l20n'];
    this.curObj = this.obj['data'];
  }
}

<commit_msg>update l20n.js lib<commit_after>var L20n = {
  getContext: function() {
    return new L20n.Context();
  },
  _startLoading: function(res, callback) {
    var httpRequest;
    httpRequest = new XMLHttpRequest();
    httpRequest.overrideMimeType('text/plain');
    httpRequest.addEventListener("load", function() {
      return callback(httpRequest.responseText)
    }, false);
    httpRequest.open('GET', res.uri, true);
    httpRequest.send('');
  },
  _paths: {'sys': '/l20n/js/data/sys.j20n',
           'globals': '/l20n/js/data/default.j20n'},
}

L20n.Resource = function(aURI) {
  this.uri = aURI;
}

L20n.Resource.prototype = {
  _loading: true,
  uri: null,
}

L20n.Context = function() {
  mFrozen = false;
  mResources = [];
  mEvents = {'ready': null}

  mObjects = {
    'resources': {},
    'context': {},
    'system': {},
    'globals': {},
  }

  this._getObject(mObjects['system'], L20n._paths['sys']);
  this._getObject(mObjects['globals'], L20n._paths['globals']);
}

L20n.Context.prototype = {
  addResource: function(aURI) {
    var res = this._getObject(mObjects['resources'], aURI);
  },
  get: function(id, args) {
    var curObj = mObjects['resources'];
    if (mObjects['context']) {
      mObjects['context'].__proto__ = curObj;
      curObj = mObjects['context'];
    }
    if (args) {
      args.__proto__ = curObj;
      curObj = args;
    }
    mObjects['globals'].__proto__ = curObj;
    curObj = mObjects['globals'];
    return mObjects['system'].getent(curObj, mObjects['system'], id);
  },
  getAttributes: function(id, args) {
    var curObj = mObjects['resources'];
    if (mObjects['context']) {
      mObjects['context'].__proto__ = curObj;
      curObj = mObjects['context'];
    }
    if (args) {
      args.__proto__ = curObj;
      curObj = args;
    }
    mObjects['globals'].__proto__ = curObj;
    curObj = mObjects['globals'];
    return mObjects['system'].getattrs(curObj, mObjects['system'], id);
  },
  isFrozen: function() {
    return mFrozen;
  },
  freeze: function() {
    mFrozen = true;
    if (this.isReady()) {
      this._fireObserver();
    }
  },
  isReady: function() {
    if (!mFrozen)
      return false;
    for (var i=0;i<mResources.length;i++) {
      if (mResources[i]._loading)
        return false;
    }
    return true;
  },
  set onReady(obs) {
    mEvents['ready'] = obs;
  },
  set data(data) {
    mObjects['context'] = data
  },
  get data() {
    return mObjects['context'];
  },

  // Private
  _loadObject: function(data, obj) {
    var read = function(data) {
      eval(data);
    }
    read.apply(obj, Array(data));
  },
  _getObject: function(obj, url) {
    var self = this;
    var res = new L20n.Resource(url);
    var _injectResource = function(data) {
      self._loadObject(data, obj);
      res._loading = false;

      if (self.isReady()) {
        self._fireObserver();
      }

    }
    L20n._startLoading(res, _injectResource);
    mResources.push(res);
  },
  _fireObserver: function() {
    if (mEvents['ready']) {
      mEvents['ready']();
      mEvents['ready'] = null;
    }
  }
}

<|endoftext|>


<commit_before>var _ = require('lodash')
  , async = require('async')
  , shellQuote = require('shell-quote').quote

  , utils = require('./utils')
  , colorize = require('./colorize')
  , text = require('../locales/en.json')
  , spawnNormal = require('./spawn-normal')

  // TODO: should these go in a strider-phases repo? centralize the constants
  , PHASES = ['environment', 'prepare', 'test', 'deploy', 'cleanup']

function getPath(path) {
  var envPath = process.env.path || process.env.Path || process.env.PATH

  if (path) {
    var sep = process.platform === 'win32' ? ';' : ':'
    var joined = path.join(sep)

    if (joined)
      return joined + sep + envPath
  }

  return envPath
}

module.exports = Job

// config:
// - baseDir - the directory to work in. The code gets cloned to baseDir/code
// - io - eventemitter for sending job status events
// - logger
// - log
// - error
// - pty
function Job(job, provider, plugins, config) {
  this.config = _.extend({
    spawn: spawnNormal,
    pty: false,
    env: {},
    logger: console
  }, config)
  if (this.config.pty) {
    this.config.logger.warn('PTY has been disabled due to a bug in node core');
    this.config.pty = false;
  }
  this.io = config.io
  this.job = job
  this.id = job._id
  this.provider = provider
  this.plugins = plugins
  this.logPrefix = colorize.job(this.id)
  this.phase = null
  this.testcode = null
  this.cancelled = false
  this.commands = []
  this.listen()
}

Job.prototype = {
  // public api
  run: function (done) {
    var self = this
      , dom = require('domain').create()

    // no plugins in use, nothing will happen. fail.
    if (!this.plugins.length) {
      return this.done({message: 'No plugins configured. Aborting'}, done)
    }

    // If the plugin has a listen function, execute it
    this.plugins.forEach(function (plugin) {
      if (plugin.listen) {
        var context = self.pluginContext(self.provider.id, _.cloneDeep(self.config.env), [])
        plugin.listen(self.io, context)
      }
    })

    if (this.job.fromStriderJson) {
      this.comment('Config merged from strider.json')
    }

    dom.on('error', function (err) {
      self.log('domain error caught', err.message, err.stack)
      self.error(err)
      dom.dispose()
      self.done(err, done)
    })
    dom.run(function () {
      self.phase = PHASES[0]
      self.runPhase(done)
    })
  },
  cancel: function () {
    if (this.cancelled) return
    var self = this
    console.log('cancelling')
    this.cancelled = true
    if (!this.commands.length) {
      return self.io.emit('job.cancelled', self.id)
    }
    this.commands.forEach(function (cmd) {
      console.log('killing', cmd.cmd.command)
      cmd.proc.kill()
    })
    setTimeout(function () {
      self.io.emit('job.cancelled', self.id)
    }, 1000)
  },
  // private api
  listen: function () {
    var self = this
    this.io.on('job.cancel', function (id) {
      console.log('io cancel', id, self.id)
      if (self.id.toString() === id.toString()) {
        self.cancel()
      }
    })
  },
  done: function (err, done) {
    if (this.cancelled) {
      this.log('"done" called but the job is cancelled. Not calling continuation')
      return
    }
    done(err)
  },

  // command execution stuff

  comment: function (text, plugin) {
    this.status('command.comment', { comment: text, plugin: plugin, time: new Date() })
  },

  /* usage:   (cmd, [plugin,] next) -> next(exitCode)
   * or:      (options, [plugin,] next) -> next(exitCode)
   *
   * plugin:  the name of the plugin that intiated the command
   *
   * options:
   *     cmd: string or {command: str, args: [], screen: str}
   *     silent: don't status the output as it goes
   *     env: {}
   *     cwd: str
   *
   * cmd('echo "hey"', next)
   * cmd({command: 'echo secretpassword', screen: 'echo [pwd]'}, next)
   * cmd({command: 'echo', args: ['hello']}, next)
   * cmd({cmd: 'hey', env: {ONE: 2}}, next)
   */
  cmd: function (cmd, plugin, next) {
    if (arguments.length === 2) {
      next = plugin
      plugin = null
    }
    var self = this
      , start = new Date()
      , options =
        { cwd: this.phase === 'environment' ? this.config.baseDir : this.config.dataDir
        , silent: false
        , detached: process.platform !== 'win32'
        }
      , std =
        { out: ''
        , err: ''
        }

    cmd = utils.normalizeCmd(cmd, options)

    this.config.spawn(cmd.command, cmd.args, options, function (err, proc) {
      if (err) {
        if (err === 127) return next(127, '', 'Command not found')
        console.log('fail!', err, cmd.command, cmd.args)
        return next(500, '', 'Unable to execude command :( ' + err)
      }
      proc.stdout.setEncoding('utf8')
      proc.stderr.setEncoding('utf8')

      proc.stdout.on('data', function(buf) {
        if (!options.silent) self.status('stdout', buf)
        std.out += buf
      })

      proc.stderr.on('data', function(buf) {
        if (!options.silent) self.status('stderr', buf)
        std.err += buf
      })

      proc.on('exit', function(exitCode) {
        var end = new Date()
          , elapsed = end.getTime() - start.getTime()
        // Uncomment to monitor job commands
        // self.log(util.format('command done %s %s; exit code %s; duration %s',
        // cmd.command, cmd.args, exitCode, elapsed))
        self.status('command.done', { exitCode: exitCode, time: end, elapsed: elapsed })
        var ind = -1
        for (var i=0; i<self.commands.length; i++) {
          if (self.commands[i].proc === proc) {
            ind = i
            break;
          }
        }
        if (ind !== -1) self.commands.splice(ind, 1)
        next(exitCode, std.out, std.err)
      })

      proc.on('error', function() {
        // prevent node from throwing an error
      })

      var strCmd = shellQuote([cmd.command].concat(cmd.args))
        , display = cmd.screen || strCmd
      this.status('command.start', { command: display, started: start, plugin: plugin, time: start })
      if (options.silent) {
        this.status('stdout', '[output suppressed]')
      }
      this.commands.push({
        cmd: { command: display, started: start, plugin: plugin, time: start },
        proc: proc
      })
    }.bind(this))
  },

  // job running stuff
  pluginContext: function (pluginName, env, path) {
    var self = this
    var context = {
      status: this.status.bind(this),
      out: this.out.bind(this),

      log: function () {
        var args = [].slice.call(arguments)
        // TODO colorize the plugin name?
        return self.log.apply(self, [pluginName].concat(args))
      },

      comment: function (text) {
        self.comment(text, pluginName)
      },
      cmd: function (cmd, next) {
        if (typeof(cmd) === 'string' || cmd.command) {
          cmd = {cmd: cmd}
        }
        cmd.env = _.extend({}, env, {
          PATH: getPath(path),
          HOME: process.env.HOME,
          LANG: process.env.LANG,
          SSH_AUTH_SOCK: process.env.SSH_AUTH_SOCK,
          PAAS_NAME: 'strider'
        }, cmd.env || {})
        return self.cmd(cmd, pluginName, next)
      },

      // update pluginData
      data: function (data, method, path) {
        self.status('plugin-data', {plugin: pluginName, data: data, method: method, path: path})
      },

      logger: this.config.logger,
      dataDir: this.config.dataDir,
      baseDir: this.config.baseDir,
      cacheDir: this.config.cacheDir,
      cachier: this.config.cachier(pluginName),
      io: this.io,

      plugin: pluginName,
      phase: this.phase,
      job: this.job,
      branch: this.job.ref.branch,
      project: this.project
    }
    return context
  },

  // collect `env` from all plugins for the current phase, and execute
  // plugin.runPhase(context) for each plugin in series
  runPhase: function (next) {
    if (this.cancelled) return
    var tasks = []
      , started = new Date()
      , self = this
      , path = []
      , env = _.cloneDeep(this.config.env)
    // need to clone the repo first
    if (this.phase === 'prepare') {
      tasks.push(this.provider.fetch.bind(this.provider, self.pluginContext(this.provider.id, env, path)))
    }
    this.plugins.forEach(function (plugin) {
      // all plugins will get the final, fully populated env object
      _.extend(env, ('function' === typeof plugin.env) ? plugin.env(self.phase) : plugin.env)
      if ('string' === typeof plugin.path) path.push(plugin.path)
      else path = path.concat('function' === typeof plugin.path ? plugin.path(self.phase) : plugin.path)
      tasks.push(function (next) {
        utils.runPlugin(self.phase, plugin, self.pluginContext(plugin.id, env, path), next)
      })
    })
    async.series(tasks, this.phaseDone.bind(this, next, started))
  },

  // called on the completion (or erroring) of a phase
  phaseDone: function (next, started, err, actuallyRan) {
    /* jshint maxcomplexity: 11 */
    var code = 0
      , now = new Date()
    if (err) {
      if (err.type === 'exitCode') code = err.code
      if ('number' === typeof err) code = err
      this.status('phase.errored', { time: now, exitCode: code });
      if (code === 0) {
        this.error(err)
        return this.done(err, next)
      }
    }
    // Complain if no plugins actually did anything during testing?
    // XXX: should this be a fail hard?
    if (['deploy', 'test'].indexOf(this.phase) !== -1 && utils.sum(actuallyRan) === 0) {
      this.out('Phase ' + this.phase + ' didn\'t actually run anything. Check your plugin configuration', 'warn')
    }
    if (this.phase === 'test') {
      this.status('tested', { time: now, exitCode: code })
    }
    if (this.phase === 'deploy') {
      this.status('deployed', { time: now, exitCode: code })
    }
    var nextPhase = PHASES[PHASES.indexOf(this.phase) + 1]
    if (code !== 0) {
      nextPhase = 'cleanup'
    } else if (nextPhase === 'deploy' && this.job.type !== 'TEST_AND_DEPLOY') {
      nextPhase = 'cleanup'
    }
    this.status('phase.done', {
      phase: this.phase,
      time: now,
      exitCode: code,
      next: nextPhase,
      elapsed: now.getTime() - started.getTime()
    })
    if (this.phase === 'cleanup') {
      return this.done(null, next)
    }
    this.phase = nextPhase
    this.runPhase(next)
  },

  // io stuff
  log: function () {
    var args = [].slice.call(arguments)
    this.config.log.apply(null, [this.logPrefix].concat(args))
  },
  error: function (error, serverOnly) {
    this.config.error(this.logPrefix, error.message || error, error.stack);
    if (!serverOnly) {
      this.status('stderr', text.errorPleaseReport + '\n\n' + error.message + '\n\n' + error.stack)
    }
  },
  status: function (type) {
    if (this.cancelled) return false
    var args = [].slice.call(arguments, 1)
    this.io.emit.apply(this.io, ['job.status.' + type, this.id].concat(args))
  },
  out: function (text, type) {
    var dest = ['error', 'stderr', 'warn'].indexOf(type) !== -1 ? 'stderr' : 'stdout'
    text = (type && colorize[type]) ? colorize[type](text) : text
    this.status(dest, text)
  }
}

<commit_msg>Fixed HOME for Windows environments<commit_after>var _ = require('lodash')
  , async = require('async')
  , shellQuote = require('shell-quote').quote

  , utils = require('./utils')
  , colorize = require('./colorize')
  , text = require('../locales/en.json')
  , spawnNormal = require('./spawn-normal')

  // TODO: should these go in a strider-phases repo? centralize the constants
  , PHASES = ['environment', 'prepare', 'test', 'deploy', 'cleanup']

function getPath(path) {
  var envPath = process.env.path || process.env.Path || process.env.PATH

  if (path) {
    var sep = process.platform === 'win32' ? ';' : ':'
    var joined = path.join(sep)

    if (joined)
      return joined + sep + envPath
  }

  return envPath
}

module.exports = Job

// config:
// - baseDir - the directory to work in. The code gets cloned to baseDir/code
// - io - eventemitter for sending job status events
// - logger
// - log
// - error
// - pty
function Job(job, provider, plugins, config) {
  this.config = _.extend({
    spawn: spawnNormal,
    pty: false,
    env: {},
    logger: console
  }, config)
  if (this.config.pty) {
    this.config.logger.warn('PTY has been disabled due to a bug in node core');
    this.config.pty = false;
  }
  this.io = config.io
  this.job = job
  this.id = job._id
  this.provider = provider
  this.plugins = plugins
  this.logPrefix = colorize.job(this.id)
  this.phase = null
  this.testcode = null
  this.cancelled = false
  this.commands = []
  this.listen()
}

Job.prototype = {
  // public api
  run: function (done) {
    var self = this
      , dom = require('domain').create()

    // no plugins in use, nothing will happen. fail.
    if (!this.plugins.length) {
      return this.done({message: 'No plugins configured. Aborting'}, done)
    }

    // If the plugin has a listen function, execute it
    this.plugins.forEach(function (plugin) {
      if (plugin.listen) {
        var context = self.pluginContext(self.provider.id, _.cloneDeep(self.config.env), [])
        plugin.listen(self.io, context)
      }
    })

    if (this.job.fromStriderJson) {
      this.comment('Config merged from strider.json')
    }

    dom.on('error', function (err) {
      self.log('domain error caught', err.message, err.stack)
      self.error(err)
      dom.dispose()
      self.done(err, done)
    })
    dom.run(function () {
      self.phase = PHASES[0]
      self.runPhase(done)
    })
  },
  cancel: function () {
    if (this.cancelled) return
    var self = this
    console.log('cancelling')
    this.cancelled = true
    if (!this.commands.length) {
      return self.io.emit('job.cancelled', self.id)
    }
    this.commands.forEach(function (cmd) {
      console.log('killing', cmd.cmd.command)
      cmd.proc.kill()
    })
    setTimeout(function () {
      self.io.emit('job.cancelled', self.id)
    }, 1000)
  },
  // private api
  listen: function () {
    var self = this
    this.io.on('job.cancel', function (id) {
      console.log('io cancel', id, self.id)
      if (self.id.toString() === id.toString()) {
        self.cancel()
      }
    })
  },
  done: function (err, done) {
    if (this.cancelled) {
      this.log('"done" called but the job is cancelled. Not calling continuation')
      return
    }
    done(err)
  },

  // command execution stuff

  comment: function (text, plugin) {
    this.status('command.comment', { comment: text, plugin: plugin, time: new Date() })
  },

  /* usage:   (cmd, [plugin,] next) -> next(exitCode)
   * or:      (options, [plugin,] next) -> next(exitCode)
   *
   * plugin:  the name of the plugin that intiated the command
   *
   * options:
   *     cmd: string or {command: str, args: [], screen: str}
   *     silent: don't status the output as it goes
   *     env: {}
   *     cwd: str
   *
   * cmd('echo "hey"', next)
   * cmd({command: 'echo secretpassword', screen: 'echo [pwd]'}, next)
   * cmd({command: 'echo', args: ['hello']}, next)
   * cmd({cmd: 'hey', env: {ONE: 2}}, next)
   */
  cmd: function (cmd, plugin, next) {
    if (arguments.length === 2) {
      next = plugin
      plugin = null
    }
    var self = this
      , start = new Date()
      , options =
        { cwd: this.phase === 'environment' ? this.config.baseDir : this.config.dataDir
        , silent: false
        , detached: process.platform !== 'win32'
        }
      , std =
        { out: ''
        , err: ''
        }

    cmd = utils.normalizeCmd(cmd, options)

    this.config.spawn(cmd.command, cmd.args, options, function (err, proc) {
      if (err) {
        if (err === 127) return next(127, '', 'Command not found')
        console.log('fail!', err, cmd.command, cmd.args)
        return next(500, '', 'Unable to execude command :( ' + err)
      }
      proc.stdout.setEncoding('utf8')
      proc.stderr.setEncoding('utf8')

      proc.stdout.on('data', function(buf) {
        if (!options.silent) self.status('stdout', buf)
        std.out += buf
      })

      proc.stderr.on('data', function(buf) {
        if (!options.silent) self.status('stderr', buf)
        std.err += buf
      })

      proc.on('exit', function(exitCode) {
        var end = new Date()
          , elapsed = end.getTime() - start.getTime()
        // Uncomment to monitor job commands
        // self.log(util.format('command done %s %s; exit code %s; duration %s',
        // cmd.command, cmd.args, exitCode, elapsed))
        self.status('command.done', { exitCode: exitCode, time: end, elapsed: elapsed })
        var ind = -1
        for (var i=0; i<self.commands.length; i++) {
          if (self.commands[i].proc === proc) {
            ind = i
            break;
          }
        }
        if (ind !== -1) self.commands.splice(ind, 1)
        next(exitCode, std.out, std.err)
      })

      proc.on('error', function() {
        // prevent node from throwing an error
      })

      var strCmd = shellQuote([cmd.command].concat(cmd.args))
        , display = cmd.screen || strCmd
      this.status('command.start', { command: display, started: start, plugin: plugin, time: start })
      if (options.silent) {
        this.status('stdout', '[output suppressed]')
      }
      this.commands.push({
        cmd: { command: display, started: start, plugin: plugin, time: start },
        proc: proc
      })
    }.bind(this))
  },

  // job running stuff
  pluginContext: function (pluginName, env, path) {
    var self = this
    var context = {
      status: this.status.bind(this),
      out: this.out.bind(this),

      log: function () {
        var args = [].slice.call(arguments)
        // TODO colorize the plugin name?
        return self.log.apply(self, [pluginName].concat(args))
      },

      comment: function (text) {
        self.comment(text, pluginName)
      },
      cmd: function (cmd, next) {
        if (typeof(cmd) === 'string' || cmd.command) {
          cmd = {cmd: cmd}
        }
        cmd.env = _.extend({}, env, {
          PATH: getPath(path),
          HOME: process.env.HOME || (process.env.HOMEDRIVE + process.env.HOMEPATH),
          LANG: process.env.LANG,
          SSH_AUTH_SOCK: process.env.SSH_AUTH_SOCK,
          PAAS_NAME: 'strider'
        }, cmd.env || {})
        return self.cmd(cmd, pluginName, next)
      },

      // update pluginData
      data: function (data, method, path) {
        self.status('plugin-data', {plugin: pluginName, data: data, method: method, path: path})
      },

      logger: this.config.logger,
      dataDir: this.config.dataDir,
      baseDir: this.config.baseDir,
      cacheDir: this.config.cacheDir,
      cachier: this.config.cachier(pluginName),
      io: this.io,

      plugin: pluginName,
      phase: this.phase,
      job: this.job,
      branch: this.job.ref.branch,
      project: this.project
    }
    return context
  },

  // collect `env` from all plugins for the current phase, and execute
  // plugin.runPhase(context) for each plugin in series
  runPhase: function (next) {
    if (this.cancelled) return
    var tasks = []
      , started = new Date()
      , self = this
      , path = []
      , env = _.cloneDeep(this.config.env)
    // need to clone the repo first
    if (this.phase === 'prepare') {
      tasks.push(this.provider.fetch.bind(this.provider, self.pluginContext(this.provider.id, env, path)))
    }
    this.plugins.forEach(function (plugin) {
      // all plugins will get the final, fully populated env object
      _.extend(env, ('function' === typeof plugin.env) ? plugin.env(self.phase) : plugin.env)
      if ('string' === typeof plugin.path) path.push(plugin.path)
      else path = path.concat('function' === typeof plugin.path ? plugin.path(self.phase) : plugin.path)
      tasks.push(function (next) {
        utils.runPlugin(self.phase, plugin, self.pluginContext(plugin.id, env, path), next)
      })
    })
    async.series(tasks, this.phaseDone.bind(this, next, started))
  },

  // called on the completion (or erroring) of a phase
  phaseDone: function (next, started, err, actuallyRan) {
    /* jshint maxcomplexity: 11 */
    var code = 0
      , now = new Date()
    if (err) {
      if (err.type === 'exitCode') code = err.code
      if ('number' === typeof err) code = err
      this.status('phase.errored', { time: now, exitCode: code });
      if (code === 0) {
        this.error(err)
        return this.done(err, next)
      }
    }
    // Complain if no plugins actually did anything during testing?
    // XXX: should this be a fail hard?
    if (['deploy', 'test'].indexOf(this.phase) !== -1 && utils.sum(actuallyRan) === 0) {
      this.out('Phase ' + this.phase + ' didn\'t actually run anything. Check your plugin configuration', 'warn')
    }
    if (this.phase === 'test') {
      this.status('tested', { time: now, exitCode: code })
    }
    if (this.phase === 'deploy') {
      this.status('deployed', { time: now, exitCode: code })
    }
    var nextPhase = PHASES[PHASES.indexOf(this.phase) + 1]
    if (code !== 0) {
      nextPhase = 'cleanup'
    } else if (nextPhase === 'deploy' && this.job.type !== 'TEST_AND_DEPLOY') {
      nextPhase = 'cleanup'
    }
    this.status('phase.done', {
      phase: this.phase,
      time: now,
      exitCode: code,
      next: nextPhase,
      elapsed: now.getTime() - started.getTime()
    })
    if (this.phase === 'cleanup') {
      return this.done(null, next)
    }
    this.phase = nextPhase
    this.runPhase(next)
  },

  // io stuff
  log: function () {
    var args = [].slice.call(arguments)
    this.config.log.apply(null, [this.logPrefix].concat(args))
  },
  error: function (error, serverOnly) {
    this.config.error(this.logPrefix, error.message || error, error.stack);
    if (!serverOnly) {
      this.status('stderr', text.errorPleaseReport + '\n\n' + error.message + '\n\n' + error.stack)
    }
  },
  status: function (type) {
    if (this.cancelled) return false
    var args = [].slice.call(arguments, 1)
    this.io.emit.apply(this.io, ['job.status.' + type, this.id].concat(args))
  },
  out: function (text, type) {
    var dest = ['error', 'stderr', 'warn'].indexOf(type) !== -1 ? 'stderr' : 'stdout'
    text = (type && colorize[type]) ? colorize[type](text) : text
    this.status(dest, text)
  }
}

<|endoftext|>


<commit_before>
jQuery(document).ready(function($) {

	// mobile nav menu, slide on click
	$('.mobile-bars').click(function(){ $('.header-menu').slideToggle(); });
	// fixme: when resized above mobile switch, if toggle was triggered menu display is none
});<commit_msg>switch to slim-nav when scroll reaches content<commit_after>
jQuery(document).ready(function($) {

	// mobile nav menu, slide on click
	$('.mobile-bars').click(function(){ $('.header-menu').slideToggle(); });
	// fixme: when resized above mobile switch, if toggle was triggered menu display is none
	// switch to slim-nav once scroll reaches content
	$(window).scroll(function() {
    	var header = $('.header'),
    		content = $('.post-title').position().top - 138,
			scroll_top = Math.round($(window).scrollTop());

		if (scroll_top >= content) {
			if ( !header.hasClass('slim-nav') )
				header.addClass('slim-nav');
		}
		else {
			if ( header.hasClass('slim-nav') )
				header.removeClass('slim-nav');
		}
    });

});<|endoftext|>


<commit_before>const menubar = require('menubar')
const { INDEX_PATH, TRAY_ICON_PATH } = require('../constants')

const mb = menubar({
  'preloadWindow': true,
  index: INDEX_PATH,
  width: 600,
  height: 700,
  icon: TRAY_ICON_PATH,
  'showDockIcon': false
})

module.exports = mb
<commit_msg>refactor(code): remove useless quotes<commit_after>const menubar = require('menubar')
const { INDEX_PATH, TRAY_ICON_PATH } = require('../constants')

const mb = menubar({
  preloadWindow: true,
  index: INDEX_PATH,
  width: 600,
  height: 700,
  icon: TRAY_ICON_PATH,
  showDockIcon: false
})

module.exports = mb
<|endoftext|>


<commit_before>'use strict';

/**
 * This file is being preloaded in Ghost Instances.
 * ⚠ Remember: No jQuery! ⚠
 */
var remote = require('electron').remote;
var Menu   = remote.Menu;

var template = [{
    label: 'Undo',
    role: 'undo'
}, {
    label: 'Redo',
    role: 'redo'
}, {
    type: 'separator'
}, {
    label: 'Cut',
    role: 'cut'
}, {
    label: 'Copy',
    role: 'copy'
}, {
    label: 'Paste',
    role: 'paste'
}, {
    label: 'Select All',
    role: 'selectall'
}];
var editorMenu = Menu.buildFromTemplate(template);

/**
 * Simple timeout function checking for
 * a) failed login
 * b) successful loaded
 */
function checkStatus() {
    var err = document.querySelector('p.main-error');
    var loaded = document.querySelector('a[title="New Post"]');

    if (err && ((err.childElementCount && err.childElementCount > 0) || (err.textContent && err.textContent.length > 0))) {
        // Noooo, login errors!
        console.log(`login-error`)
    } else if (loaded) {
        // Yay, successfully loaded
        console.log('loaded');
    } else {
        setTimeout(checkStatus, 100);
    }
}

/**
 * Setup the context menu
 */
function handleContextMenu(e) {
    // Do nothing when there's no input nearby
    if (!e.target.closest('textarea, input, [contenteditable="true"]')) {
        return;
    };

    e.preventDefault();
    e.stopPropagation();

    var node = e.target;

    while (node) {
        if (node.nodeName.match(/^(input|textarea)$/i) || node.isContentEditable) {
            editorMenu.popup(remote.getCurrentWindow());
            break;
        }

        node = node.parentNode;
    }
}

/**
 * Init
 */
setTimeout(checkStatus, 100);
window.addEventListener('contextmenu', handleContextMenu);

/**
 * Cleanup
 */
remote = undefined;
Menu = undefined;<commit_msg>:wrench: Improve Preloader<commit_after>'use strict';

/**
 * This file is being preloaded in Ghost Instances.
 * ⚠ Remember: No jQuery! ⚠
 */
var remote = require('electron').remote;
var Menu   = remote.Menu;

var template = [{
    label: 'Undo',
    role: 'undo'
}, {
    label: 'Redo',
    role: 'redo'
}, {
    type: 'separator'
}, {
    label: 'Cut',
    role: 'cut'
}, {
    label: 'Copy',
    role: 'copy'
}, {
    label: 'Paste',
    role: 'paste'
}, {
    label: 'Select All',
    role: 'selectall'
}];
var editorMenu = Menu.buildFromTemplate(template);

/**
 * Simple timeout function checking for
 * a) failed login
 * b) successful loaded
 */
function checkStatus() {
    var err = document.querySelector('p.main-error');
    var loaded = document.querySelector('a[title="New Post"]');

    if (err && ((err.childElementCount && err.childElementCount > 0) || (err.textContent && err.textContent.length > 0))) {
        // Noooo, login errors!
        console.log(`login-error`)
    } else if (loaded) {
        // Yay, successfully loaded - let's give the renderer 200 more ms
        // for rendering
        setTimeout(() => console.log('loaded'), 200);
    } else {
        setTimeout(checkStatus, 100);
    }
}

/**
 * Setup the context menu
 */
function handleContextMenu(e) {
    // Do nothing when there's no input nearby
    if (!e.target.closest('textarea, input, [contenteditable="true"]')) {
        return;
    };

    e.preventDefault();
    e.stopPropagation();

    var node = e.target;

    while (node) {
        if (node.nodeName.match(/^(input|textarea)$/i) || node.isContentEditable) {
            editorMenu.popup(remote.getCurrentWindow());
            break;
        }

        node = node.parentNode;
    }
}

/**
 * Init
 */
setTimeout(checkStatus, 100);
window.addEventListener('contextmenu', handleContextMenu);

/**
 * Cleanup
 */
remote = undefined;
Menu = undefined;<|endoftext|>


<commit_before>
/**
 * Required modules
 */

const colors = require( 'colors' )
const padEnd = require( 'pad-end' )

module.exports = {

    /**
     * Log a warning message
     *
     * @param   {String}  userMsg  Message to log
     * @param   {Object}           Filter name
     * @return  void
     */

    warn( userMsg, { filterName } = {} ) {

        const msgPrimary = colors.red( `\u2718 ${userMsg}` )

        if ( filterName ) {
            const msgSecondary = colors.gray( filterName )

            return console.warn(
                this.padEnd( msgPrimary, msgSecondary )
            )
        }

        return console.warn( msgPrimary )

    },

    /**
     * Log a success message
     *
     * @param   {String}  userMsg  Message to log
     * @param   {Object}           Silent mode, filter name
     * @return  void
     */

    ok( userMsg, { silentMode, filterName } = {} ) {

        if ( silentMode ) {
            return
        }

        const msgPrimary = colors.green( `\u2714 ${userMsg}` )

        if ( filterName ) {
            const msgSecondary = colors.gray( filterName )

            return console.log(
                this.padEnd( msgPrimary, msgSecondary )
            )
        }

        return console.log( msgPrimary )

    },

    /**
     * Log a info message
     *
     * @param   {String}  userMsg  Message to log
     * @param   {Object}           Silent mode, filter name
     * @return  void
     */

    info( userMsg, { silentMode, filterName } = {} ) {

        if ( silentMode ) {
            return
        }

        const msgPrimary = colors.yellow( `\u2139 ${userMsg}` )

        if ( filterName ) {
            const msgSecondary = colors.gray( filterName )

            return console.log(
                this.padEnd( msgPrimary, msgSecondary )
            )
        }

        return console.log( msgPrimary )

    },

    /**
     * Pads the current string with spaces and add a string
     *
     * @param   {String}  msgPrimary    Primary string
     * @param   {String}  msgSecondary  Secondary (gray) string
     * @return  {String}                Concated string
     */

    padEnd( msgPrimary, msgSecondary ) {

        return `${padEnd( msgPrimary, 99 )} ${msgSecondary}`

    }

}
<commit_msg>FUP v0.6.0: Rename function parameters<commit_after>
/**
 * Required modules
 */

const colors = require( 'colors' )
const padEnd = require( 'pad-end' )

module.exports = {

    /**
     * Log a warning message
     *
     * @param   {String}  warnMsg  Message to log
     * @param   {Object}           Filter name
     * @return  void
     */

    warn( warnMsg, { filterName } = {} ) {

        const msgPrimary = colors.red( `\u2718 ${warnMsg}` )

        if ( filterName ) {
            const msgSecondary = colors.gray( filterName )

            return console.warn(
                this.padEnd( msgPrimary, msgSecondary )
            )
        }

        return console.warn( msgPrimary )

    },

    /**
     * Log a success message
     *
     * @param   {String}  okMsg  Message to log
     * @param   {Object}           Silent mode, filter name
     * @return  void
     */

    ok( okMsg, { silentMode, filterName } = {} ) {

        if ( silentMode ) {
            return
        }

        const msgPrimary = colors.green( `\u2714 ${okMsg}` )

        if ( filterName ) {
            const msgSecondary = colors.gray( filterName )

            return console.log(
                this.padEnd( msgPrimary, msgSecondary )
            )
        }

        return console.log( msgPrimary )

    },

    /**
     * Log a info message
     *
     * @param   {String}  infoMsg  Message to log
     * @param   {Object}           Silent mode, filter name
     * @return  void
     */

    info( infoMsg, { silentMode, filterName } = {} ) {

        if ( silentMode ) {
            return
        }

        const msgPrimary = colors.yellow( `\u2139 ${infoMsg}` )

        if ( filterName ) {
            const msgSecondary = colors.gray( filterName )

            return console.log(
                this.padEnd( msgPrimary, msgSecondary )
            )
        }

        return console.log( msgPrimary )

    },

    /**
     * Pads the current string with spaces and add a string
     *
     * @param   {String}  msgPrimary    Primary string
     * @param   {String}  msgSecondary  Secondary (gray) string
     * @return  {String}                Concated string
     */

    padEnd( msgPrimary, msgSecondary ) {

        return `${padEnd( msgPrimary, 99 )} ${msgSecondary}`

    }

}
<|endoftext|>


<commit_before>/**
 * @fileoverview 向控制台写入消息
 * @author AceMood
 * @email zmike86@gmail.com
 */

'use strict';

// system
var chalk = require('chalk');

/**
 * 显示错误消息但不退出进程.
 * @param {string} var_msg
 */
exports.error = function (var_msg) {
    var msg = Array.prototype.join.call(arguments, '');
    msg = String(msg);
    console.info(chalk.red.bold(msg))
};

/**
 * 显示警告.
 * @param {string} var_msg
 */
exports.warn = function (var_msg) {
    var msg = Array.prototype.join.call(arguments, '');
    msg = String(msg);
    console.info(chalk.yellow(msg));
};

/**
 * 显示完成消息.
 * @param {string} var_msg
 */
exports.ok = function (var_msg) {
    var msg = Array.prototype.join.call(arguments, '');
    msg = String(msg);
    console.info(chalk.green(msg))
};

/**
 * 显示实用信息.
 * @param {string} var_msg
 */
exports.info = function (var_msg) {
    var msg = Array.prototype.join.call(arguments, '');
    msg = String(msg);
    console.info(chalk.cyan(msg))
};<commit_msg>remove chalk dependance<commit_after>/**
 * @file 向控制台写入消息
 */

'use strict';

var E = String.fromCharCode(27);

function wrap(options, text) {
  return E + '[' + options + 'm' + text + E + '[m';
}

function bold(text) {
  return wrap('1', text);
}

function underline(text) {
  return wrap('4', text);
}

function awesome(text) {
  return wrap('1;4;7;5;42;35', text);
}

var colors = {
  black: 0,
  red: 1,
  green: 2,
  yellow: 3,
  blue: 4,
  magenta: 5,
  cyan: 6,
  white: 7
};

function color(name, text) {
  return E + '[' + (colors[name] + 30) + 'm' + text + E + '[39m';
}

exports.bold = bold;
exports.underline = underline;
exports.awesome = awesome;
exports.color = color;

/**
 * 显示错误消息但不退出进程.
 * @param {string} var_msg
 */
exports.error = function(var_msg) {
  var msg = Array.prototype.join.call(arguments, '');
  msg = String(msg);
  console.log(color('red', msg));
};

/**
 * 显示警告.
 * @param {string} var_msg
 */
exports.warn = function(var_msg) {
  var msg = Array.prototype.join.call(arguments, '');
  msg = String(msg);
  console.log(color('yellow', msg));
};

/**
 * 显示完成消息.
 * @param {string} var_msg
 */
exports.ok = function(var_msg) {
  var msg = Array.prototype.join.call(arguments, '');
  msg = String(msg);
  console.log(color('green', msg));
};

/**
 * 显示实用信息.
 * @param {string} var_msg
 */
exports.info = function(var_msg) {
  var msg = Array.prototype.join.call(arguments, '');
  msg = String(msg);
  console.log(color('cyan', msg));
};<|endoftext|>


<commit_before>module("NFA");

test("Empty", function() {
    var nfa = NFA.empty();

    nfa.begin();
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), []);
});

test("Single token", function() {
    var nfa = NFA.forToken("T");

    nfa.begin();
    equal(nfa.isFinal(), false);
    deepEqual(nfa.follow(), ["T"]);

    nfa.consume("T");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), []);
});

test("Single function token", function() {
    var fn = function(token) { return token == "t" || token == "T"; };
    var nfa = NFA.forToken(fn);

    nfa.begin();
    equal(nfa.isFinal(), false);
    deepEqual(nfa.follow(), [fn]);

    nfa.consume("t");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), []);
});

test("Not-accept", function() {
    var nfa = NFA.forToken("T");

    nfa.begin();
    nfa.consume("x");
    equal(nfa.isFinal(), false);
    deepEqual(nfa.follow(), []);
});

test("Concatenation", function() {
    var nfa = NFA.concatenation(NFA.forToken("a"), NFA.forToken("b"));

    nfa.begin();
    equal(nfa.isFinal(), false);
    deepEqual(nfa.follow(), ["a"]);

    nfa.consume("a");
    equal(nfa.isFinal(), false);
    deepEqual(nfa.follow(), ["b"]);

    nfa.consume("b");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), []);
});

test("Concatenate zero", function() {
    var nfa = NFA.concatenation();

    nfa.begin();
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), []);
});

test("Concatenate one", function() {
    var nfa = NFA.concatenation(NFA.forToken("a"));

    nfa.begin();
    equal(nfa.isFinal(), false);
    deepEqual(nfa.follow(), ["a"]);

    nfa.consume("a");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), []);
});

test("Concatenate many", function() {
    var nfa = NFA.concatenation(
        NFA.forToken("a"),
        NFA.forToken("b"),
        NFA.forToken("c"),
        NFA.forToken("d")
    );

    nfa.begin();
    equal(nfa.isFinal(), false);
    deepEqual(nfa.follow(), ["a"]);

    nfa.consume("abc");
    equal(nfa.isFinal(), false);
    deepEqual(nfa.follow(), ["d"]);

    nfa.consume("d");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), []);
});

test("Union", function() {
    var nfa = NFA.union(NFA.forToken("a"), NFA.forToken("b"));

    nfa.begin();
    equal(nfa.isFinal(), false);
    deepEqual(nfa.follow().sort(), ["a", "b"]);

    nfa.consume("a");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), []);

    nfa.begin();
    equal(nfa.isFinal(), false);
    deepEqual(nfa.follow().sort(), ["a", "b"]);

    nfa.consume("b");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), []);
});

test("Union zero", function() {
    var nfa = NFA.union();

    nfa.begin();
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), []);
});

test("Union one", function() {
    var nfa = NFA.union(NFA.forToken("a"));

    nfa.begin();
    equal(nfa.isFinal(), false);
    deepEqual(nfa.follow(), ["a"]);

    nfa.consume("a");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), []);
});

test("Union many", function() {
    var nfa = NFA.union(
        NFA.forToken("a"),
        NFA.forToken("b"),
        NFA.forToken("c"),
        NFA.forToken("d")
    );

    nfa.begin();
    equal(nfa.isFinal(), false);
    deepEqual(nfa.follow().sort(), ["a", "b", "c", "d"]);

    nfa.consume("a");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), []);

    nfa.begin();
    nfa.consume("b");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), []);
});

test("Kleene", function() {
    var nfa = NFA.kleene(NFA.forToken("x"));

    nfa.begin();
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), ["x"]);

    nfa.consume("x");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), ["x"]);

    nfa.consume("x");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), ["x"]);
});

test("Quantify", function() {
    var nfa = NFA.quantify(NFA.concatenation(NFA.forToken("a"), NFA.forToken("b")), 2, 3);

    nfa.begin();
    equal(nfa.isFinal(), false);
    deepEqual(nfa.follow(), ["a"]);

    nfa.consume("ab");
    equal(nfa.isFinal(), false);
    deepEqual(nfa.follow(), ["a"]);

    nfa.consume("ab");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), ["a"]);

    nfa.consume("ab");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), []);
});

test("Complex", function() {
    var nfa1 = NFA.concatenation(NFA.concatenation(NFA.forToken("a"), NFA.forToken("b")), NFA.forToken("c")) // abc
    var nfa2 = NFA.concatenation(NFA.forToken("a"), NFA.kleene(NFA.forToken("b"))); // ab*
    var nfa3 = NFA.kleene(NFA.concatenation(NFA.forToken("a"), NFA.forToken("b"))); // (ab)*

    var nfa = NFA.union(nfa1, NFA.union(nfa2, nfa3)); // abc | ab* | (ab)*

    nfa.begin();
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), ["a"]);

    nfa.consume("a");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), ["b"]);

    nfa.consume("b");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow().sort(), ["a", "b", "c"]);

    nfa.consume("b");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), ["b"]);

    nfa.begin();
    nfa.consume("aba");
    equal(nfa.isFinal(), false);
    deepEqual(nfa.follow(), ["b"]);

    nfa.consume("b");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), ["a"]);

    nfa = NFA.concatenation(nfa, nfa.clone()); // (abc | ab* | (ab)*) (abc | ab* | (ab)*)

    nfa.begin();
    nfa.consume("abc");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), ["a"]);

    nfa.consume("abc");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), []);

    nfa.begin();
    nfa.consume("abb");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow().sort(), ["a", "b"]);

    nfa.consume("aba");
    equal(nfa.isFinal(), false);
    deepEqual(nfa.follow(), ["b"]);

    nfa.consume("b");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), ["a"]);
});

test("Event not-accept", function() {
    var digit = function(token) { return /[0-9]/.test(token); };
    var nfa = NFA.concatenation(
        NFA.quantify(NFA.forToken(digit), 4, 4),
        NFA.forToken("-"),
        NFA.quantify(NFA.forToken(digit), 2, 2),
        NFA.forToken("-"),
        NFA.quantify(NFA.forToken(digit), 2, 2));

    $(nfa).on("not-accept", function(evt) {
        var follow = nfa.follow();
        if (follow.length == 1 && !(follow[0] instanceof Function)) {
            nfa.consume(follow[0]);
            nfa.consume(evt.token);
        }
        evt.preventDefault();
    });

    nfa.begin();
    nfa.consume("2014-01-01");
    equal(nfa.isFinal(), true);

    nfa.begin();
    nfa.consume("20140101");
    equal(nfa.isFinal(), true);

    nfa.begin();
    nfa.consume("20-14-01-01");
    equal(nfa.isFinal(), true);
});

module("PatternParser");

test("Empty", function() {
    var parser = new PatternParser("");

    equal(parser.nfa.isFinal(), true);
    deepEqual(parser.nfa.follow(), []);
});

test("Invalid", function() {
    throws(function() { new PatternParser("*"); });
});

test("Concatenation", function() {
    var parser = new PatternParser("abc");

    equal(parser.nfa.isFinal(), false);
    deepEqual(parser.nfa.follow(), ["a"]);

    parser.nfa.consume("abc");
    equal(parser.nfa.isFinal(), true);
    deepEqual(parser.nfa.follow(), []);
});

test("Union", function() {
    var parser = new PatternParser("abc|def");

    equal(parser.nfa.isFinal(), false);
    deepEqual(parser.nfa.follow().sort(), ["a", "d"]);

    parser.nfa.consume("abc");
    equal(parser.nfa.isFinal(), true);
    deepEqual(parser.nfa.follow(), []);

    parser.nfa.begin();
    parser.nfa.consume("def");
    equal(parser.nfa.isFinal(), true);
    deepEqual(parser.nfa.follow(), []);
});

test("Union empty", function() {
    var parser = new PatternParser("abc|");

    equal(parser.nfa.isFinal(), true);
    deepEqual(parser.nfa.follow(), ["a"]);
});

test("Kleene", function() {
    var parser = new PatternParser("abc*");

    equal(parser.nfa.isFinal(), false);
    deepEqual(parser.nfa.follow(), ["a"]);

    parser.nfa.consume("ab");
    equal(parser.nfa.isFinal(), true);
    deepEqual(parser.nfa.follow(), ["c"]);

    parser.nfa.consume("ccccccc");
    equal(parser.nfa.isFinal(), true);
    deepEqual(parser.nfa.follow(), ["c"]);
});

test("Other quantifiers", function() {
    var parser = new PatternParser("a?bc{2,3}");

    equal(parser.nfa.isFinal(), false);
    deepEqual(parser.nfa.follow().sort(), ["a", "b"]);

    parser.nfa.consume("b");
    equal(parser.nfa.isFinal(), false);
    deepEqual(parser.nfa.follow(), ["c"]);

    parser.nfa.consume("c");
    equal(parser.nfa.isFinal(), false);
    deepEqual(parser.nfa.follow(), ["c"]);

    parser.nfa.consume("c");
    equal(parser.nfa.isFinal(), true);
    deepEqual(parser.nfa.follow(), ["c"]);

    parser.nfa.consume("c");
    equal(parser.nfa.isFinal(), true);
    deepEqual(parser.nfa.follow(), []);
});

test("Complex", function() {
    var parser = new PatternParser("((x|y){2,3}-){2}(x|y)(x|y|z)*");

    equal(parser.nfa.isFinal(), false);
    deepEqual(parser.nfa.follow().sort(), ["x", "y"]);

    parser.nfa.consume("xy-xxx-yxxyzz");
    equal(parser.nfa.isFinal(), true);
    deepEqual(parser.nfa.follow().sort(), ["x", "y", "z"]);

    parser.nfa.begin();
    parser.nfa.consume("xxy-y-");
    equal(parser.nfa.isFinal(), false);
    deepEqual(parser.nfa.follow(), []);

    parser.nfa.begin();
    parser.nfa.consume("yyx-yy-z");
    equal(parser.nfa.isFinal(), false);
    deepEqual(parser.nfa.follow(), []);

    parser.nfa.begin();
    parser.nfa.consume("xxx-yz");
    equal(parser.nfa.isFinal(), false);
    deepEqual(parser.nfa.follow(), []);
});

/* vim: set et ts=4 sw=4: */
<commit_msg>A few more parsing tests<commit_after>module("NFA");

test("Empty", function() {
    var nfa = NFA.empty();

    nfa.begin();
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), []);
});

test("Single token", function() {
    var nfa = NFA.forToken("T");

    nfa.begin();
    equal(nfa.isFinal(), false);
    deepEqual(nfa.follow(), ["T"]);

    nfa.consume("T");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), []);
});

test("Single function token", function() {
    var fn = function(token) { return token == "t" || token == "T"; };
    var nfa = NFA.forToken(fn);

    nfa.begin();
    equal(nfa.isFinal(), false);
    deepEqual(nfa.follow(), [fn]);

    nfa.consume("t");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), []);
});

test("Not-accept", function() {
    var nfa = NFA.forToken("T");

    nfa.begin();
    nfa.consume("x");
    equal(nfa.isFinal(), false);
    deepEqual(nfa.follow(), []);
});

test("Concatenation", function() {
    var nfa = NFA.concatenation(NFA.forToken("a"), NFA.forToken("b"));

    nfa.begin();
    equal(nfa.isFinal(), false);
    deepEqual(nfa.follow(), ["a"]);

    nfa.consume("a");
    equal(nfa.isFinal(), false);
    deepEqual(nfa.follow(), ["b"]);

    nfa.consume("b");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), []);
});

test("Concatenate zero", function() {
    var nfa = NFA.concatenation();

    nfa.begin();
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), []);
});

test("Concatenate one", function() {
    var nfa = NFA.concatenation(NFA.forToken("a"));

    nfa.begin();
    equal(nfa.isFinal(), false);
    deepEqual(nfa.follow(), ["a"]);

    nfa.consume("a");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), []);
});

test("Concatenate many", function() {
    var nfa = NFA.concatenation(
        NFA.forToken("a"),
        NFA.forToken("b"),
        NFA.forToken("c"),
        NFA.forToken("d")
    );

    nfa.begin();
    equal(nfa.isFinal(), false);
    deepEqual(nfa.follow(), ["a"]);

    nfa.consume("abc");
    equal(nfa.isFinal(), false);
    deepEqual(nfa.follow(), ["d"]);

    nfa.consume("d");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), []);
});

test("Union", function() {
    var nfa = NFA.union(NFA.forToken("a"), NFA.forToken("b"));

    nfa.begin();
    equal(nfa.isFinal(), false);
    deepEqual(nfa.follow().sort(), ["a", "b"]);

    nfa.consume("a");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), []);

    nfa.begin();
    equal(nfa.isFinal(), false);
    deepEqual(nfa.follow().sort(), ["a", "b"]);

    nfa.consume("b");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), []);
});

test("Union zero", function() {
    var nfa = NFA.union();

    nfa.begin();
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), []);
});

test("Union one", function() {
    var nfa = NFA.union(NFA.forToken("a"));

    nfa.begin();
    equal(nfa.isFinal(), false);
    deepEqual(nfa.follow(), ["a"]);

    nfa.consume("a");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), []);
});

test("Union many", function() {
    var nfa = NFA.union(
        NFA.forToken("a"),
        NFA.forToken("b"),
        NFA.forToken("c"),
        NFA.forToken("d")
    );

    nfa.begin();
    equal(nfa.isFinal(), false);
    deepEqual(nfa.follow().sort(), ["a", "b", "c", "d"]);

    nfa.consume("a");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), []);

    nfa.begin();
    nfa.consume("b");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), []);
});

test("Kleene", function() {
    var nfa = NFA.kleene(NFA.forToken("x"));

    nfa.begin();
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), ["x"]);

    nfa.consume("x");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), ["x"]);

    nfa.consume("x");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), ["x"]);
});

test("Quantify", function() {
    var nfa = NFA.quantify(NFA.concatenation(NFA.forToken("a"), NFA.forToken("b")), 2, 3);

    nfa.begin();
    equal(nfa.isFinal(), false);
    deepEqual(nfa.follow(), ["a"]);

    nfa.consume("ab");
    equal(nfa.isFinal(), false);
    deepEqual(nfa.follow(), ["a"]);

    nfa.consume("ab");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), ["a"]);

    nfa.consume("ab");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), []);
});

test("Complex", function() {
    var nfa1 = NFA.concatenation(NFA.concatenation(NFA.forToken("a"), NFA.forToken("b")), NFA.forToken("c")) // abc
    var nfa2 = NFA.concatenation(NFA.forToken("a"), NFA.kleene(NFA.forToken("b"))); // ab*
    var nfa3 = NFA.kleene(NFA.concatenation(NFA.forToken("a"), NFA.forToken("b"))); // (ab)*

    var nfa = NFA.union(nfa1, NFA.union(nfa2, nfa3)); // abc | ab* | (ab)*

    nfa.begin();
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), ["a"]);

    nfa.consume("a");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), ["b"]);

    nfa.consume("b");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow().sort(), ["a", "b", "c"]);

    nfa.consume("b");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), ["b"]);

    nfa.begin();
    nfa.consume("aba");
    equal(nfa.isFinal(), false);
    deepEqual(nfa.follow(), ["b"]);

    nfa.consume("b");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), ["a"]);

    nfa = NFA.concatenation(nfa, nfa.clone()); // (abc | ab* | (ab)*) (abc | ab* | (ab)*)

    nfa.begin();
    nfa.consume("abc");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), ["a"]);

    nfa.consume("abc");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), []);

    nfa.begin();
    nfa.consume("abb");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow().sort(), ["a", "b"]);

    nfa.consume("aba");
    equal(nfa.isFinal(), false);
    deepEqual(nfa.follow(), ["b"]);

    nfa.consume("b");
    equal(nfa.isFinal(), true);
    deepEqual(nfa.follow(), ["a"]);
});

test("Event not-accept", function() {
    var digit = function(token) { return /[0-9]/.test(token); };
    var nfa = NFA.concatenation(
        NFA.quantify(NFA.forToken(digit), 4, 4),
        NFA.forToken("-"),
        NFA.quantify(NFA.forToken(digit), 2, 2),
        NFA.forToken("-"),
        NFA.quantify(NFA.forToken(digit), 2, 2));

    $(nfa).on("not-accept", function(evt) {
        var follow = nfa.follow();
        if (follow.length == 1 && !(follow[0] instanceof Function)) {
            nfa.consume(follow[0]);
            nfa.consume(evt.token);
        }
        evt.preventDefault();
    });

    nfa.begin();
    nfa.consume("2014-01-01");
    equal(nfa.isFinal(), true);

    nfa.begin();
    nfa.consume("20140101");
    equal(nfa.isFinal(), true);

    nfa.begin();
    nfa.consume("20-14-01-01");
    equal(nfa.isFinal(), true);
});

module("PatternParser");

test("Empty", function() {
    var parser = new PatternParser("");

    equal(parser.nfa.isFinal(), true);
    deepEqual(parser.nfa.follow(), []);
});

test("Invalid", function() {
    throws(function() {
        new PatternParser("*");
    });
    throws(function() {
        new PatternParser("a|+");
    });
    throws(function() {
        new PatternParser("a*?");
    });
    throws(function() {
        new PatternParser("({3,5})");
    });
    throws(function() {
        new PatternParser("(");
    });
    throws(function() {
        new PatternParser(")");
    });
});

test("Concatenation", function() {
    var parser = new PatternParser("abc");

    equal(parser.nfa.isFinal(), false);
    deepEqual(parser.nfa.follow(), ["a"]);

    parser.nfa.consume("abc");
    equal(parser.nfa.isFinal(), true);
    deepEqual(parser.nfa.follow(), []);
});

test("Union", function() {
    var parser = new PatternParser("abc|def");

    equal(parser.nfa.isFinal(), false);
    deepEqual(parser.nfa.follow().sort(), ["a", "d"]);

    parser.nfa.consume("abc");
    equal(parser.nfa.isFinal(), true);
    deepEqual(parser.nfa.follow(), []);

    parser.nfa.begin();
    parser.nfa.consume("def");
    equal(parser.nfa.isFinal(), true);
    deepEqual(parser.nfa.follow(), []);
});

test("Union empty", function() {
    var parser = new PatternParser("abc|");

    equal(parser.nfa.isFinal(), true);
    deepEqual(parser.nfa.follow(), ["a"]);
});

test("Kleene", function() {
    var parser = new PatternParser("abc*");

    equal(parser.nfa.isFinal(), false);
    deepEqual(parser.nfa.follow(), ["a"]);

    parser.nfa.consume("ab");
    equal(parser.nfa.isFinal(), true);
    deepEqual(parser.nfa.follow(), ["c"]);

    parser.nfa.consume("ccccccc");
    equal(parser.nfa.isFinal(), true);
    deepEqual(parser.nfa.follow(), ["c"]);
});

test("Other quantifiers", function() {
    var parser = new PatternParser("a?bc{2,3}");

    equal(parser.nfa.isFinal(), false);
    deepEqual(parser.nfa.follow().sort(), ["a", "b"]);

    parser.nfa.consume("b");
    equal(parser.nfa.isFinal(), false);
    deepEqual(parser.nfa.follow(), ["c"]);

    parser.nfa.consume("c");
    equal(parser.nfa.isFinal(), false);
    deepEqual(parser.nfa.follow(), ["c"]);

    parser.nfa.consume("c");
    equal(parser.nfa.isFinal(), true);
    deepEqual(parser.nfa.follow(), ["c"]);

    parser.nfa.consume("c");
    equal(parser.nfa.isFinal(), true);
    deepEqual(parser.nfa.follow(), []);
});

test("Special literals", function() {
    var parser = new PatternParser("{23:24}");
    parser.nfa.consume("{23:24}");
    equal(parser.nfa.isFinal(), true);

    parser = new PatternParser("]a;b]");
    parser.nfa.consume("]a;b]");
    equal(parser.nfa.isFinal(), true);
});

test("Escape sequences", function() {
    var parser = new PatternParser("\\(a\\*\\)\\|a\\?\\\\\\.\\{2,3\\}");

    parser.nfa.consume("(a*)|a?\\.{2,3}")
    equal(parser.nfa.isFinal(), true);
});

test("Complex", function() {
    var parser = new PatternParser("((x|y){2,3}-){2}.(x|y|z)*");

    equal(parser.nfa.isFinal(), false);
    deepEqual(parser.nfa.follow().sort(), ["x", "y"]);

    parser.nfa.consume("xy-xxx-kxxyzz");
    equal(parser.nfa.isFinal(), true);
    deepEqual(parser.nfa.follow().sort(), ["x", "y", "z"]);

    parser.nfa.begin();
    parser.nfa.consume("xxy-y-");
    equal(parser.nfa.isFinal(), false);
    deepEqual(parser.nfa.follow(), []);

    parser.nfa.begin();
    parser.nfa.consume("xxx-yz");
    equal(parser.nfa.isFinal(), false);
    deepEqual(parser.nfa.follow(), []);
});

/* vim: set et ts=4 sw=4: */
<|endoftext|>


<commit_before>'use strict';

var fs = require('fs'),
    path = require('path'),
    filePath = path.join(process.cwd(), 'react-collider.log')

module.exports = function log(file, type, value) {
    if (typeof file === 'string') {
        filePath = file
    }

    var message

    switch (type) {
        case 'perf':
            message = '[' + value.startTime + '] ' + value.path + ' rendered in ' + value.time + 'ms'
            break
    }

    fs.writeFile(filePath, message, {flag: 'a'})
}
<commit_msg>Missing line break<commit_after>'use strict';

var fs = require('fs'),
    path = require('path'),
    filePath = path.join(process.cwd(), 'react-collider.log')

module.exports = function log(file, type, value) {
    if (typeof file === 'string') {
        filePath = file
    }

    var message

    switch (type) {
        case 'perf':
            message = '[' + value.startTime + '] ' + value.path + ' rendered in ' + value.time + 'ms\n'
            break
    }

    fs.writeFile(filePath, message, {flag: 'a'})
}
<|endoftext|>


<commit_before>'use strict';

var $ = require('jquery');
var _ = require('underscore');
var querystring = require('querystring');
var fs = require('fs');
var store = require('store');
var mouse = require('mousetrap');
var BingLayer = require('./ext/bing.js');

var core = require('./core');
var template = _(fs.readFileSync('./templates/map.html', 'utf8')).template();

// transparent street layer for putting on top of other layers
var contextLayer = L.mapbox.tileLayer('aaronlidman.87d3cc29', {
    detectRetina: false
});

var layers = {
    'Bing Satellite': new BingLayer('Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU'),
    'Mapbox Satellite': L.mapbox.tileLayer('aaronlidman.j5kfpn4g', { detectRetina: false }),
    'Streets': L.mapbox.tileLayer('aaronlidman.jgo996i0'),
    'OSM.org': L.tileLayer('http://a.tile.openstreetmap.org/{z}/{x}/{y}.png', {
        attribution: '© OpenStreetMap contributors'
    })
};

var baseLayer = store.get('baseLayer') || 'Streets';

window.featureStyle = {
    color: '#FF00B7',
    opacity: 1,
    weight: 4
};

window.altStyle = {
    color: '#00BFFF',
    opacity: 1,
    weight: 4
};

module.exports = {
    init: function() {

        // map is already initialized
        if ($('#map').length) return;
        $('#main').append(template(window.current));
        this.handlers(); // Attach handlers to edit bar

        window.map = L.mapbox.map('map', {'mapbox_logo': true}, {
            maxZoom: 18,
            keyboard: false
        }).setView([22.76, -25.84], 3);

        window.map.zoomControl.setPosition('topright');

        // Layer controller
        layers[baseLayer].addTo(window.map);
        if (baseLayer == 'Bing Satellite') contextLayer.addTo(window.map).bringToFront();
        L.control.layers(layers).addTo(window.map);
        window.map.on('baselayerchange', function(e) {
            store.set('baseLayer', e.name);
            if (e.name == 'Bing Satellite') {
                contextLayer.addTo(window.map).bringToFront();
            } else {
                if (window.map.hasLayer(contextLayer)) window.map.removeLayer(contextLayer);
            }
        });
        window.featureGroup = L.featureGroup().addTo(window.map);
    },

    handlers: function() {
        var self = this;
        $('#edit').on('click', function() {
            self.edit();
            return false;
        });

        $('#skip').on('click', function() {
            self.clear();
            window.current.loader.next();
            return false;
        });

        $('#fixed').on('click', function() {
            self.clear();
            core.mark('done', window.current.loader.next);
            return false;
        });

        mouse.bind('e', function() {
            $('#edit').click();
        });

        mouse.bind('s', function() {
            $('#skip').click();
        });
    },

    edit: function() {
        var bottom = window.current.item._bounds._southWest.lat - 0.001;
        var left = window.current.item._bounds._southWest.lng - 0.001;
        var top = window.current.item._bounds._northEast.lat + 0.001;
        var right = window.current.item._bounds._northEast.lng + 0.001;

        $(window.map.getContainer()).addClass('loading');
        $.ajax('http://localhost:8111/load_and_zoom?' + querystring.stringify({
            left: left,
            right: right,
            top: top,
            bottom: bottom,
            select: window.current.item._osm_object_type + window.current.item._osm_object_id
        }), {
            error: function() {
                $(window.map.getContainer()).removeClass('loading');

                // if JOSM doesn't respond fallback to iD
                var url = 'http://openstreetmap.us/iD/release/#';
                if (window.current.item._osm_object_type && window.current.item._osm_object_id) {
                    url += 'id=' + window.current.item._osm_object_type.slice(0, 1) + window.current.item._osm_object_id;
                } else {
                    url += 'map=' + window.map.getZoom() + '/' + window.map.getCenter().lng + '/' + window.map.getCenter().lat;
                }

                $('#main').append('');
                $('#iD_escape')
                    .removeClass('hidden')
                    .on('click', function() {
                        $('#iD').remove();
                        $('#skip').click();
                        $('#iD_escape')
                            .addClass('hidden')
                            .unbind();

                        return false;
                    });
            },
            success: function() {
                // this newWindow dance is to get around some browser limitations
                // so we always open a new window, if we need it we populate the url, else, just close the empty window
                // this all happens quick enough to not cause issues for the user
                // it's all commented out because I want to make it a setting in the future
                // whether iD loads in an iframe or a new window
                // newWindow.close();
                $('#message')
                    .text('Opened in JOSM')
                    .show();
                $('#message').slideDown();
                window.setTimeout(function() {
                    $('#message').slideUp();
                }, 5000);

                $(window.map.getContainer()).removeClass('loading');
            }
        });
    },

    clear: function() {
        window.featureGroup.getLayers().forEach(function(layer) {
            window.featureGroup.removeLayer(layer);
        });
    }
};
<commit_msg>'f' for fixed<commit_after>'use strict';

var $ = require('jquery');
var _ = require('underscore');
var querystring = require('querystring');
var fs = require('fs');
var store = require('store');
var mouse = require('mousetrap');
var BingLayer = require('./ext/bing.js');

var core = require('./core');
var template = _(fs.readFileSync('./templates/map.html', 'utf8')).template();

// transparent street layer for putting on top of other layers
var contextLayer = L.mapbox.tileLayer('aaronlidman.87d3cc29', {
    detectRetina: false
});

var layers = {
    'Bing Satellite': new BingLayer('Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU'),
    'Mapbox Satellite': L.mapbox.tileLayer('aaronlidman.j5kfpn4g', { detectRetina: false }),
    'Streets': L.mapbox.tileLayer('aaronlidman.jgo996i0'),
    'OSM.org': L.tileLayer('http://a.tile.openstreetmap.org/{z}/{x}/{y}.png', {
        attribution: '© OpenStreetMap contributors'
    })
};

var baseLayer = store.get('baseLayer') || 'Streets';

window.featureStyle = {
    color: '#FF00B7',
    opacity: 1,
    weight: 4
};

window.altStyle = {
    color: '#00BFFF',
    opacity: 1,
    weight: 4
};

module.exports = {
    init: function() {

        // map is already initialized
        if ($('#map').length) return;
        $('#main').append(template(window.current));
        this.handlers(); // Attach handlers to edit bar

        window.map = L.mapbox.map('map', {'mapbox_logo': true}, {
            maxZoom: 18,
            keyboard: false
        }).setView([22.76, -25.84], 3);

        window.map.zoomControl.setPosition('topright');

        // Layer controller
        layers[baseLayer].addTo(window.map);
        if (baseLayer == 'Bing Satellite') contextLayer.addTo(window.map).bringToFront();
        L.control.layers(layers).addTo(window.map);
        window.map.on('baselayerchange', function(e) {
            store.set('baseLayer', e.name);
            if (e.name == 'Bing Satellite') {
                contextLayer.addTo(window.map).bringToFront();
            } else {
                if (window.map.hasLayer(contextLayer)) window.map.removeLayer(contextLayer);
            }
        });
        window.featureGroup = L.featureGroup().addTo(window.map);
    },

    handlers: function() {
        var self = this;
        $('#edit').on('click', function() {
            self.edit();
            return false;
        });

        $('#skip').on('click', function() {
            self.clear();
            window.current.loader.next();
            return false;
        });

        $('#fixed').on('click', function() {
            self.clear();
            core.mark('done', window.current.loader.next);
            return false;
        });

        mouse.bind('e', function() {
            $('#edit').click();
        });

        mouse.bind('s', function() {
            $('#skip').click();
        });

        mouse.bind('f', function() {
            $('#fixed').click();
        });
    },

    edit: function() {
        var bottom = window.current.item._bounds._southWest.lat - 0.001;
        var left = window.current.item._bounds._southWest.lng - 0.001;
        var top = window.current.item._bounds._northEast.lat + 0.001;
        var right = window.current.item._bounds._northEast.lng + 0.001;

        $(window.map.getContainer()).addClass('loading');
        $.ajax('http://localhost:8111/load_and_zoom?' + querystring.stringify({
            left: left,
            right: right,
            top: top,
            bottom: bottom,
            select: window.current.item._osm_object_type + window.current.item._osm_object_id
        }), {
            error: function() {
                $(window.map.getContainer()).removeClass('loading');

                // if JOSM doesn't respond fallback to iD
                var url = 'http://openstreetmap.us/iD/release/#';
                if (window.current.item._osm_object_type && window.current.item._osm_object_id) {
                    url += 'id=' + window.current.item._osm_object_type.slice(0, 1) + window.current.item._osm_object_id;
                } else {
                    url += 'map=' + window.map.getZoom() + '/' + window.map.getCenter().lng + '/' + window.map.getCenter().lat;
                }

                $('#main').append('');
                $('#iD_escape')
                    .removeClass('hidden')
                    .on('click', function() {
                        $('#iD').remove();
                        $('#skip').click();
                        $('#iD_escape')
                            .addClass('hidden')
                            .unbind();

                        return false;
                    });
            },
            success: function() {
                // this newWindow dance is to get around some browser limitations
                // so we always open a new window, if we need it we populate the url, else, just close the empty window
                // this all happens quick enough to not cause issues for the user
                // it's all commented out because I want to make it a setting in the future
                // whether iD loads in an iframe or a new window
                // newWindow.close();
                $('#message')
                    .text('Opened in JOSM')
                    .show();
                $('#message').slideDown();
                window.setTimeout(function() {
                    $('#message').slideUp();
                }, 5000);

                $(window.map.getContainer()).removeClass('loading');
            }
        });
    },

    clear: function() {
        window.featureGroup.getLayers().forEach(function(layer) {
            window.featureGroup.removeLayer(layer);
        });
    }
};
<|endoftext|>