<commit_before>'use strict'

var toString = require('nlcst-to-string')
var modifier = require('unist-util-modify-children')
var gemoji = require('gemoji')

module.exports = modifier(mergeEmoji)

var own = {}.hasOwnProperty

var EMOTICON_NODE = 'EmoticonNode'

/* Magic numbers.
 *
 * Gemoji's are treated by a parser as multiple nodes.
 * Because this modifier walks backwards, the first colon
 * never matches a gemoji it would normaly walk back to
 * the beginning (the first node). However, because the
 * longest gemoji is tokenized as `Punctuation` (`:`),
 * `Punctuation` (`+`), `Word` (`1`), and `Punctuation`
 * (`:`), we can safely break when the modifier walked
 * back more than 4 times. */
var MAX_GEMOJI_PART_COUNT = 12

var shortcodes = []
var unicodes = gemoji.unicode
var byName = gemoji.name
var key

for (key in byName) {
  shortcodes.push(':' + key + ':')
}

/* Merge emoji and github-emoji (punctuation marks,
 * symbols, and words) into an `EmoticonNode`. */
function mergeEmoji(child, index, parent) {
  var siblings = parent.children
  var value = toString(child)
  var siblingIndex
  var node
  var nodes
  var subvalue
  var left
  var right
  var leftMatch
  var rightMatch
  var start
  var pos
  var end
  var replace
  var startIndex
  var nextSibling
  var nextNextSibling
  var possibleEmoji
  var maxSiblingIndex
  var loopIndex
  var lastSibling
  var lastSiblingIndex

  if (child.type === 'WordNode') {
    /* 1⃣ — sometimes a unicode emoji is marked as a word. Mark it as
     * an `EmoticonNode`. */
    if (own.call(unicodes, value)) {
      node = {type: EMOTICON_NODE, value: value}

      if (child.position) {
        node.position = child.position
      }

      siblings[index] = node
    } else {
      /* ❤ — Sometimes a unicode emoji is split in two.  Remove the last
       * and add its value to the first. */
      node = siblings[index - 1]

      if (node && own.call(unicodes, toString(node) + value)) {
        node.type = EMOTICON_NODE
        node.value = toString(node) + value

        if (child.position && node.position) {
          node.position.end = child.position.end
        }

        siblings.splice(index, 1)

        return index
      }
    }
  } else if (own.call(unicodes, value)) {
    child.type = EMOTICON_NODE
    startIndex = index + 1
    nextSibling = siblings[startIndex]
    if (!nextSibling) {
      return
    }

    if (nextSibling.type === 'WordNode') {
      /* 🏌 — Normal emoji. */
      if (!isVarianceSelector(nextSibling)) {
        return
      }

      possibleEmoji = value + toString(nextSibling)
      maxSiblingIndex = siblings.length
      loopIndex = startIndex + 1

      while (
        loopIndex < maxSiblingIndex &&
        loopIndex - startIndex < 5 &&
        siblings[loopIndex].type !== 'WordNode'
      ) {
        possibleEmoji += toString(siblings[loopIndex])
        loopIndex++
      }

      lastSibling = siblings[loopIndex]

      if (lastSibling && lastSibling.type === 'WordNode') {
        possibleEmoji += toString(lastSibling)
      }

      /* 🏌♀ — Emoji with variance selector. */
      if (own.call(unicodes, possibleEmoji)) {
        child.value = possibleEmoji

        if (child.position && lastSibling.position) {
          child.position.end = lastSibling.position.end
        }

        siblings.splice(index + 1, loopIndex - index)

        return index + 1
      }
      /* 👨❤💋👨 — combined emoji. */
    } else if (nextSibling.type === 'SymbolNode') {
      possibleEmoji = value + toString(nextSibling)
      maxSiblingIndex = siblings.length
      loopIndex = startIndex + 1

      while (
        loopIndex < maxSiblingIndex &&
        loopIndex - startIndex < 5 &&
        (siblings[loopIndex].type === 'SymbolNode' ||
          (siblings[loopIndex].type === 'WordNode' &&
            isVarianceSelector(siblings[loopIndex])))
      ) {
        possibleEmoji += toString(siblings[loopIndex])
        loopIndex++
      }

      if (own.call(unicodes, possibleEmoji)) {
        child.value = possibleEmoji
        lastSiblingIndex = loopIndex - 1
        lastSibling = siblings[lastSiblingIndex]

        if (child.position && lastSibling.position) {
          child.position.end = lastSibling.position.end
        }

        siblings.splice(index + 1, lastSiblingIndex - index)

        return index + 1
      }
    }
    /* 🤽♀ — Combined emoji starting in a symbol. */
  } else if (child.type === 'SymbolNode') {
    nextSibling = siblings[index + 1]
    nextNextSibling = siblings[index + 2]
    if (!nextSibling || !nextNextSibling) {
      return
    }

    if (
      (nextSibling.type === 'SymbolNode' || nextSibling.type === 'WordNode') &&
      nextNextSibling &&
      nextNextSibling.type === 'SymbolNode'
    ) {
      possibleEmoji = value + toString(nextSibling) + toString(nextNextSibling)

      if (own.call(unicodes, possibleEmoji)) {
        child.type = EMOTICON_NODE
        child.value = possibleEmoji

        if (child.position && nextNextSibling.position) {
          child.position.end = nextNextSibling.position.end
        }

        siblings.splice(index + 1, 2)

        return index + 1
      }
    }
    /* :+1: — Gemoji shortcodes. */
  } else if (value.charAt(0) === ':') {
    nodes = []
    siblingIndex = index
    subvalue = value
    left = null
    right = null
    leftMatch = null
    rightMatch = null

    if (subvalue.length === 1) {
      rightMatch = child
    } else {
      end = child.position && child.position.end
      start = end && child.position.start
      pos = end && {
        line: start.line,
        column: start.column + 1,
        offset: start.offset + 1
      }

      rightMatch = {
        type: 'PunctuationNode',
        value: ':'
      }

      right = {
        type: 'PunctuationNode',
        value: subvalue.slice(1)
      }

      if (end) {
        rightMatch.position = {start: start, end: pos}
        right.position = {start: pos, end: end}
      }
    }

    while (siblingIndex--) {
      if (index - siblingIndex > MAX_GEMOJI_PART_COUNT) {
        return
      }

      node = siblings[siblingIndex]

      subvalue = toString(node)

      if (subvalue.charAt(subvalue.length - 1) === ':') {
        leftMatch = node
        break
      }

      if (node.children) {
        nodes = nodes.concat(node.children.concat().reverse())
      } else {
        nodes.push(node)
      }

      if (siblingIndex === 0) {
        return
      }
    }

    if (!leftMatch) {
      return
    }

    subvalue = toString(leftMatch)

    if (subvalue.length !== 1) {
      end = leftMatch.position && leftMatch.position.end
      start = end && leftMatch.position.start
      pos = end && {
        line: end.line,
        column: end.column - 1,
        offset: end.offset - 1
      }

      left = {
        type: 'PunctuationNode',
        value: subvalue.slice(0, -1)
      }

      leftMatch = {
        type: 'PunctuationNode',
        value: ':'
      }

      if (end) {
        left.position = {start: start, end: pos}
        leftMatch.position = {start: pos, end: end}
      }
    }

    nodes.push(leftMatch)
    nodes.reverse().push(rightMatch)

    value = toString(nodes)

    if (shortcodes.indexOf(value) === -1) {
      return
    }

    replace = [siblingIndex, index - siblingIndex + 1]

    if (left) {
      replace.push(left)
    }

    child.type = EMOTICON_NODE
    child.value = value

    if (child.position && leftMatch.position) {
      child.position.start = leftMatch.position.start
    }

    if (child.position && rightMatch.position) {
      child.position.end = rightMatch.position.end
    }

    replace.push(child)

    if (right) {
      replace.push(right)
    }

    ;[].splice.apply(siblings, replace)

    return siblingIndex + 3
  }
}

function isVarianceSelector(node) {
  var code = toString(node).charCodeAt(0)
  return code > 65023 && code < 65040
}
<commit_msg>Refactor comment-style<commit_after>'use strict'

var toString = require('nlcst-to-string')
var modifier = require('unist-util-modify-children')
var gemoji = require('gemoji')

module.exports = modifier(mergeEmoji)

var own = {}.hasOwnProperty

var EMOTICON_NODE = 'EmoticonNode'

// Magic numbers.

// Gemoji’s are treated by a parser as multiple nodes.
// Because this modifier walks backwards, the first colon never matches a gemoji
// it would normaly walk back to the beginning (the first node).
// However, because the longest gemoji is tokenized as `Punctuation` (`:`),
// `Punctuation` (`+`), `Word` (`1`), and `Punctuation` (`:`), we can safely
// break when the modifier walked back more than 4 times.
var MAX_GEMOJI_PART_COUNT = 12

var shortcodes = []
var unicodes = gemoji.unicode
var byName = gemoji.name
var key

for (key in byName) {
  shortcodes.push(':' + key + ':')
}

// Merge emoji and github-emoji (punctuation marks, symbols, and words) into an
// `EmoticonNode`.
function mergeEmoji(child, index, parent) {
  var siblings = parent.children
  var value = toString(child)
  var siblingIndex
  var node
  var nodes
  var subvalue
  var left
  var right
  var leftMatch
  var rightMatch
  var start
  var pos
  var end
  var replace
  var startIndex
  var nextSibling
  var nextNextSibling
  var possibleEmoji
  var maxSiblingIndex
  var loopIndex
  var lastSibling
  var lastSiblingIndex

  if (child.type === 'WordNode') {
    // 1⃣ — sometimes a unicode emoji is marked as a word. Mark it as an
    // `EmoticonNode`.
    if (own.call(unicodes, value)) {
      node = {type: EMOTICON_NODE, value: value}

      if (child.position) {
        node.position = child.position
      }

      siblings[index] = node
    } else {
      // ❤ — Sometimes a unicode emoji is split in two.
      // Remove the last and add its value to the first.
      node = siblings[index - 1]

      if (node && own.call(unicodes, toString(node) + value)) {
        node.type = EMOTICON_NODE
        node.value = toString(node) + value

        if (child.position && node.position) {
          node.position.end = child.position.end
        }

        siblings.splice(index, 1)

        return index
      }
    }
  } else if (own.call(unicodes, value)) {
    child.type = EMOTICON_NODE
    startIndex = index + 1
    nextSibling = siblings[startIndex]
    if (!nextSibling) {
      return
    }

    if (nextSibling.type === 'WordNode') {
      // 🏌 — Normal emoji.
      if (!isVarianceSelector(nextSibling)) {
        return
      }

      possibleEmoji = value + toString(nextSibling)
      maxSiblingIndex = siblings.length
      loopIndex = startIndex + 1

      while (
        loopIndex < maxSiblingIndex &&
        loopIndex - startIndex < 5 &&
        siblings[loopIndex].type !== 'WordNode'
      ) {
        possibleEmoji += toString(siblings[loopIndex])
        loopIndex++
      }

      lastSibling = siblings[loopIndex]

      if (lastSibling && lastSibling.type === 'WordNode') {
        possibleEmoji += toString(lastSibling)
      }

      // 🏌♀ — Emoji with variance selector.
      if (own.call(unicodes, possibleEmoji)) {
        child.value = possibleEmoji

        if (child.position && lastSibling.position) {
          child.position.end = lastSibling.position.end
        }

        siblings.splice(index + 1, loopIndex - index)

        return index + 1
      }
      // 👨❤💋👨 — combined emoji.
    } else if (nextSibling.type === 'SymbolNode') {
      possibleEmoji = value + toString(nextSibling)
      maxSiblingIndex = siblings.length
      loopIndex = startIndex + 1

      while (
        loopIndex < maxSiblingIndex &&
        loopIndex - startIndex < 5 &&
        (siblings[loopIndex].type === 'SymbolNode' ||
          (siblings[loopIndex].type === 'WordNode' &&
            isVarianceSelector(siblings[loopIndex])))
      ) {
        possibleEmoji += toString(siblings[loopIndex])
        loopIndex++
      }

      if (own.call(unicodes, possibleEmoji)) {
        child.value = possibleEmoji
        lastSiblingIndex = loopIndex - 1
        lastSibling = siblings[lastSiblingIndex]

        if (child.position && lastSibling.position) {
          child.position.end = lastSibling.position.end
        }

        siblings.splice(index + 1, lastSiblingIndex - index)

        return index + 1
      }
    }
    // 🤽♀ — Combined emoji starting in a symbol.
  } else if (child.type === 'SymbolNode') {
    nextSibling = siblings[index + 1]
    nextNextSibling = siblings[index + 2]
    if (!nextSibling || !nextNextSibling) {
      return
    }

    if (
      (nextSibling.type === 'SymbolNode' || nextSibling.type === 'WordNode') &&
      nextNextSibling &&
      nextNextSibling.type === 'SymbolNode'
    ) {
      possibleEmoji = value + toString(nextSibling) + toString(nextNextSibling)

      if (own.call(unicodes, possibleEmoji)) {
        child.type = EMOTICON_NODE
        child.value = possibleEmoji

        if (child.position && nextNextSibling.position) {
          child.position.end = nextNextSibling.position.end
        }

        siblings.splice(index + 1, 2)

        return index + 1
      }
    }
    // :+1: — Gemoji shortcodes.
  } else if (value.charAt(0) === ':') {
    nodes = []
    siblingIndex = index
    subvalue = value
    left = null
    right = null
    leftMatch = null
    rightMatch = null

    if (subvalue.length === 1) {
      rightMatch = child
    } else {
      end = child.position && child.position.end
      start = end && child.position.start
      pos = end && {
        line: start.line,
        column: start.column + 1,
        offset: start.offset + 1
      }

      rightMatch = {
        type: 'PunctuationNode',
        value: ':'
      }

      right = {
        type: 'PunctuationNode',
        value: subvalue.slice(1)
      }

      if (end) {
        rightMatch.position = {start: start, end: pos}
        right.position = {start: pos, end: end}
      }
    }

    while (siblingIndex--) {
      if (index - siblingIndex > MAX_GEMOJI_PART_COUNT) {
        return
      }

      node = siblings[siblingIndex]

      subvalue = toString(node)

      if (subvalue.charAt(subvalue.length - 1) === ':') {
        leftMatch = node
        break
      }

      if (node.children) {
        nodes = nodes.concat(node.children.concat().reverse())
      } else {
        nodes.push(node)
      }

      if (siblingIndex === 0) {
        return
      }
    }

    if (!leftMatch) {
      return
    }

    subvalue = toString(leftMatch)

    if (subvalue.length !== 1) {
      end = leftMatch.position && leftMatch.position.end
      start = end && leftMatch.position.start
      pos = end && {
        line: end.line,
        column: end.column - 1,
        offset: end.offset - 1
      }

      left = {
        type: 'PunctuationNode',
        value: subvalue.slice(0, -1)
      }

      leftMatch = {
        type: 'PunctuationNode',
        value: ':'
      }

      if (end) {
        left.position = {start: start, end: pos}
        leftMatch.position = {start: pos, end: end}
      }
    }

    nodes.push(leftMatch)
    nodes.reverse().push(rightMatch)

    value = toString(nodes)

    if (shortcodes.indexOf(value) === -1) {
      return
    }

    replace = [siblingIndex, index - siblingIndex + 1]

    if (left) {
      replace.push(left)
    }

    child.type = EMOTICON_NODE
    child.value = value

    if (child.position && leftMatch.position) {
      child.position.start = leftMatch.position.start
    }

    if (child.position && rightMatch.position) {
      child.position.end = rightMatch.position.end
    }

    replace.push(child)

    if (right) {
      replace.push(right)
    }

    ;[].splice.apply(siblings, replace)

    return siblingIndex + 3
  }
}

function isVarianceSelector(node) {
  var code = toString(node).charCodeAt(0)
  return code > 65023 && code < 65040
}
<|endoftext|>


<commit_before>var coind = require('coind-client');
var async = require('async');
var cluster = require('cluster');
var Web3 = require('web3');
var config = require('./config.js');

var data = [];

function getTimeout(coinCode){
    try{
        return config.timeout[coinCode];
    }catch (e){
        return config.timeout['BTC'];
    }
}

function getIndex(clusterId){
    return (clusterId < 0) ? 0 : clusterId - 1;
}

function getDaemon(index){
    try{
        return config.daemonList[index];
    }catch (e){
        return null;
    }
}

var childProcess = function(){
    var index = getIndex(cluster.worker.id);
    console.log(getDaemon(index));

    setTimeout(childProcess, config.recheckTime);
}

if (cluster.isMaster) {

    // Fork workers.
    for (var i = 0; i < config.daemonList.length; i++) {
        cluster.fork();
    }

    cluster.on('exit', (worker, code, signal) => {
        console.log(`worker ${worker.process.pid} died`);
    });

} else {
    childProcess();
}

/*
async.eachSeries(geths, function (element, callback) {
    var web3 = new Web3(new Web3.providers.HttpProvider(element));
    web3.eth.getBlockNumber((e, r) => { console.log(element, e, r); });
    callback();
}, function () {
    async.eachSeries(config, function (element, callback) {
        var myClient = new coind.Client(element);
        myClient.cmd('getblockcount', function (e, r) {
            console.log("Server:", element.host, "Port:", element.port, "User:", element.user, "--------------");
            if (!e) {
                console.log("Block number", r);
            } else {
                console.log("Error", e);
            }
            callback();
        });
    });
});

var myClient = new coind.Client(config[0]);

myClient.cmd('getrawtransaction', 'f661368054502b90d1187548dbd6853a32aa6d3ac27d57e2d48fa8fd469d23f9',1 , (e, r) => {
    console.log(0);
    console.log(r);
});

var myClient = new coind.Client(config[3]);

myClient.cmd('getrawtransaction', 'f661368054502b90d1187548dbd6853a32aa6d3ac27d57e2d48fa8fd469d23f9',1 , (e, r) => {
    console.log(3);
    console.log(r);
});

var myClient = new coind.Client(config[6]);

myClient.cmd('getrawtransaction', 'b52ff514410ec005a077f68dbf52883a3de1951320176d5f0fa8fa15a2575785',1 , (e, r) => {
    console.log(r);
    if (!e) {
        console.log(r.tx);
        for(var i = 0; i < r.tx.length; i ++){
            console.log(r.tx[i]);
        }
        var txs = r.tx;
        async.eachSeries(txs, function (tx, callback) {

            myClient.cmd('getrawtransaction', tx, 1, (e, r) => {
                if (!e) {
                    console.log(r);
                }else{
                    console.log(e);
                }
                callback();
            });
        });
    }
});*/<commit_msg>Add monitoring code<commit_after>var coind = require('coind-client');
var async = require('async');
var cluster = require('cluster');
var Web3 = require('web3');
var config = require('./config.js');

var data = [];

function getTimeout(coinCode){
    try{
        return config.timeout[coinCode];
    }catch (e){
        return config.timeout['BTC'];
    }
}

function getIndex(clusterId){
    return (clusterId < 0) ? 0 : clusterId - 1;
}

function getDaemon(index){
    try{
        return config.daemonList[index];
    }catch (e){
        return null;
    }
}

var childProcess = function(){
    var index = getIndex(cluster.worker.id);
    var daemonInfo = getDaemon(index);
    if(daemonInfo.code == 'ETH'){
        var web3 = new Web3(new Web3.providers.HttpProvider(daemonInfo.host));
        web3.eth.getBlockNumber((e, r) => {
            if(e){
                console.log(e, daemonInfo);
            }else{
                if(data[index].lastBlock < r){
                    data[index].lastBlock = r;
                    data[index].timeOut = 0;
                }else{
                    data[index].timeOut += config.recheckTime;
                    if(data[index].timeout > config.timeout[daemonInfo.code]){
                        console.log('No block found', daemonInfo);
                    }
                }
            }
        });
    }else{
        var myClient = new coind.Client(daemonInfo);
        myClient.cmd('getblockcount', (e, r) => {
            if(e){
                console.log(e, daemonInfo);
            }else{
                if(data[index].lastBlock < r){
                    data[index].lastBlock = r;
                    data[index].timeOut = 0;
                }else{
                    data[index].timeOut += config.recheckTime;
                    if(data[index].timeout > config.timeout[daemonInfo.code]){
                        console.log('No block found', daemonInfo);
                    }
                }
            }
        });
    }
    setTimeout(childProcess, config.recheckTime);
}

if (cluster.isMaster) {

    // Fork workers.
    for (var i = 0; i < config.daemonList.length; i++) {
        cluster.fork();
    }

    cluster.on('exit', (worker, code, signal) => {
        console.log(`worker ${worker.process.pid} died`);
    });

} else {
    var index = getIndex(cluster.worker.id);
    data[index] =
    childProcess();
}

/*
async.eachSeries(geths, function (element, callback) {
    var web3 = new Web3(new Web3.providers.HttpProvider(element));
    web3.eth.getBlockNumber((e, r) => { console.log(element, e, r); });
    callback();
}, function () {
    async.eachSeries(config, function (element, callback) {
        var myClient = new coind.Client(element);
        myClient.cmd('getblockcount', function (e, r) {
            console.log("Server:", element.host, "Port:", element.port, "User:", element.user, "--------------");
            if (!e) {
                console.log("Block number", r);
            } else {
                console.log("Error", e);
            }
            callback();
        });
    });
});

var myClient = new coind.Client(config[0]);

myClient.cmd('getrawtransaction', 'f661368054502b90d1187548dbd6853a32aa6d3ac27d57e2d48fa8fd469d23f9',1 , (e, r) => {
    console.log(0);
    console.log(r);
});

var myClient = new coind.Client(config[3]);

myClient.cmd('getrawtransaction', 'f661368054502b90d1187548dbd6853a32aa6d3ac27d57e2d48fa8fd469d23f9',1 , (e, r) => {
    console.log(3);
    console.log(r);
});

var myClient = new coind.Client(config[6]);

myClient.cmd('getrawtransaction', 'b52ff514410ec005a077f68dbf52883a3de1951320176d5f0fa8fa15a2575785',1 , (e, r) => {
    console.log(r);
    if (!e) {
        console.log(r.tx);
        for(var i = 0; i < r.tx.length; i ++){
            console.log(r.tx[i]);
        }
        var txs = r.tx;
        async.eachSeries(txs, function (tx, callback) {

            myClient.cmd('getrawtransaction', tx, 1, (e, r) => {
                if (!e) {
                    console.log(r);
                }else{
                    console.log(e);
                }
                callback();
            });
        });
    }
});*/<|endoftext|>


<commit_before>// Copyright 2012 Mark Cavage <mcavage@gmail.com> All rights reserved.
//           2013 Bryce B. Baril <bryce@ravenwall.com> All rights reserved.

module.exports = Throttle

var assert = require("assert-plus")

var TokenBucket = require("./token_bucket")
var TokenTable = require("./token_table")

/**
 * Create a a token-based throttle instance.
 * @param {Object} options Options to create the throttle with.
 *              - {Number} rate The actions per time window to replenish. REQUIRED
 *              - {Number} burst The number allowed to burst to in a time window. Default = rate
 *              - {Number} window The time window in milliseconds to measure actions in. Default = 1000
 *              - {TokensTable} tokensTable A replacement token table to use. Must provide get/set.
 *              - {Object} overrides A set of overrides for certain tokens.
 *                                   Can specify alternate rate, burst, or window.
 *                                   Does not inherit, so defaults apply.
 */
function Throttle(options) {
  if (!(this instanceof Throttle)) return new Throttle(options)
  assert.object(options, "options")
  assert.number(options.rate, "options.rate")

  this.burst = options.burst || options.rate
  this.rate = options.rate
  this.window = options.window || 1000
  var table = options.tokensTable || TokenTable({size: options.maxKeys})
  this.table = table
  this.overrides = options.overrides

  this.getter = table.get
  this.putter = table.put
  if (table.put.length == 2 && table.get.length == 1) {
    // This looks like a synchronous table, wrap the methods to make them async.
    this.getter = function (key, cb) {
      process.nextTick(function () {
        cb(null, table.get(key))
      })
    }
    this.putter = function (key, bucket, cb) {
      process.nextTick(function () {
        cb(null, table.put(key, bucket))
      })
    }
  }
  else if (table.put.length != 3 && table.get.length != 2) {
    throw new Error("Unable to detect TokenTable implementation type (sync/async) check API.")
  }
}

/**
 * Test a key for throttle status.
 * @param  {String}   key Throttle key to check.
 * @param  {Function} cb  Callback f(err, limited)
 */
Throttle.prototype.rateLimit = function (key, cb) {
  if (key === undefined || key === null) return cb()
  var self = this

  var burst = self.burst
  var rate = self.rate
  var window = self.window

  // Check the overrides
  if (self.overrides &&
    self.overrides[key] &&
    (self.overrides[key].burst !== undefined ||
    self.overrides[key].rate !== undefined ||
    self.overrides[key].window !== undefined)) {

    burst = self.overrides[key].burst
    rate = self.overrides[key].rate
    window = self.overrides[key].window
  }

  if (!rate || !burst) return cb()

  self.getter.call(self.table, key, function (err, bucket) {
    if (err) {
      return cb(new Error("Unable to check token table" + err))
    }
    if (bucket) {
      // Recreate the token bucket
      bucket = TokenBucket(bucket)
    }
    else {
      // Make a new one
      bucket = TokenBucket({
        capacity: burst,
        fillRate: rate,
        window: window,
      })
    }

    var hasCapacity = bucket.consume(1)

    //console.log("Throttle(%s): num_tokens= %d -- throttled: %s", key, bucket.tokens, !hasCapacity)

    self.putter.call(self.table, key, bucket, function (err) {
      // Error here is not fatal -- we were able to determine throttle status, just not save state.
      if (err) {
        err = new Error("Error saving throttle information to table" + err)
      }
      if (!hasCapacity) {
        return cb(err, true)
      }
      return cb(err, false)
    })
  })
}
<commit_msg>Renamed the 'window' variable to 'and'.<commit_after>// Copyright 2012 Mark Cavage <mcavage@gmail.com> All rights reserved.
//           2013 Bryce B. Baril <bryce@ravenwall.com> All rights reserved.

module.exports = Throttle

var assert = require("assert-plus")

var TokenBucket = require("./token_bucket")
var TokenTable = require("./token_table")

/**
 * Create a a token-based throttle instance.
 * @param {Object} options Options to create the throttle with.
 *              - {Number} rate The actions per time window to replenish. REQUIRED
 *              - {Number} burst The number allowed to burst to in a time window. Default = rate
 *              - {Number} window The time window in milliseconds to measure actions in. Default = 1000
 *              - {TokensTable} tokensTable A replacement token table to use. Must provide get/set.
 *              - {Object} overrides A set of overrides for certain tokens.
 *                                   Can specify alternate rate, burst, or window.
 *                                   Does not inherit, so defaults apply.
 */
function Throttle(options) {
  if (!(this instanceof Throttle)) return new Throttle(options)
  assert.object(options, "options")
  assert.number(options.rate, "options.rate")

  this.burst = options.burst || options.rate
  this.rate = options.rate
  this.window = options.window || 1000
  var table = options.tokensTable || TokenTable({size: options.maxKeys})
  this.table = table
  this.overrides = options.overrides

  this.getter = table.get
  this.putter = table.put
  if (table.put.length == 2 && table.get.length == 1) {
    // This looks like a synchronous table, wrap the methods to make them async.
    this.getter = function (key, cb) {
      process.nextTick(function () {
        cb(null, table.get(key))
      })
    }
    this.putter = function (key, bucket, cb) {
      process.nextTick(function () {
        cb(null, table.put(key, bucket))
      })
    }
  }
  else if (table.put.length != 3 && table.get.length != 2) {
    throw new Error("Unable to detect TokenTable implementation type (sync/async) check API.")
  }
}

/**
 * Test a key for throttle status.
 * @param  {String}   key Throttle key to check.
 * @param  {Function} cb  Callback f(err, limited)
 */
Throttle.prototype.rateLimit = function (key, cb) {
  if (key === undefined || key === null) return cb()
  var self = this

  var burst = self.burst
  var rate = self.rate
  var wnd = self.window

  // Check the overrides
  if (self.overrides &&
    self.overrides[key] &&
    (self.overrides[key].burst !== undefined ||
    self.overrides[key].rate !== undefined ||
    self.overrides[key].window !== undefined)) {

    burst = self.overrides[key].burst
    rate = self.overrides[key].rate
    wnd = self.overrides[key].window
  }

  if (!rate || !burst) return cb()

  self.getter.call(self.table, key, function (err, bucket) {
    if (err) {
      return cb(new Error("Unable to check token table" + err))
    }
    if (bucket) {
      // Recreate the token bucket
      bucket = TokenBucket(bucket)
    }
    else {
      // Make a new one
      bucket = TokenBucket({
        capacity: burst,
        fillRate: rate,
        window: wnd,
      })
    }

    var hasCapacity = bucket.consume(1)

    //console.log("Throttle(%s): num_tokens= %d -- throttled: %s", key, bucket.tokens, !hasCapacity)

    self.putter.call(self.table, key, bucket, function (err) {
      // Error here is not fatal -- we were able to determine throttle status, just not save state.
      if (err) {
        err = new Error("Error saving throttle information to table" + err)
      }
      if (!hasCapacity) {
        return cb(err, true)
      }
      return cb(err, false)
    })
  })
}
<|endoftext|>


<commit_before>var fs = require('fs')
var p = require('path')
var minimatch = require('minimatch')

// how to know when you are done?
function readdir(path, ignores, callback) {
  if (typeof ignores == 'function') {
    callback = ignores
    ignores  = []
  }
  var list = []

  fs.readdir(path, function (err, files) {
    if (err) {
      return callback(err)
    }

    var pending = files.length
    if (!pending) {
      // we are done, woop woop
      return callback(null, list)
    }

    var ignoreOpts = {matchBase: true}
    files.forEach(function (file) {
      for (var i = 0; i < ignores.length; i++) {
        if (minimatch(p.join(path, file), ignores[i], ignoreOpts)) {
          pending -= 1
          if (pending <= 0) {
            callback(null, list)
          }
          return
        }
      }

      fs.lstat(p.join(path, file), function (err, stats) {
        if (err) {
          return callback(err)
        }

        if (stats.isDirectory()) {
          files = readdir(p.join(path, file), ignores, function (err, res) {
            list = list.concat(res)
            pending -= 1
            if (!pending) {
              callback(null, list)
            }
          })
        }
        else {
          list.push(p.join(path, file))
          pending -= 1
          if (!pending) {
            callback(null, list)
          }
        }
      })
    })
  })
}

module.exports = readdir
<commit_msg>Allow errors to pass up through the recursive calls.<commit_after>var fs = require('fs')
var p = require('path')
var minimatch = require('minimatch')

// how to know when you are done?
function readdir(path, ignores, callback) {
  if (typeof ignores == 'function') {
    callback = ignores
    ignores  = []
  }
  var list = []

  fs.readdir(path, function (err, files) {
    if (err) {
      return callback(err)
    }

    var pending = files.length
    if (!pending) {
      // we are done, woop woop
      return callback(null, list)
    }

    var ignoreOpts = {matchBase: true}
    files.forEach(function (file) {
      for (var i = 0; i < ignores.length; i++) {
        if (minimatch(p.join(path, file), ignores[i], ignoreOpts)) {
          pending -= 1
          if (pending <= 0) {
            callback(null, list)
          }
          return
        }
      }

      fs.lstat(p.join(path, file), function (err, stats) {
        if (err) {
          return callback(err)
        }

        if (stats.isDirectory()) {
          files = readdir(p.join(path, file), ignores, function (err, res) {
            if (err) {
              return callback(err)
            }

            list = list.concat(res)
            pending -= 1
            if (!pending) {
              callback(null, list)
            }
          })
        }
        else {
          list.push(p.join(path, file))
          pending -= 1
          if (!pending) {
            callback(null, list)
          }
        }
      })
    })
  })
}

module.exports = readdir
<|endoftext|>


<commit_before>var hash = require('./murmerhash');
var Promise = null;
var isCordova = typeof cordova !== 'undefined';

/* Cordova File Cache x */
function FileCache(options){
  var self = this;
  // cordova-promise-fs
  this._fs = options.fs;
  if(!this._fs) {
    throw new Error('Missing required option "fs". Add an instance of cordova-promise-fs.');
  }
  // Use Promises from fs.
  Promise = this._fs.Promise;

  // 'mirror' mirrors files structure from "serverRoot" to "localRoot"
  // 'hash' creates a 1-deep filestructure, where the filenames are hashed server urls (with extension)
  this._mirrorMode = options.mode !== 'hash';
  this._retry = options.retry || [500,1500,8000];
  this._cacheBuster = !!options.cacheBuster;

  // normalize path
  this.localRoot = this._fs.normalize(options.localRoot || 'data');
  this.serverRoot = this._fs.normalize(options.serverRoot || '');

  // set internal variables
  this._downloading = [];    // download promises
  this._added = [];          // added files
  this._cached = {};         // cached files

  // list existing cache contents
  this.ready = this._fs.ensure(this.localRoot)
  .then(function(entry){
    self.localInternalURL = isCordova? entry.toInternalURL(): entry.toURL();
    self.localUrl = entry.toURL();
    return self.list();
  });
}

FileCache.hash = hash;

/**
 * Helper to cache all 'internalURL' and 'URL' for quick synchronous access
 * to the cached files.
 */
FileCache.prototype.list = function list(){
  var self = this;
  return new Promise(function(resolve,reject){
    self._fs.list(self.localRoot,'rfe').then(function(entries){
      self._cached = {};
      entries = entries.map(function(entry){
        var fullPath = self._fs.normalize(entry.fullPath);
        self._cached[fullPath] = {
          toInternalURL: isCordova? entry.toInternalURL(): entry.toURL(),
          toURL: entry.toURL(),
        };
        return fullPath;
      });
      resolve(entries);
    },function(){
      resolve([]);
    });
  });
};

FileCache.prototype.add = function add(urls){
  if(!urls) urls = [];
  if(typeof urls === 'string') urls = [urls];
  var self = this;
  urls.forEach(function(url){
    url = self.toServerURL(url);
    if(self._added.indexOf(url) === -1) {
      self._added.push(url);
    }
  });
  return self.isDirty();
};

FileCache.prototype.remove = function remove(urls,returnPromises){
  if(!urls) urls = [];
  var promises = [];
  if(typeof urls === 'string') urls = [urls];
  var self = this;
  urls.forEach(function(url){
    var index = self._added.indexOf(self.toServerURL(url));
    if(index >= 0) self._added.splice(index,1);
    var path = self.toPath(url);
    promises.push(self._fs.remove(path));
    delete self._cached[path];
  });
  return returnPromises? Promise.all(promises): self.isDirty();
};

FileCache.prototype.getDownloadQueue = function(){
  var self = this;
  var queue = self._added.filter(function(url){
    return !self.isCached(url);
  });
  return queue;
};

FileCache.prototype.getAdded = function() {
  return this._added;
};

FileCache.prototype.isDirty = function isDirty(){
  return this.getDownloadQueue().length > 0;
};

FileCache.prototype.download = function download(onprogress){
  var fs = this._fs;
  var self = this;
  self.abort();

  return new Promise(function(resolve,reject){
    // make sure cache directory exists and that
    // we have retrieved the latest cache contents
    // to avoid downloading files we already have!
    fs.ensure(self.localRoot).then(function(){
      return self.list();
    }).then(function(){
      // no dowloads needed, resolve
      if(!self.isDirty()) {
        resolve(self);
        return;
      }

      // keep track of number of downloads!
      var queue = self.getDownloadQueue();
      var done = self._downloading.length;
      var total = self._downloading.length + queue.length;

      // download every file in the queue (which is the diff from _added with _cached)
      queue.forEach(function(url){
        var path = self.toPath(url);
        // augment progress event with done/total stats
        var onSingleDownloadProgress;
        if(typeof onprogress === 'function') {
          onSingleDownloadProgress = function(ev){
            ev.queueIndex = done;
            ev.queueSize = total;
            ev.url = url;
            ev.path = path;
            ev.percentage = done / total;
            if(ev.loaded > 0 && ev.total > 0 && index !== total){
               ev.percentage += (ev.loaded / ev.total) / total;
            }
            onprogress(ev);
          };
        }

        // callback
        var onDone = function(){
          done++;

          // when we're done
          if(done === total) {
            // reset downloads
            self._downloading = [];
            // check if we got everything
            self.list().then(function(){
              // final progress event!
              if(onSingleDownloadProgress) onSingleDownloadProgress(new ProgressEvent());
              // Yes, we're not dirty anymore!
              if(!self.isDirty()) {
                resolve(self);
              // Aye, some files got left behind!
              } else {
                reject(self.getDownloadQueue());
              }
            },reject);
          }
        };
        var downloadUrl = url;
        if(self._cacheBuster) downloadUrl += "?"+Date.now();
        var download = fs.download(downloadUrl,path,{retry:self._retry},onSingleDownloadProgress);
        download.then(onDone,onDone);
        self._downloading.push(download);
      });
    },reject);
  });
};

FileCache.prototype.abort = function abort(){
  this._downloading.forEach(function(download){
    download.abort();
  });
  this._downloading = [];
};

FileCache.prototype.isCached = function isCached(url){
  url = this.toPath(url);
  return !!this._cached[url];
};

FileCache.prototype.clear = function clear(){
  var self = this;
  this._cached = {};
  return this._fs.removeDir(this.localRoot).then(function(){
    return self._fs.ensure(self.localRoot);
  });
};

/**
 * Helpers to output to various formats
 */
FileCache.prototype.toInternalURL = function toInternalURL(url){
  path = this.toPath(url);
  if(this._cached[path]) return this._cached[path].toInternalURL;
  return url;
};

FileCache.prototype.get = function get(url){
  path = this.toPath(url);
  if(this._cached[path]) return this._cached[path].toInternalURL;
  return this.toServerURL(url);
};

FileCache.prototype.toDataURL = function toDataURL(url){
  return this._fs.toDataURL(this.toPath(url));
};

FileCache.prototype.toURL = function toURL(url){
  path = this.toPath(url);
  return this._cached[path]? this._cached[path].toURL: url;
};

FileCache.prototype.toServerURL = function toServerURL(path){
  path = this._fs.normalize(path);
  return path.indexOf('://') < 0? this.serverRoot + path: path;
};

/**
 * Helper to transform remote URL to a local path (for cordova-promise-fs)
 */
FileCache.prototype.toPath = function toPath(url){
  if(this._mirrorMode) {
    var query = url.indexOf('?');
    if(query > -1){
      url = url.substr(0,query);
    }
    url = url = this._fs.normalize(url || '');
    len = this.serverRoot.length;
    if(url.substr(0,len) !== this.serverRoot) {
      return this.localRoot + url;
    } else {
      return this.localRoot + url.substr(len);
    }
  } else {
    return this.localRoot + hash(url) + url.substr(url.lastIndexOf('.'));
  }
};

module.exports = FileCache;<commit_msg>bugfix download progress<commit_after>var hash = require('./murmerhash');
var Promise = null;
var isCordova = typeof cordova !== 'undefined';

/* Cordova File Cache x */
function FileCache(options){
  var self = this;
  // cordova-promise-fs
  this._fs = options.fs;
  if(!this._fs) {
    throw new Error('Missing required option "fs". Add an instance of cordova-promise-fs.');
  }
  // Use Promises from fs.
  Promise = this._fs.Promise;

  // 'mirror' mirrors files structure from "serverRoot" to "localRoot"
  // 'hash' creates a 1-deep filestructure, where the filenames are hashed server urls (with extension)
  this._mirrorMode = options.mode !== 'hash';
  this._retry = options.retry || [500,1500,8000];
  this._cacheBuster = !!options.cacheBuster;

  // normalize path
  this.localRoot = this._fs.normalize(options.localRoot || 'data');
  this.serverRoot = this._fs.normalize(options.serverRoot || '');

  // set internal variables
  this._downloading = [];    // download promises
  this._added = [];          // added files
  this._cached = {};         // cached files

  // list existing cache contents
  this.ready = this._fs.ensure(this.localRoot)
  .then(function(entry){
    self.localInternalURL = isCordova? entry.toInternalURL(): entry.toURL();
    self.localUrl = entry.toURL();
    return self.list();
  });
}

FileCache.hash = hash;

/**
 * Helper to cache all 'internalURL' and 'URL' for quick synchronous access
 * to the cached files.
 */
FileCache.prototype.list = function list(){
  var self = this;
  return new Promise(function(resolve,reject){
    self._fs.list(self.localRoot,'rfe').then(function(entries){
      self._cached = {};
      entries = entries.map(function(entry){
        var fullPath = self._fs.normalize(entry.fullPath);
        self._cached[fullPath] = {
          toInternalURL: isCordova? entry.toInternalURL(): entry.toURL(),
          toURL: entry.toURL(),
        };
        return fullPath;
      });
      resolve(entries);
    },function(){
      resolve([]);
    });
  });
};

FileCache.prototype.add = function add(urls){
  if(!urls) urls = [];
  if(typeof urls === 'string') urls = [urls];
  var self = this;
  urls.forEach(function(url){
    url = self.toServerURL(url);
    if(self._added.indexOf(url) === -1) {
      self._added.push(url);
    }
  });
  return self.isDirty();
};

FileCache.prototype.remove = function remove(urls,returnPromises){
  if(!urls) urls = [];
  var promises = [];
  if(typeof urls === 'string') urls = [urls];
  var self = this;
  urls.forEach(function(url){
    var index = self._added.indexOf(self.toServerURL(url));
    if(index >= 0) self._added.splice(index,1);
    var path = self.toPath(url);
    promises.push(self._fs.remove(path));
    delete self._cached[path];
  });
  return returnPromises? Promise.all(promises): self.isDirty();
};

FileCache.prototype.getDownloadQueue = function(){
  var self = this;
  var queue = self._added.filter(function(url){
    return !self.isCached(url);
  });
  return queue;
};

FileCache.prototype.getAdded = function() {
  return this._added;
};

FileCache.prototype.isDirty = function isDirty(){
  return this.getDownloadQueue().length > 0;
};

FileCache.prototype.download = function download(onprogress){
  var fs = this._fs;
  var self = this;
  self.abort();

  return new Promise(function(resolve,reject){
    // make sure cache directory exists and that
    // we have retrieved the latest cache contents
    // to avoid downloading files we already have!
    fs.ensure(self.localRoot).then(function(){
      return self.list();
    }).then(function(){
      // no dowloads needed, resolve
      if(!self.isDirty()) {
        resolve(self);
        return;
      }

      // keep track of number of downloads!
      var queue = self.getDownloadQueue();
      var done = self._downloading.length;
      var total = self._downloading.length + queue.length;

      // download every file in the queue (which is the diff from _added with _cached)
      queue.forEach(function(url){
        var path = self.toPath(url);
        // augment progress event with done/total stats
        var onSingleDownloadProgress;
        if(typeof onprogress === 'function') {
          onSingleDownloadProgress = function(ev){
            ev.queueIndex = done;
            ev.queueSize = total;
            ev.url = url;
            ev.path = path;
            ev.percentage = done / total;
            if(ev.loaded > 0 && ev.total > 0 && done !== total){
               ev.percentage += (ev.loaded / ev.total) / total;
            }
            onprogress(ev);
          };
        }

        // callback
        var onDone = function(){
          done++;

          // when we're done
          if(done === total) {
            // reset downloads
            self._downloading = [];
            // check if we got everything
            self.list().then(function(){
              // final progress event!
              if(onSingleDownloadProgress) onSingleDownloadProgress(new ProgressEvent());
              // Yes, we're not dirty anymore!
              if(!self.isDirty()) {
                resolve(self);
              // Aye, some files got left behind!
              } else {
                reject(self.getDownloadQueue());
              }
            },reject);
          }
        };
        var downloadUrl = url;
        if(self._cacheBuster) downloadUrl += "?"+Date.now();
        var download = fs.download(downloadUrl,path,{retry:self._retry},onSingleDownloadProgress);
        download.then(onDone,onDone);
        self._downloading.push(download);
      });
    },reject);
  });
};

FileCache.prototype.abort = function abort(){
  this._downloading.forEach(function(download){
    download.abort();
  });
  this._downloading = [];
};

FileCache.prototype.isCached = function isCached(url){
  url = this.toPath(url);
  return !!this._cached[url];
};

FileCache.prototype.clear = function clear(){
  var self = this;
  this._cached = {};
  return this._fs.removeDir(this.localRoot).then(function(){
    return self._fs.ensure(self.localRoot);
  });
};

/**
 * Helpers to output to various formats
 */
FileCache.prototype.toInternalURL = function toInternalURL(url){
  path = this.toPath(url);
  if(this._cached[path]) return this._cached[path].toInternalURL;
  return url;
};

FileCache.prototype.get = function get(url){
  path = this.toPath(url);
  if(this._cached[path]) return this._cached[path].toInternalURL;
  return this.toServerURL(url);
};

FileCache.prototype.toDataURL = function toDataURL(url){
  return this._fs.toDataURL(this.toPath(url));
};

FileCache.prototype.toURL = function toURL(url){
  path = this.toPath(url);
  return this._cached[path]? this._cached[path].toURL: url;
};

FileCache.prototype.toServerURL = function toServerURL(path){
  path = this._fs.normalize(path);
  return path.indexOf('://') < 0? this.serverRoot + path: path;
};

/**
 * Helper to transform remote URL to a local path (for cordova-promise-fs)
 */
FileCache.prototype.toPath = function toPath(url){
  if(this._mirrorMode) {
    var query = url.indexOf('?');
    if(query > -1){
      url = url.substr(0,query);
    }
    url = url = this._fs.normalize(url || '');
    len = this.serverRoot.length;
    if(url.substr(0,len) !== this.serverRoot) {
      return this.localRoot + url;
    } else {
      return this.localRoot + url.substr(len);
    }
  } else {
    return this.localRoot + hash(url) + url.substr(url.lastIndexOf('.'));
  }
};

module.exports = FileCache;<|endoftext|>


<commit_before>/**
 * Activates typeahead behavior for given element.
 * @param element (required) The DOM element to infect.
 * @param source (optional) The custom data source.
 */
Meteor.typeahead = function(element, source) {
	var $e = $(element);
	var datasets = resolve_datasets($e, source);

	$e.typeahead('destroy');

	var opts = $e.data('options') || {};
	if (typeof opts != 'object') {
		opts = {};
	}

	// other known options passed via data attributes
	var highlight = Boolean($e.data('highlight')) || false;
	var hint = Boolean($e.data('hint')) || false;
	var minLength = parseInt($e.data('min-length')) || 1;
	var autocompleted = null, selected = null;

	if ($e.data('autocompleted')) {
		autocompleted = resolve_template_function($e[0], $e.data('autocompleted'));
	}
	if ($e.data('selected')) {
		selected = resolve_template_function($e[0], $e.data('selected'));
	}

	var options = $.extend(opts, {
		highlight: highlight,
		hint: hint,
		minLength: minLength
	});

	var instance;
	if (Array.isArray(datasets)) {
		instance = $e.typeahead.apply($e, [options].concat(datasets));
	} else {
		instance = $e.typeahead(options, datasets);
	}

	// event handlers (PR #18)
	if (typeof selected == 'function') {
		instance.on('typeahead:selected', selected);
	}
	if (typeof autocompleted == 'function') {
		instance.on('typeahead:autocompleted', autocompleted);
	}

	// fix to apply bootstrap form-control to tt-hint
	// TODO support other classes if needed
	if ($e.hasClass('form-control')) {
		$e.parent('.twitter-typeahead').find('.tt-hint').addClass('form-control');
	}
};

/**
 * Activates all typeahead elements.
 * @param selector (optional) selector to find typeahead elements to be activated
 */
Meteor.typeahead.inject = function(selector) {
	if (!selector) {
		selector = '.typeahead';
	}
	$(selector).each(function(i,e) {
		try {
			Meteor.typeahead(e);
		} catch (err) {
			console.log(err);
		}
	});
};

function resolve_datasets($e, source) {
	var element = $e[0];
	var datasets = $e.data('sets');
	if (datasets) {
		if (typeof datasets == 'string') {
			datasets = resolve_template_function(element, datasets);
		}
		if (typeof datasets == 'function') {
			datasets = datasets() || [];
		}
		return datasets.map(function(ds) {
			return make_bloodhound(ds);
		});
	}

	var name = $e.attr('name') || $e.attr('id') || 'dataset';
	var limit = $e.data('limit');
	var templateName = $e.data('template'); // specifies name of custom template
	var valueKey = $e.data('value-key');

	if (!source) {
		source = $e.data('source') || [];
	}

	if (typeof source === 'string') {
		source = resolve_template_function(element, source);
	}

	var dataset = {
		name: name,
		valueKey: valueKey,
		displayKey: valueKey
	};

	if (limit) {
		dataset.limit = limit;
	}

	// support for custom templates
	if (templateName) {
		dataset.template = templateName;
	}

	if (Array.isArray(source) || (typeof source == 'function' && source.length === 0)) {
		dataset.local = source;
		return make_bloodhound(dataset);
	}

	dataset.source = source;
	dataset.templates = make_templates(dataset);

	return dataset;
}

function resolve_template_function(element, name) {
	var view = Blaze.getElementView(element);
	if (!view) {
		return [];
	}
	var fn = view.template && view.template[name];
	if (typeof fn != 'function') {
		console.log("Unable to resolve data source function '%s'.", name);
		return [];
	}
	return fn;
}

function make_template_function(templateName) {
	if (!templateName) {
		throw new Error("templateName is not specified");
	}

	var tmpl = Template[templateName];
	if (!tmpl) {
		throw new Error("Template '" + templateName  + "' is not defined");
	}

	return function(context) {
		var div = $("<div/>");
		var range = UI.renderWithData(tmpl, context);
		UI.insert(range, div[0]);
		return div.html();
	};
}

function make_templates(dataset) {
	var templates = {};
	if (dataset.header) {
		templates.header = dataset.header;
	}
	if (dataset.template) {
		var templateFn = typeof dataset.template == 'string' ?
			make_template_function(dataset.template)
			: dataset.template;
		if (typeof templateFn == 'function') {
			templates.suggestion = templateFn;
		}
	}
	return templates;
}

// creates Bloodhound suggestion engine based on given dataset
function make_bloodhound(dataset) {

	function wrap_value(value) {
          if (typeof value == 'object') {
                return value;
          } else {
		return {value: value};
          }
	}

	if (!dataset.template) {
		if (Array.isArray(dataset.local)) {
			dataset.local = dataset.local.map(wrap_value);
		} else if (typeof dataset.local == 'function' && dataset.local.length === 0) {
			var localFn = dataset.local;
			dataset.local = function() {
				return (localFn() || []).map(wrap_value);
			};
		}
	}

	var need_bloodhound = Array.isArray(dataset.local) ||
		typeof dataset.local == 'function' && dataset.local.length === 0;

	var engine;
	var valueKey = dataset.valueKey || 'value';

	if (need_bloodhound) {
		var options = $.extend({}, dataset, {
			// TODO support custom tokenizers
			datumTokenizer: Bloodhound.tokenizers.obj.whitespace(valueKey),
			queryTokenizer: Bloodhound.tokenizers.whitespace
		});

		engine = new Bloodhound(options);
		engine.initialize();

		if (typeof dataset.local == 'function' && dataset.local.length === 0) {
			// update data source on changing deps of local function
			// TODO find better (functional) way to do that
			Deps.autorun(function() {
				engine = new Bloodhound(options);
				engine.initialize();
			});
		}
	}

	function bloodhound_source(query, cb) {
		var fn = engine.ttAdapter();
		return fn(query, cb);
	}

	return {
		displayKey: valueKey,
		source: need_bloodhound ? bloodhound_source : dataset.local,
		templates: make_templates(dataset)
	};
}
<commit_msg>fixed resolve_template_function for meteor 0.8.2 and earlier<commit_after>/**
 * Activates typeahead behavior for given element.
 * @param element (required) The DOM element to infect.
 * @param source (optional) The custom data source.
 */
Meteor.typeahead = function(element, source) {
	var $e = $(element);
	var datasets = resolve_datasets($e, source);

	$e.typeahead('destroy');

	var opts = $e.data('options') || {};
	if (typeof opts != 'object') {
		opts = {};
	}

	// other known options passed via data attributes
	var highlight = Boolean($e.data('highlight')) || false;
	var hint = Boolean($e.data('hint')) || false;
	var minLength = parseInt($e.data('min-length')) || 1;
	var autocompleted = null, selected = null;

	if ($e.data('autocompleted')) {
		autocompleted = resolve_template_function($e[0], $e.data('autocompleted'));
	}
	if ($e.data('selected')) {
		selected = resolve_template_function($e[0], $e.data('selected'));
	}

	var options = $.extend(opts, {
		highlight: highlight,
		hint: hint,
		minLength: minLength
	});

	var instance;
	if (Array.isArray(datasets)) {
		instance = $e.typeahead.apply($e, [options].concat(datasets));
	} else {
		instance = $e.typeahead(options, datasets);
	}

	// event handlers (PR #18)
	if (typeof selected == 'function') {
		instance.on('typeahead:selected', selected);
	}
	if (typeof autocompleted == 'function') {
		instance.on('typeahead:autocompleted', autocompleted);
	}

	// fix to apply bootstrap form-control to tt-hint
	// TODO support other classes if needed
	if ($e.hasClass('form-control')) {
		$e.parent('.twitter-typeahead').find('.tt-hint').addClass('form-control');
	}
};

/**
 * Activates all typeahead elements.
 * @param selector (optional) selector to find typeahead elements to be activated
 */
Meteor.typeahead.inject = function(selector) {
	if (!selector) {
		selector = '.typeahead';
	}
	$(selector).each(function(i,e) {
		try {
			Meteor.typeahead(e);
		} catch (err) {
			console.log(err);
		}
	});
};

function resolve_datasets($e, source) {
	var element = $e[0];
	var datasets = $e.data('sets');
	if (datasets) {
		if (typeof datasets == 'string') {
			datasets = resolve_template_function(element, datasets);
		}
		if (typeof datasets == 'function') {
			datasets = datasets() || [];
		}
		return datasets.map(function(ds) {
			return make_bloodhound(ds);
		});
	}

	var name = $e.attr('name') || $e.attr('id') || 'dataset';
	var limit = $e.data('limit');
	var templateName = $e.data('template'); // specifies name of custom template
	var valueKey = $e.data('value-key');

	if (!source) {
		source = $e.data('source') || [];
	}

	if (typeof source === 'string') {
		source = resolve_template_function(element, source);
	}

	var dataset = {
		name: name,
		valueKey: valueKey,
		displayKey: valueKey
	};

	if (limit) {
		dataset.limit = limit;
	}

	// support for custom templates
	if (templateName) {
		dataset.template = templateName;
	}

	if (Array.isArray(source) || (typeof source == 'function' && source.length === 0)) {
		dataset.local = source;
		return make_bloodhound(dataset);
	}

	dataset.source = source;
	dataset.templates = make_templates(dataset);

	return dataset;
}

function resolve_template_function(element, name) {
	var fn = null;

	if (typeof Blaze == "undefined") {
		var component = UI.DomRange.getContainingComponent(element);
		if (!component) {
			return [];
		}
		fn = component[name];
	} else {
		var view = Blaze.getElementView(element);
		if (!view) {
			return [];
		}
		fn = view.template && view.template[name];
	}

	if (typeof fn != 'function') {
		console.log("Unable to resolve data source function '%s'.", name);
		return [];
	}

	return fn;
}

function make_template_function(templateName) {
	if (!templateName) {
		throw new Error("templateName is not specified");
	}

	var tmpl = Template[templateName];
	if (!tmpl) {
		throw new Error("Template '" + templateName  + "' is not defined");
	}

	return function(context) {
		var div = $("<div/>");
		var range = UI.renderWithData(tmpl, context);
		UI.insert(range, div[0]);
		return div.html();
	};
}

function make_templates(dataset) {
	var templates = {};
	if (dataset.header) {
		templates.header = dataset.header;
	}
	if (dataset.template) {
		var templateFn = typeof dataset.template == 'string' ?
			make_template_function(dataset.template)
			: dataset.template;
		if (typeof templateFn == 'function') {
			templates.suggestion = templateFn;
		}
	}
	return templates;
}

// creates Bloodhound suggestion engine based on given dataset
function make_bloodhound(dataset) {

	function wrap_value(value) {
          if (typeof value == 'object') {
                return value;
          } else {
		return {value: value};
          }
	}

	if (!dataset.template) {
		if (Array.isArray(dataset.local)) {
			dataset.local = dataset.local.map(wrap_value);
		} else if (typeof dataset.local == 'function' && dataset.local.length === 0) {
			var localFn = dataset.local;
			dataset.local = function() {
				return (localFn() || []).map(wrap_value);
			};
		}
	}

	var need_bloodhound = Array.isArray(dataset.local) ||
		typeof dataset.local == 'function' && dataset.local.length === 0;

	var engine;
	var valueKey = dataset.valueKey || 'value';

	if (need_bloodhound) {
		var options = $.extend({}, dataset, {
			// TODO support custom tokenizers
			datumTokenizer: Bloodhound.tokenizers.obj.whitespace(valueKey),
			queryTokenizer: Bloodhound.tokenizers.whitespace
		});

		engine = new Bloodhound(options);
		engine.initialize();

		if (typeof dataset.local == 'function' && dataset.local.length === 0) {
			// update data source on changing deps of local function
			// TODO find better (functional) way to do that
			Deps.autorun(function() {
				engine = new Bloodhound(options);
				engine.initialize();
			});
		}
	}

	function bloodhound_source(query, cb) {
		var fn = engine.ttAdapter();
		return fn(query, cb);
	}

	return {
		displayKey: valueKey,
		source: need_bloodhound ? bloodhound_source : dataset.local,
		templates: make_templates(dataset)
	};
}
<|endoftext|>


<commit_before>var _ = require('lodash');
var async = require('async-chainable');
var colors = require('colors');
var fs = require('fs');
var reflib = require('reflib');

console.log('Beginning analysis');

async()
	.set('output', 'data/database-analysis.csv')
	.set('refs', [])
	.set('dbs', [
		{id: 'db-a', title: 'DB-A', file: 'data/db-a.xml'},
		/*{id: 'db-b', title: 'DB-B', file: 'data/db-b.xml'},
		{id: 'db-c', title: 'DB-C', file: 'data/db-c.xml'},
		{id: 'db-d', title: 'DB-D', file: 'data/db-d.xml'},
		{id: 'db-e', title: 'DB-E', file: 'data/db-e.xml'},
		{id: 'db-f', title: 'DB-F', file: 'data/db-f.xml'},
		{id: 'db-g', title: 'DB-G', file: 'data/db-g.xml'},*/
	])
	.forEach('dbs', function(next, db) {
		console.log(colors.grey('Processing database file'), colors.grey(db.file));
		var self = this;
		var refCount = 0;
		reflib.parseFile(db.file)
			.on('error', function(err) {
				next(err);
			})
			.on('ref', function(newRef) {
				refCount++;
				// Try to find an existing similar ref {{{
				if (!newRef.title) {
					console.log('Skipping blank title');
					return;
				}
				// Generate a searchable title to match by {{{
				var queryTitle = newRef.title
					.replace(/[^A-Z0-9]+/i, ' ');
				// }}}
				var found = _.find(self.refs.find, function(existingRef) {
					return existingRef.titleQuery == queryTitle;
				});
				// }}}

				if (found) { // Found existing - merge
					found.sources[db.id] = newRef.notes;
				} else { // No existing one located - create new
					newRef.sources = {};
					newRef.sources[db.id] = newRef.notes;
					newRef.titleQuery = queryTitle;
					self.refs.push(newRef);
				}
			})
			.on('end', function() {
				console.log('Extracted', colors.cyan(refCount), 'from', colors.cyan(db.file));
				next();
			});
	})
	.then(function(next) {
		var self = this;
		var csv = fs.createWriteStream(self.output)
			.on('error', next)
			.on('finish', next);

		// Write header {{{
		csv.write(['Paper Title'].concat(self.dbs.map(function(db) {
			return db.title;
		})).join(',') + "\n");
		// }}}
		self.refs.forEach(function(ref, index) {
			csv.write(['\"' + ref.title + '\"'].concat(self.dbs.map(function(db) {
				return ref.sources[db.id] || 'Missing';
			})).join(',') + "\n");
		});

		csv.end();
	})
	.end(function(err) {
		if (err) {
			console.log(colors.red('ERROR'), err);
			process.exit(1);
		}

		console.log();
		console.log(colors.green('Completed'));
		console.log(colors.cyan(this.refs.length), 'references processed from', colors.cyan(this.dbs.length), 'databases');
		console.log('Analysis file saved to', colors.cyan(this.output));
		process.exit(1);
	});
<commit_msg>Switched to using buffer output instead of the buggy stream system<commit_after>var _ = require('lodash');
var async = require('async-chainable');
var colors = require('colors');
var fs = require('fs');
var reflib = require('reflib');

console.log('Beginning analysis');

async()
	.set('output', 'data/database-analysis.csv')
	.set('refs', [])
	.set('dbs', [
		{id: 'db-a', title: 'DB-A', file: 'data/db-a.xml'},
		/*{id: 'db-b', title: 'DB-B', file: 'data/db-b.xml'},
		{id: 'db-c', title: 'DB-C', file: 'data/db-c.xml'},
		{id: 'db-d', title: 'DB-D', file: 'data/db-d.xml'},
		{id: 'db-e', title: 'DB-E', file: 'data/db-e.xml'},
		{id: 'db-f', title: 'DB-F', file: 'data/db-f.xml'},
		{id: 'db-g', title: 'DB-G', file: 'data/db-g.xml'},*/
	])
	.forEach('dbs', function(next, db) {
		console.log(colors.grey('Processing database file'), colors.grey(db.file));
		var self = this;
		var refCount = 0;
		reflib.parseFile(db.file)
			.on('error', function(err) {
				next(err);
			})
			.on('ref', function(newRef) {
				refCount++;
				// Try to find an existing similar ref {{{
				if (!newRef.title) {
					console.log('Skipping blank title');
					return;
				}
				// Generate a searchable title to match by {{{
				var queryTitle = newRef.title
					.replace(/[^A-Z0-9]+/i, ' ');
				// }}}
				var found = _.find(self.refs.find, function(existingRef) {
					return existingRef.titleQuery == queryTitle;
				});
				// }}}

				if (found) { // Found existing - merge
					found.sources[db.id] = newRef.notes;
				} else { // No existing one located - create new
					newRef.sources = {};
					newRef.sources[db.id] = newRef.notes;
					newRef.titleQuery = queryTitle;
					self.refs.push(newRef);
				}
			})
			.on('end', function() {
				console.log('Extracted', colors.cyan(refCount), 'from', colors.cyan(db.file));
				next();
			});
	})
	.then(function(next) {
		var self = this;
		var csv = fs.openSync(self.output, 'w');
		console.log(colors.grey('Writing CSV file'));

		// Write header {{{
		fs.writeSync(csv, ['Paper Title'].concat(self.dbs.map(function(db) {
			return db.title;
		})).join(',') + "\n");
		// }}}
		self.refs.forEach(function(ref, index) {
			fs.writeSync(csv, ['\"' + ref.title + '\"'].concat(self.dbs.map(function(db) {
				return ref.sources[db.id] || 'Missing';
			})).join(',') + "\n");
		});

		fs.closeSync(csv);
		next();
	})
	.end(function(err) {
		if (err) {
			console.log(colors.red('ERROR'), err);
			process.exit(1);
		}

		console.log();
		console.log(colors.green('Completed'));
		console.log(colors.cyan(this.refs.length), 'unqiue references processed from', colors.cyan(this.dbs.length), 'databases');
		console.log('Analysis file saved to', colors.cyan(this.output));
		process.exit(1);
	});
<|endoftext|>


<commit_before>/**
 * Keet.js v2.0 Alpha release: https://github.com/syarul/keet
 * an API for web application
 *
 * <<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Keet.js >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 *
 * Copyright 2017, Shahrul Nizam Selamat
 * Released under the MIT License.
 */
'use strict'
var cat = require('./cat')
var copy = require('./copy')

module.exports = Keet

function Keet(tagName, context) {
  var ctx = this
  ,   argv = [].slice.call(arguments)
  ,   context = argv.filter(function(c) { return typeof c === 'object'})[0]
  ,   isDoc = (function() {
        return typeof document == 'object' ? true : false
      }())
  ,   getId = function(id) {
        var ret
        if (isDoc) {
            ret = document.getElementById(id)
        } else {
            throw ('Not a document object model.')
        }
        return ret
      }
  ,   testEval = function(ev) {
        try { return eval(ev) }
        catch (e) { return false }
      }
  ,   camelCase = function(s) {
        var rx = /\-([a-z])/g
        return s.replace(rx, function(a, b) {
          return b.toUpperCase()
        })
      }
  ,   guid = function(){
        return (Math.round(Math.random()*0x1000000)).toString(32)
      }
  ,   genElement = function(child){
        var tempDiv = document.createElement('div')
        var cloneChild = copy(child)
        delete cloneChild.template
        delete cloneChild.tag
        delete cloneChild.click
        delete cloneChild.style
        delete cloneChild.bind
        for(var attr in cloneChild){
          if(typeof cloneChild[attr] === 'function'){
            delete cloneChild[attr]
          }
        }
        var s = tag(child.tag, child.template ? child.template : '', cloneChild, child.style)
        tempDiv.innerHTML = s
        if(child.tag === 'input'){
          if (child.click) tempDiv.childNodes[0].click()
          if (child.bind){
            ctx.bind(child.bind.type, child.bind.fn)
          }
          if (child.checked) tempDiv.childNodes[0].checked = 'checked'
          else if(child.checked === false)
            tempDiv.childNodes[0].checked = false
        }
        process_k_click(tempDiv)
        return tempDiv.childNodes[0]
      }
  ,   parseStr = function(appObj, watch){
        var str = appObj.template ? appObj.template : ''
        ,   childs = str.match(/{{([^{}]+)}}/g, '$1')
        ,   regc
        ,   child
        ,   tempDiv
        ,   elemArr = []
        if(childs){

          if(Array.isArray(appObj.list)) {
              var arrProps = str.match(/{{([^{}]+)}}/g, '$1'), tmplStr = '', tmpl
              appObj.list.forEach(function(r) {
                tmpl = str
                arrProps.forEach(function(s) {
                  var rep = s.replace(/{{([^{}]+)}}/g, '$1')
                  tmpl = tmpl.replace(/{{([^{}]+)}}/, r[rep])
                })
                tempDiv = document.createElement('div')
                tempDiv.innerHTML = tmpl
                process_k_click(tempDiv)
                elemArr.push(tempDiv.childNodes[0])
              })
              watcher3(appObj.list)
          } else {
            childs.forEach(function(c, index){
              regc = c.replace(/{{([^{}]+)}}/g, '$1')
              // skip tags which not being declared yet
              if(context){
                // check closure object
                child = context[regc] ? context[regc] : false
              } else {
                // check if current  objectr has prop
                child = appObj[regc]
                // check global object
                if(!child) child = testEval(regc) ? eval(regc) : false
              }
              if(child && typeof child === 'object'){
                var newElement = genElement(child)
                elemArr.push(newElement)
              } else if(!child){
                tempDiv = document.createElement('div')
                tempDiv.innerHTML = c
                elemArr.push(tempDiv.childNodes[0])
              }

              // watch object state
              if(watch && child) {
                watcher(child, index)
              }
            })
          }

        } else {
          tempDiv = document.createElement('div')
          tempDiv.innerHTML = str
          elemArr.push(tempDiv.childNodes[0])
          watcher2(appObj)
        }
        return elemArr
  }
  ,   process_k_click = function(kNode){
        var listKnodeChild = []
        if(kNode.hasChildNodes()){
          loopChilds(listKnodeChild, kNode)
          listKnodeChild.forEach(function(c, i){
            if(c.nodeType === 1 && c.hasAttributes()){
              var kStringSingle = c.getAttribute('k-click')
              var KStringDouble = c.getAttribute('k-double-click')
              var kString = KStringDouble || kStringSingle
              var isDouble = KStringDouble ? true : false
              if(kString){
                var kFn = kString.split('(')
                var kClick
                if(kFn){
                  kClick = testEval(ctx.base[kFn[0]]) ? eval(ctx.base[kFn[0]]) : false
                  if(typeof kClick === 'function') processClickEvt(c, kClick, kFn, isDouble)
                }

              }
            }
          })
        }
        listKnodeChild = []
  }
  ,   processClickEvt = function(c, kClick, kFn, isDouble) {
        var click = isDouble ? 'dblclick' : 'click'
        var rem = isDouble ? 'k-double-click' : 'k-click'
        c.removeAttribute(rem)
        c.addEventListener(click, function(evt){
          var argv = []
          argv.push(evt)
          if(kFn) {
            var v = kFn[1].slice(0, -1).split(',')
            if(v) v.forEach(function(v){ argv.push(v) })
          }
          return kClick.apply(c, argv)
        })
  }

  /**
  * render component to DOM
  */

  this.render = function(){
    var ele = getId(ctx.el)
    if(context) ctx.base = context
    var elArr = parseStr(ctx.base, true)
    for (var i = 0; i < elArr.length; i++) {
      ele.appendChild(elArr[i])
    }

  }

  this.update = function(appObj){
    var ele = getId(ctx.el)
    var elArr = parseStr(appObj, true)
    for (var i = 0; i < elArr.length; i++) {
      ele.replaceChild(elArr[i], ele.childNodes[i])
    }
  }

  this.bind = function(type, fn){
    var ele = getId(ctx.el)
    ele.addEventListener(type, ctx.base ? fn.bind(ctx.base) : fn, false)
  }

  var watcher = function(instance, index){
    var obj, attr, ele, copyInstance, newElem
    for (attr in instance){
      instance.watch(attr, function(idx, o, n) {
        instance.unwatch(attr)
        obj = {}
        obj[idx] = n
        ele = getId(ctx.el)
        if(idx !== 'click'){
          copyInstance = copy(instance)
          Object.assign(copyInstance, obj)
          newElem = genElement(copyInstance)
          updateElem(ele.childNodes[index], newElem)
        } else {
          ele.childNodes[index].click()
        }
        watcher(instance, index)
      })
    }
  }

  var watcher2 = function(instance){
    var obj, attr, ele, copyInstance, newElem
    for (attr in instance){
      instance.watch(attr, function(idx, o, n) {
        instance.unwatch(attr)
        obj = {}
        obj[idx] = n
        ele = getId(ctx.el)
        if(idx !== 'click'){
          copyInstance = copy(instance)
          Object.assign(copyInstance, obj)
          newElem = genElement(copyInstance)
          updateElem(ele, newElem)
        } else {
          ele.click()
        }
        watcher2(instance)
      })
    }
  }

  var watcher3 = function(instance){
    var pristineLen = copy(instance), opsList, op, query

    opsList = function() { return ['push', 'pop', 'shift', 'unshift', 'splice', 'update'] }

    op = opsList()

    query = function(ops, argvs) {
      op = []
      if(ops === 'push')
        arrProtoPush(argvs[0])
      else if(ops === 'pop')
        arrProtoPop()
      else if(ops === 'shift')
        arrProtoShift()
      else if(ops === 'unshift')
        arrProtoUnShift.apply(null, argvs)
      else if(ops === 'splice')
        arrProtoSplice.apply(null, argvs)
      else
        arrProtoUpdate.apply(null, argvs)
      op = opsList()
      pristineLen = copy(instance)
    }

    op.forEach(function(f, i, r){
      instance[f] = function() {
        if(op.length > 0) {
          var fargv = [].slice.call(arguments)
          Array.prototype[f].apply(this, fargv)
          //propagate splice with single arguments
          if(fargv.length === 1 && f === 'splice')
            fargv.push(pristineLen.length - fargv[0])
          query(f, fargv)
        }
      }
    })
  }

  var arrProtoPush = function(newObj){
    var ele = getId(ctx.el)
    ele.appendChild(genTemplate(newObj))
  }

  var arrProtoPop = function(){
    var ele = getId(ctx.el)
    if(ele.childNodes.length) {
      ele.removeChild(ele.lastChild)
    }
  }

  var arrProtoShift = function(){
    var ele = getId(ctx.el)
    if(ele.childNodes.length) {
      ele.removeChild(ele.firstChild)
    }
  }

  var arrProtoUnShift = function(){
    var argv = [].slice.call(arguments)
    var ele = getId(ctx.el)
    var i = argv.length - 1
    while(i > -1) {
      ele.insertBefore(genTemplate(argv[i]), ele.firstChild)
      i--
    }
  }

  var arrProtoSplice = function(){
    var ele = getId(ctx.el)
    ,   childLen
    ,   len
    ,   i
    ,   j
    ,   k
    ,   c
    ,   tempDivChildLen
    ,   tempDiv
    ,   argv = [].slice.call(arguments)
    ,   start = [].shift.call(argv)
    ,   count
    if(typeof argv[0] === 'number'){
      count = [].shift.call(argv)
    }

    tempDiv = document.createElement('div')
    if(argv.length){
      i = 0
      while(i < argv.length){
        tempDiv.appendChild(genTemplate(argv[i]))
        i++
      }
    }

    childLen = copy(ele.childNodes.length)
    tempDivChildLen = copy(tempDiv.childNodes.length)
    if (count && count > 0) {
      for (i = start; i < childLen + 1; i++) {
        len = start + count
        if (i < len) {
          ele.removeChild(ele.childNodes[start])
          if (i === len - 1 && tempDivChildLen > 0) {
            c = start - 1
            for (j = start; j < tempDivChildLen + start; j++) {
              insertAfter(tempDiv.childNodes[0], ele.childNodes[c], ele)
              c++
            }
          }
        }
      }
    } else if (argv.length) {
      c = start - 1
      for (k = start; k < tempDivChildLen + start; k++) {
        insertAfter(tempDiv.childNodes[0], ele.childNodes[c], ele)
        c++
      }
    }
  }

  var arrProtoUpdate = function(){
    var argv = [].slice.call(arguments)
    ,   ele = getId(ctx.el)
    ,   index = [].shift.call(argv)
    updateElem(ele.childNodes[index], genTemplate(argv[0]))
  }

  var genTemplate = function(obj){
    var arrProps = ctx.base.template.match(/{{([^{}]+)}}/g, '$1'),  tmpl, tempDiv, ele
    tmpl = ctx.base.template
    arrProps.forEach(function(s) {
      var rep = s.replace(/{{([^{}]+)}}/g, '$1')
      tmpl = tmpl.replace(/{{([^{}]+)}}/, obj[rep])
    })
    tempDiv = document.createElement('div')
    tempDiv.innerHTML = tmpl
    return tempDiv.childNodes[0]
  }

  var loopChilds = function(arr, elem) {
    for (var child = elem.firstChild; child !== null; child = child.nextSibling) {
      arr.push(child)
      if (child.hasChildNodes()) {
        loopChilds(arr, child)
      }
    }
  }

  var insertAfter = function(newNode, referenceNode, parentNode) {
    referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling)
  }

  var nodeUpdate = function(newNode, oldNode) {
    var oAttr = newNode.attributes
    var output = {};
    for(var i = oAttr.length - 1; i >= 0; i--) {
       output[oAttr[i].name] = oAttr[i].value
    }
    for (var iAttr in output) {
      if(oldNode.attributes[iAttr] && oldNode.attributes[iAttr].name === iAttr && oldNode.attributes[iAttr].value != output[iAttr]){
        if(iAttr === 'click') oldNode.click()
        else oldNode.setAttribute(iAttr, output[iAttr])
      }
    }
    output = {}
  }

  var nodeUpdateHTML = function(newNode, oldNode) {
    if(newNode.nodeValue !== oldNode.nodeValue)
        oldNode.nodeValue = newNode.nodeValue
  }

  var updateElem = function(oldElem, newElem){
    // console.log(oldElem)
    var oldArr = [], newArr = []
    oldArr.push(oldElem)
    newArr.push(newElem)
    loopChilds(oldArr, oldElem)
    loopChilds(newArr, newElem)
    if(oldArr.length !== newArr.length){
      // if nodeList length is different, replace the HTMLString
      oldElem.innerHTML = newElem.innerHTML
      return false
    }

    oldArr.forEach(function(ele, idx, arr) {
      if (ele.nodeType === 1 && ele.hasAttributes()) {
        nodeUpdate(newArr[idx], ele)
      } else if (ele.nodeType === 3) {
        nodeUpdateHTML(newArr[idx], ele)
      }
      if(idx === arr.length - 1){
        oldArr.splice(0)
        newArr.splice(0)
      }
    })
  }

  if (!Object.prototype.watch) {
    Object.defineProperty(Object.prototype, 'watch', {
      enumerable: false,
      configurable: true,
      writable: false,
      value: function(prop, handler) {
        var oldval = this[prop],
          newval = oldval,
          getter = function() {
            return newval
          },
          setter = function(val) {
            oldval = newval
            return newval = handler.call(this, prop, oldval, val)
          }
        if (delete this[prop]) {
          Object.defineProperty(this, prop, {
            get: getter,
            set: setter,
            enumerable: true,
            configurable: true
          })
        }
      }
    })
  }

  if (!Object.prototype.unwatch) {
    Object.defineProperty(Object.prototype, 'unwatch', {
      enumerable: false,
      configurable: true,
      writable: false,
      value: function(prop) {
        var val = this[prop]
        delete this[prop]
        this[prop] = val
      }
    })
  }

  if(!Array.prototype.update){
    Object.defineProperty(Array.prototype, 'update', {
        enumerable: false,
        writable: true,
        value: function(index, value) {
          this[index] = value
        }
    })
  }
}

Keet.prototype.link = function(id, value) {
  var argv = [].slice.call(arguments)

  this.el = argv[0]
  if (argv.length === 2){
    if(!argv[1].tag){
      argv[1].tag = document.getElementById(id).tagName.toLowerCase()
    }
    this.base = argv[1]
  }
  this.render()
  return this
}

Keet.prototype.compose = function(instance) {
  this.update(instance)
  return this
}<commit_msg>added require for tag<commit_after>/**
 * Keet.js v2.0 Alpha release: https://github.com/syarul/keet
 * an API for web application
 *
 * <<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Keet.js >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 *
 * Copyright 2017, Shahrul Nizam Selamat
 * Released under the MIT License.
 */
'use strict'
var cat = require('./cat')
var copy = require('./copy')
var tag = require('./tag')

module.exports = Keet

function Keet(tagName, context) {
  var ctx = this
  ,   argv = [].slice.call(arguments)
  ,   context = argv.filter(function(c) { return typeof c === 'object'})[0]
  ,   isDoc = (function() {
        return typeof document == 'object' ? true : false
      }())
  ,   getId = function(id) {
        var ret
        if (isDoc) {
            ret = document.getElementById(id)
        } else {
            throw ('Not a document object model.')
        }
        return ret
      }
  ,   testEval = function(ev) {
        try { return eval(ev) }
        catch (e) { return false }
      }
  ,   camelCase = function(s) {
        var rx = /\-([a-z])/g
        return s.replace(rx, function(a, b) {
          return b.toUpperCase()
        })
      }
  ,   guid = function(){
        return (Math.round(Math.random()*0x1000000)).toString(32)
      }
  ,   genElement = function(child){
        var tempDiv = document.createElement('div')
        var cloneChild = copy(child)
        delete cloneChild.template
        delete cloneChild.tag
        delete cloneChild.click
        delete cloneChild.style
        delete cloneChild.bind
        for(var attr in cloneChild){
          if(typeof cloneChild[attr] === 'function'){
            delete cloneChild[attr]
          }
        }
        var s = tag(child.tag, child.template ? child.template : '', cloneChild, child.style)
        tempDiv.innerHTML = s
        if(child.tag === 'input'){
          if (child.click) tempDiv.childNodes[0].click()
          if (child.bind){
            ctx.bind(child.bind.type, child.bind.fn)
          }
          if (child.checked) tempDiv.childNodes[0].checked = 'checked'
          else if(child.checked === false)
            tempDiv.childNodes[0].checked = false
        }
        process_k_click(tempDiv)
        return tempDiv.childNodes[0]
      }
  ,   parseStr = function(appObj, watch){
        var str = appObj.template ? appObj.template : ''
        ,   childs = str.match(/{{([^{}]+)}}/g, '$1')
        ,   regc
        ,   child
        ,   tempDiv
        ,   elemArr = []
        if(childs){

          if(Array.isArray(appObj.list)) {
              var arrProps = str.match(/{{([^{}]+)}}/g, '$1'), tmplStr = '', tmpl
              appObj.list.forEach(function(r) {
                tmpl = str
                arrProps.forEach(function(s) {
                  var rep = s.replace(/{{([^{}]+)}}/g, '$1')
                  tmpl = tmpl.replace(/{{([^{}]+)}}/, r[rep])
                })
                tempDiv = document.createElement('div')
                tempDiv.innerHTML = tmpl
                process_k_click(tempDiv)
                elemArr.push(tempDiv.childNodes[0])
              })
              watcher3(appObj.list)
          } else {
            childs.forEach(function(c, index){
              regc = c.replace(/{{([^{}]+)}}/g, '$1')
              // skip tags which not being declared yet
              if(context){
                // check closure object
                child = context[regc] ? context[regc] : false
              } else {
                // check if current  objectr has prop
                child = appObj[regc]
                // check global object
                if(!child) child = testEval(regc) ? eval(regc) : false
              }
              if(child && typeof child === 'object'){
                var newElement = genElement(child)
                elemArr.push(newElement)
              } else if(!child){
                tempDiv = document.createElement('div')
                tempDiv.innerHTML = c
                elemArr.push(tempDiv.childNodes[0])
              }

              // watch object state
              if(watch && child) {
                watcher(child, index)
              }
            })
          }

        } else {
          tempDiv = document.createElement('div')
          tempDiv.innerHTML = str
          elemArr.push(tempDiv.childNodes[0])
          watcher2(appObj)
        }
        return elemArr
  }
  ,   process_k_click = function(kNode){
        var listKnodeChild = []
        if(kNode.hasChildNodes()){
          loopChilds(listKnodeChild, kNode)
          listKnodeChild.forEach(function(c, i){
            if(c.nodeType === 1 && c.hasAttributes()){
              var kStringSingle = c.getAttribute('k-click')
              var KStringDouble = c.getAttribute('k-double-click')
              var kString = KStringDouble || kStringSingle
              var isDouble = KStringDouble ? true : false
              if(kString){
                var kFn = kString.split('(')
                var kClick
                if(kFn){
                  kClick = testEval(ctx.base[kFn[0]]) ? eval(ctx.base[kFn[0]]) : false
                  if(typeof kClick === 'function') processClickEvt(c, kClick, kFn, isDouble)
                }

              }
            }
          })
        }
        listKnodeChild = []
  }
  ,   processClickEvt = function(c, kClick, kFn, isDouble) {
        var click = isDouble ? 'dblclick' : 'click'
        var rem = isDouble ? 'k-double-click' : 'k-click'
        c.removeAttribute(rem)
        c.addEventListener(click, function(evt){
          var argv = []
          argv.push(evt)
          if(kFn) {
            var v = kFn[1].slice(0, -1).split(',')
            if(v) v.forEach(function(v){ argv.push(v) })
          }
          return kClick.apply(c, argv)
        })
  }

  /**
  * render component to DOM
  */

  this.render = function(){
    var ele = getId(ctx.el)
    if(context) ctx.base = context
    var elArr = parseStr(ctx.base, true)
    for (var i = 0; i < elArr.length; i++) {
      ele.appendChild(elArr[i])
    }

  }

  this.update = function(appObj){
    var ele = getId(ctx.el)
    var elArr = parseStr(appObj, true)
    for (var i = 0; i < elArr.length; i++) {
      ele.replaceChild(elArr[i], ele.childNodes[i])
    }
  }

  this.bind = function(type, fn){
    var ele = getId(ctx.el)
    ele.addEventListener(type, ctx.base ? fn.bind(ctx.base) : fn, false)
  }

  var watcher = function(instance, index){
    var obj, attr, ele, copyInstance, newElem
    for (attr in instance){
      instance.watch(attr, function(idx, o, n) {
        instance.unwatch(attr)
        obj = {}
        obj[idx] = n
        ele = getId(ctx.el)
        if(idx !== 'click'){
          copyInstance = copy(instance)
          Object.assign(copyInstance, obj)
          newElem = genElement(copyInstance)
          updateElem(ele.childNodes[index], newElem)
        } else {
          ele.childNodes[index].click()
        }
        watcher(instance, index)
      })
    }
  }

  var watcher2 = function(instance){
    var obj, attr, ele, copyInstance, newElem
    for (attr in instance){
      instance.watch(attr, function(idx, o, n) {
        instance.unwatch(attr)
        obj = {}
        obj[idx] = n
        ele = getId(ctx.el)
        if(idx !== 'click'){
          copyInstance = copy(instance)
          Object.assign(copyInstance, obj)
          newElem = genElement(copyInstance)
          updateElem(ele, newElem)
        } else {
          ele.click()
        }
        watcher2(instance)
      })
    }
  }

  var watcher3 = function(instance){
    var pristineLen = copy(instance), opsList, op, query

    opsList = function() { return ['push', 'pop', 'shift', 'unshift', 'splice', 'update'] }

    op = opsList()

    query = function(ops, argvs) {
      op = []
      if(ops === 'push')
        arrProtoPush(argvs[0])
      else if(ops === 'pop')
        arrProtoPop()
      else if(ops === 'shift')
        arrProtoShift()
      else if(ops === 'unshift')
        arrProtoUnShift.apply(null, argvs)
      else if(ops === 'splice')
        arrProtoSplice.apply(null, argvs)
      else
        arrProtoUpdate.apply(null, argvs)
      op = opsList()
      pristineLen = copy(instance)
    }

    op.forEach(function(f, i, r){
      instance[f] = function() {
        if(op.length > 0) {
          var fargv = [].slice.call(arguments)
          Array.prototype[f].apply(this, fargv)
          //propagate splice with single arguments
          if(fargv.length === 1 && f === 'splice')
            fargv.push(pristineLen.length - fargv[0])
          query(f, fargv)
        }
      }
    })
  }

  var arrProtoPush = function(newObj){
    var ele = getId(ctx.el)
    ele.appendChild(genTemplate(newObj))
  }

  var arrProtoPop = function(){
    var ele = getId(ctx.el)
    if(ele.childNodes.length) {
      ele.removeChild(ele.lastChild)
    }
  }

  var arrProtoShift = function(){
    var ele = getId(ctx.el)
    if(ele.childNodes.length) {
      ele.removeChild(ele.firstChild)
    }
  }

  var arrProtoUnShift = function(){
    var argv = [].slice.call(arguments)
    var ele = getId(ctx.el)
    var i = argv.length - 1
    while(i > -1) {
      ele.insertBefore(genTemplate(argv[i]), ele.firstChild)
      i--
    }
  }

  var arrProtoSplice = function(){
    var ele = getId(ctx.el)
    ,   childLen
    ,   len
    ,   i
    ,   j
    ,   k
    ,   c
    ,   tempDivChildLen
    ,   tempDiv
    ,   argv = [].slice.call(arguments)
    ,   start = [].shift.call(argv)
    ,   count
    if(typeof argv[0] === 'number'){
      count = [].shift.call(argv)
    }

    tempDiv = document.createElement('div')
    if(argv.length){
      i = 0
      while(i < argv.length){
        tempDiv.appendChild(genTemplate(argv[i]))
        i++
      }
    }

    childLen = copy(ele.childNodes.length)
    tempDivChildLen = copy(tempDiv.childNodes.length)
    if (count && count > 0) {
      for (i = start; i < childLen + 1; i++) {
        len = start + count
        if (i < len) {
          ele.removeChild(ele.childNodes[start])
          if (i === len - 1 && tempDivChildLen > 0) {
            c = start - 1
            for (j = start; j < tempDivChildLen + start; j++) {
              insertAfter(tempDiv.childNodes[0], ele.childNodes[c], ele)
              c++
            }
          }
        }
      }
    } else if (argv.length) {
      c = start - 1
      for (k = start; k < tempDivChildLen + start; k++) {
        insertAfter(tempDiv.childNodes[0], ele.childNodes[c], ele)
        c++
      }
    }
  }

  var arrProtoUpdate = function(){
    var argv = [].slice.call(arguments)
    ,   ele = getId(ctx.el)
    ,   index = [].shift.call(argv)
    updateElem(ele.childNodes[index], genTemplate(argv[0]))
  }

  var genTemplate = function(obj){
    var arrProps = ctx.base.template.match(/{{([^{}]+)}}/g, '$1'),  tmpl, tempDiv, ele
    tmpl = ctx.base.template
    arrProps.forEach(function(s) {
      var rep = s.replace(/{{([^{}]+)}}/g, '$1')
      tmpl = tmpl.replace(/{{([^{}]+)}}/, obj[rep])
    })
    tempDiv = document.createElement('div')
    tempDiv.innerHTML = tmpl
    return tempDiv.childNodes[0]
  }

  var loopChilds = function(arr, elem) {
    for (var child = elem.firstChild; child !== null; child = child.nextSibling) {
      arr.push(child)
      if (child.hasChildNodes()) {
        loopChilds(arr, child)
      }
    }
  }

  var insertAfter = function(newNode, referenceNode, parentNode) {
    referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling)
  }

  var nodeUpdate = function(newNode, oldNode) {
    var oAttr = newNode.attributes
    var output = {};
    for(var i = oAttr.length - 1; i >= 0; i--) {
       output[oAttr[i].name] = oAttr[i].value
    }
    for (var iAttr in output) {
      if(oldNode.attributes[iAttr] && oldNode.attributes[iAttr].name === iAttr && oldNode.attributes[iAttr].value != output[iAttr]){
        if(iAttr === 'click') oldNode.click()
        else oldNode.setAttribute(iAttr, output[iAttr])
      }
    }
    output = {}
  }

  var nodeUpdateHTML = function(newNode, oldNode) {
    if(newNode.nodeValue !== oldNode.nodeValue)
        oldNode.nodeValue = newNode.nodeValue
  }

  var updateElem = function(oldElem, newElem){
    // console.log(oldElem)
    var oldArr = [], newArr = []
    oldArr.push(oldElem)
    newArr.push(newElem)
    loopChilds(oldArr, oldElem)
    loopChilds(newArr, newElem)
    if(oldArr.length !== newArr.length){
      // if nodeList length is different, replace the HTMLString
      oldElem.innerHTML = newElem.innerHTML
      return false
    }

    oldArr.forEach(function(ele, idx, arr) {
      if (ele.nodeType === 1 && ele.hasAttributes()) {
        nodeUpdate(newArr[idx], ele)
      } else if (ele.nodeType === 3) {
        nodeUpdateHTML(newArr[idx], ele)
      }
      if(idx === arr.length - 1){
        oldArr.splice(0)
        newArr.splice(0)
      }
    })
  }

  if (!Object.prototype.watch) {
    Object.defineProperty(Object.prototype, 'watch', {
      enumerable: false,
      configurable: true,
      writable: false,
      value: function(prop, handler) {
        var oldval = this[prop],
          newval = oldval,
          getter = function() {
            return newval
          },
          setter = function(val) {
            oldval = newval
            return newval = handler.call(this, prop, oldval, val)
          }
        if (delete this[prop]) {
          Object.defineProperty(this, prop, {
            get: getter,
            set: setter,
            enumerable: true,
            configurable: true
          })
        }
      }
    })
  }

  if (!Object.prototype.unwatch) {
    Object.defineProperty(Object.prototype, 'unwatch', {
      enumerable: false,
      configurable: true,
      writable: false,
      value: function(prop) {
        var val = this[prop]
        delete this[prop]
        this[prop] = val
      }
    })
  }

  if(!Array.prototype.update){
    Object.defineProperty(Array.prototype, 'update', {
        enumerable: false,
        writable: true,
        value: function(index, value) {
          this[index] = value
        }
    })
  }
}

Keet.prototype.link = function(id, value) {
  var argv = [].slice.call(arguments)

  this.el = argv[0]
  if (argv.length === 2){
    if(!argv[1].tag){
      argv[1].tag = document.getElementById(id).tagName.toLowerCase()
    }
    this.base = argv[1]
  }
  this.render()
  return this
}

Keet.prototype.compose = function(instance) {
  this.update(instance)
  return this
}<|endoftext|>


<commit_before>var EventEmitter = require('eventemitter3');

module.exports = function(prot, methods, attributes, events) {

  function emitter(target) {
    if (! target.__emitter) {
      target.__emitter = new EventEmitter();
    }

    return target.__emitter;
  }

  // patch methods
  methods.forEach(function(method) {
    target[method] = function() {
      var fn = this.__orig && this.__orig[method];

      if (typeof fn == 'function') {
        return fn.apply(this.__orig, arguments);
      }
    };
  });

  // patch properties
  attributes.forEach(function(attrData) {
    var key = attrData[0];
    var readonly = attrData[1];
    var gs = {
      get: function() {
        return this.__orig[key];
      }
    };

    if (! readonly) {
      gs.set = function(value) {
        this.__orig[key] = value;
      };
    }

    Object.defineProperty(prot, key, gs);
  });

  events.forEach(function(name) {
    Object.defineProperty(prot, 'on' + name, {
      get: function() {
        return emitter(this).listeners(name)[0];
      },

      set: function(handler) {
        emitter(this).on(name, handler);
      }
    });
  });

  prot.addEventListener = function(name, handler) {
    emitter(this).on(name, handler);
  };

  prot.removeEventListener = function(name, handler) {
    emitter(this).removeListener(name, handler);
  };

  return prot;
};
<commit_msg>Properly pass through event handling<commit_after>var EventEmitter = require('eventemitter3');

module.exports = function(prot, methods, attributes, events) {

  function capEvents(target, name) {
    var events = emitter(target);

    if (typeof target.__orig['on' + name] != 'function') {
      target.__orig['on' + name] = function() {
        events.emit.apply(events, [name].concat([].slice.call(arguments)));
      };
    }

    return events;
  }

  function emitter(target) {
    if (! target.__emitter) {
      target.__emitter = new EventEmitter();
    }

    return target.__emitter;
  }

  // patch methods
  (methods || []).forEach(function(method) {
    prot[method] = function() {
      var fn = this.__orig && this.__orig[method];

      if (typeof fn == 'function') {
        return fn.apply(this.__orig, arguments);
      }

      console.warn('could not invoke: ' + method);
    };
  });

  // patch properties
  (attributes || []).forEach(function(attrData) {
    var key = attrData[0];
    var readonly = attrData[1];
    var gs = {
      get: function() {
        return this.__orig[key];
      }
    };

    if (! readonly) {
      gs.set = function(value) {
        this.__orig[key] = value;
      };
    }

    Object.defineProperty(prot, key, gs);
  });

  (events || []).forEach(function(name) {
    Object.defineProperty(prot, 'on' + name, {
      get: function() {
        return emitter(this).listeners(name)[0];
      },

      set: function(handler) {
        var events = capEvents(this, name);

        if (! handler) {
          return events.removeAllListeners(name);
        }

        events.on(name, handler);
      }
    });
  });

  prot.addEventListener = function(name, handler) {
    capEvents(this, name).on(name, handler);
  };

  prot.removeEventListener = function(name, handler) {
    emitter(this).removeListener(name, handler);
  };

  return prot;
};
<|endoftext|>