<commit_before>'use strict';

var path = require('path');
var util = require('expand-utils');
var utils = require('./utils');
var use = require('use');

/**
 * Create an instance of `ExpandFiles` with `options`.
 *
 * ```js
 * var config = new ExpandFiles({cwd: 'src'});
 * ```
 * @param {Object} `options`
 * @api public
 */

function ExpandFiles(options) {
  if (!(this instanceof ExpandFiles)) {
    return new ExpandFiles(options);
  }

  // add `isFiles` non-enumberable property
  utils.define(this, 'isFiles', true);

  // enable plugins
  use(this);

  this.options = options || {};
  if (util.isFiles(options) || arguments.length > 1) {
    this.options = {};
    this.expand.apply(this, arguments);
    return this;
  }
}

/**
 * Normalize and expand files definitions and src-dest mappings
 * from a declarative configuration.
 *
 * ```js
 * var config = new ExpandFiles({cwd: 'src'});
 * config.expand({src: '*.hbs', dest: 'templates/'});
 * ```
 * @param {Object|String|Array} `src`
 * @param {Object|String} `dest`
 * @param {Object} `options`
 * @return {Object}
 * @api public
 */

ExpandFiles.prototype.expand = function(src, dest, options) {
  var config = utils.normalize.apply(this, arguments);
  util.run(this, 'normalized', config);

  config = expandMapping(config, options);
  util.run(this, 'expanded', config);

  for (var key in config) {
    this[key] = config[key];
  }
  return this;
};

/**
 * Iterate over a files array and expand src-dest mappings
 *
 * ```js
 * { files: [ { src: [ '*.js' ], dest: 'dist/' } ] }
 * ```
 * @param {Object} `config`
 * @param {Object} `options`
 * @return {Object}
 */

function expandMapping(config, options) {
  var len = config.files.length, i = -1;
  var res = [];

  while (++i < len) {
    var node = new RawNode(config.files[i], config);
    if (!node.files.length) {
      continue;
    }
    res.push.apply(res, node.files);
  }
  config.files = res;
  return config;
}

/**
 * Create a `raw` node. A node represents a single element
 * in a `files` array, and "raw" means that `src` glob patterns
 * have not been expanded.
 *
 * @param {Object} `raw`
 * @param {Object} `config`
 * @return {Object}
 */

function RawNode(raw, config) {
  util.run(config, 'rawNode', raw);
  this.files = [];
  var paths = {};

  raw.options = resolvePaths(raw.options);
  var opts = utils.extend({}, raw.options);
  var filter = filterFiles(opts);

  var srcFiles = raw.src;
  if (opts.glob !== false && utils.hasGlob(raw.src)) {
    srcFiles = utils.glob.sync(raw.src, opts);
  }

  srcFiles = srcFiles.filter(filter);

  if (config.options.mapDest) {
    var len = srcFiles.length, i = -1;
    while (++i < len) {
      var node = new Node(srcFiles[i], raw, config);
      var dest = node.dest;
      if (!node.src && !node.path) continue;
      var src = resolveArray(node.src, opts);

      if (paths[dest]) {
        paths[dest].src = paths[dest].src.concat(src);
      } else {
        node.src = arrayify(src);
        this.files.push(node);
        paths[dest] = node;
      }
    }

    if (!this.files.length) {
      node = raw;
      raw.src = [];
      this.files.push(raw);
    }

  } else {
    createNode(srcFiles, raw, this.files, config);
  }
}

/**
 * Create a new `Node` with the given `src`, `raw` node and
 * `config` object.
 *
 * @param {String|Array} `src` Glob patterns
 * @param {Object} `raw` Node with un-expanded glob patterns.
 * @param {Object} `config`
 * @return {Object}
 */

function Node(src, raw, config) {
  this.options = utils.omit(raw.options, ['mapDest', 'flatten', 'rename', 'filter']);
  this.src = arrayify(src);
  if (raw.options.mapDest) {
    this.dest = mapDest(raw.dest, src, raw);
  } else {
    this.dest = rewriteDest(raw.dest, src, raw.options);
  }
  util.run(config, 'node', this);
}

function mapDest(dest, src, node) {
  var opts = node.options;

  if (opts.rename === false) {
    return dest;
  }

  var fp = src;
  if (fp && typeof fp === 'string') {
    fp = !utils.hasGlob(fp) ? fp : '';
    var cwd = path.resolve(opts.cwd || '');
    fp = path.join(cwd, fp);
    fp = utils.relative(cwd, fp);
  } else {
    fp = '';
  }

  if (opts.flatten === true) {
    fp = path.basename(fp);
  }

  if (opts.base === true) {
    opts.base = utils.base(node.orig.src);
  }

  if (opts.base) {
    dest = path.join(dest, opts.base, path.basename(fp));
  } else {
    dest = path.join(dest, fp);
  }
  return rewriteDest(dest, src, opts);
}

/**
 * Used when `mapDest` is not true
 */

function rewriteDest(dest, src, opts) {
  dest = utils.resolve(dest);

  if (opts.destBase) {
    dest = path.join(opts.destBase, dest);
  }

  if (opts.extDot || opts.hasOwnProperty('ext')) {
    dest = rewriteExt(dest, opts);
  }

  if (typeof opts.rename === 'function') {
    return opts.rename(dest, src, opts);
  }
  return dest;
}

function rewriteExt(dest, opts) {
  var re = {first: /(\.[^\/]*)?$/, last: /(\.[^\/\.]*)?$/};

  if (opts.ext === false) {
    opts.ext = '';
  }

  if (opts.ext.charAt(0) !== '.') {
    opts.ext = '.' + opts.ext;
  }

  if (typeof opts.extDot === 'undefined') {
    opts.extDot = 'first';
  }

  dest = dest.replace(re[opts.extDot], opts.ext);
  if (dest.slice(-1) === '.') {
    dest = dest.slice(0, -1);
  }
  return dest;
}

function resolvePaths(opts) {
  if (opts.destBase) {
    opts.destBase = utils.resolve(opts.destBase);
  }
  if (opts.cwd) {
    opts.cwd = utils.resolve(opts.cwd);
  }
  return opts;
}

/**
 * Create a new `Node` and push it onto the `files` array if the
 * returned node has a `path` or `src` property. In plugins, you
 * may remove the `src` and/or `path` properties to prevent nodes
 * from being pushed onto the array.
 */

function createNode(src, raw, files, config) {
  var node = new Node(src, raw, config);
  if (node.path || node.src) {
    files.push(node);
  }
}

/**
 * Default filter function.
 *
 * @param {String} `fp`
 * @param {Object} `opts`
 * @return {Boolean} Returns `true` if a file matches.
 */

function filterFiles(opts) {
  if (typeof opts.filter === 'function') {
    return opts.filter;
  }
  return function(fp) {
    return true;
  };
}

function resolveArray(files, opts) {
  if (!opts.mapDest) return files;

  return files.map(function(fp) {
    return path.join(opts.cwd || '', fp);
  });
}

function arrayify(val) {
  return Array.isArray(val) ? val : [val];
}

/**
 * Expose expand
 */

module.exports = ExpandFiles;
<commit_msg>use hasOwnProperty<commit_after>'use strict';

var path = require('path');
var util = require('expand-utils');
var utils = require('./utils');
var use = require('use');

/**
 * Create an instance of `ExpandFiles` with `options`.
 *
 * ```js
 * var config = new ExpandFiles({cwd: 'src'});
 * ```
 * @param {Object} `options`
 * @api public
 */

function ExpandFiles(options) {
  if (!(this instanceof ExpandFiles)) {
    return new ExpandFiles(options);
  }

  // add `isFiles` non-enumberable property
  utils.define(this, 'isFiles', true);

  // enable plugins
  use(this);

  this.options = options || {};
  if (util.isFiles(options) || arguments.length > 1) {
    this.options = {};
    this.expand.apply(this, arguments);
    return this;
  }
}

/**
 * Normalize and expand files definitions and src-dest mappings
 * from a declarative configuration.
 *
 * ```js
 * var config = new ExpandFiles({cwd: 'src'});
 * config.expand({src: '*.hbs', dest: 'templates/'});
 * ```
 * @param {Object|String|Array} `src`
 * @param {Object|String} `dest`
 * @param {Object} `options`
 * @return {Object}
 * @api public
 */

ExpandFiles.prototype.expand = function(src, dest, options) {
  var config = utils.normalize.apply(this, arguments);
  util.run(this, 'normalized', config);

  config = expandMapping(config, options);
  util.run(this, 'expanded', config);

  for (var key in config) {
    if (config.hasOwnProperty(key)) {
      this[key] = config[key];
    }
  }
  return this;
};

/**
 * Iterate over a files array and expand src-dest mappings
 *
 * ```js
 * { files: [ { src: [ '*.js' ], dest: 'dist/' } ] }
 * ```
 * @param {Object} `config`
 * @param {Object} `options`
 * @return {Object}
 */

function expandMapping(config, options) {
  var len = config.files.length, i = -1;
  var res = [];

  while (++i < len) {
    var node = new RawNode(config.files[i], config);
    if (!node.files.length) {
      continue;
    }
    res.push.apply(res, node.files);
  }
  config.files = res;
  return config;
}

/**
 * Create a `raw` node. A node represents a single element
 * in a `files` array, and "raw" means that `src` glob patterns
 * have not been expanded.
 *
 * @param {Object} `raw`
 * @param {Object} `config`
 * @return {Object}
 */

function RawNode(raw, config) {
  util.run(config, 'rawNode', raw);
  this.files = [];
  var paths = {};

  raw.options = resolvePaths(raw.options);
  var opts = utils.extend({}, raw.options);
  var filter = filterFiles(opts);

  var srcFiles = raw.src;
  if (opts.glob !== false && utils.hasGlob(raw.src)) {
    srcFiles = utils.glob.sync(raw.src, opts);
  }

  srcFiles = srcFiles.filter(filter);

  if (config.options.mapDest) {
    var len = srcFiles.length, i = -1;
    while (++i < len) {
      var node = new Node(srcFiles[i], raw, config);
      var dest = node.dest;
      if (!node.src && !node.path) continue;
      var src = resolveArray(node.src, opts);

      if (paths[dest]) {
        paths[dest].src = paths[dest].src.concat(src);
      } else {
        node.src = arrayify(src);
        this.files.push(node);
        paths[dest] = node;
      }
    }

    if (!this.files.length) {
      node = raw;
      raw.src = [];
      this.files.push(raw);
    }

  } else {
    createNode(srcFiles, raw, this.files, config);
  }
}

/**
 * Create a new `Node` with the given `src`, `raw` node and
 * `config` object.
 *
 * @param {String|Array} `src` Glob patterns
 * @param {Object} `raw` Node with un-expanded glob patterns.
 * @param {Object} `config`
 * @return {Object}
 */

function Node(src, raw, config) {
  this.options = utils.omit(raw.options, ['mapDest', 'flatten', 'rename', 'filter']);
  this.src = arrayify(src);
  if (raw.options.mapDest) {
    this.dest = mapDest(raw.dest, src, raw);
  } else {
    this.dest = rewriteDest(raw.dest, src, raw.options);
  }
  util.run(config, 'node', this);
}

function mapDest(dest, src, node) {
  var opts = node.options;

  if (opts.rename === false) {
    return dest;
  }

  var fp = src;
  if (fp && typeof fp === 'string') {
    fp = !utils.hasGlob(fp) ? fp : '';
    var cwd = path.resolve(opts.cwd || '');
    fp = path.join(cwd, fp);
    fp = utils.relative(cwd, fp);
  } else {
    fp = '';
  }

  if (opts.flatten === true) {
    fp = path.basename(fp);
  }

  if (opts.base === true) {
    opts.base = utils.base(node.orig.src);
  }

  if (opts.base) {
    dest = path.join(dest, opts.base, path.basename(fp));
  } else {
    dest = path.join(dest, fp);
  }
  return rewriteDest(dest, src, opts);
}

/**
 * Used when `mapDest` is not true
 */

function rewriteDest(dest, src, opts) {
  dest = utils.resolve(dest);
  if (opts.destBase) {
    dest = path.join(opts.destBase, dest);
  }
  if (opts.extDot || opts.hasOwnProperty('ext')) {
    dest = rewriteExt(dest, opts);
  }
  if (typeof opts.rename === 'function') {
    return opts.rename(dest, src, opts);
  }
  return dest;
}

function rewriteExt(dest, opts) {
  var re = {first: /(\.[^\/]*)?$/, last: /(\.[^\/\.]*)?$/};

  if (opts.ext === false) {
    opts.ext = '';
  }

  if (opts.ext.charAt(0) !== '.') {
    opts.ext = '.' + opts.ext;
  }

  if (typeof opts.extDot === 'undefined') {
    opts.extDot = 'first';
  }

  dest = dest.replace(re[opts.extDot], opts.ext);
  if (dest.slice(-1) === '.') {
    dest = dest.slice(0, -1);
  }
  return dest;
}

function resolvePaths(opts) {
  if (opts.destBase) {
    opts.destBase = utils.resolve(opts.destBase);
  }
  if (opts.cwd) {
    opts.cwd = utils.resolve(opts.cwd);
  }
  return opts;
}

/**
 * Create a new `Node` and push it onto the `files` array if the
 * returned node has a `path` or `src` property. In plugins, you
 * may remove the `src` and/or `path` properties to prevent nodes
 * from being pushed onto the array.
 */

function createNode(src, raw, files, config) {
  var node = new Node(src, raw, config);
  if (node.path || node.src) {
    files.push(node);
  }
}

/**
 * Default filter function.
 *
 * @param {String} `fp`
 * @param {Object} `opts`
 * @return {Boolean} Returns `true` if a file matches.
 */

function filterFiles(opts) {
  if (typeof opts.filter === 'function') {
    return opts.filter;
  }
  return function(fp) {
    return true;
  };
}

function resolveArray(files, opts) {
  if (!opts.mapDest) return files;

  return files.map(function(fp) {
    return path.join(opts.cwd || '', fp);
  });
}

function arrayify(val) {
  return Array.isArray(val) ? val : [val];
}

/**
 * Expose expand
 */

module.exports = ExpandFiles;
<|endoftext|>


<commit_before>'use strict';

var separator = require('simple-random-id')();

module.exports = function(page, language, cb, options) {
  var request = (options && options.request) || require('request');
  var apiURL = 'http://'+ language + '.wikipedia.org/w/api.php?format' +
               '=json&action=query&prop=revisions&rvprop=content&titles=' +
               page;

  var wikiURL = 'http://' + language +'.wikipedia.org/wiki/';

  request.get(apiURL, function(error, data, body) {
    if (error) {
      cb(error);
      return;
    }

    // Create a JSON object from the response
    var content = JSON.parse(body);

    // The API answers with quite complex JSON structure, similar to this:
    // {
    //   "query" : {
    //     "pages" : {
    //       "32908": {
    //         "revisions": [
    //           "*": CONTENT OF THE PAGE
    // ]}}}}
    //
    // So this is how we will get the content
    content = content.query.pages;
    var page = Object.keys(content);
    content = content[page].revisions[0]['*'];

    // Let's find the beginning of our infobox, it will start with two
    // mustache brackets (I don't know proper English workd for this),
    // unlimited number of spaces and 'infobox' label (can also start with
    // uppercase char).
    var startingPointRegex = /\{\{\s*[Ii]nfobox/;

    // What is the position of the string we are looking for
    // in the whole document?
    var startArray  =  content.match(startingPointRegex);
    if(!startArray) {
      cb(new Error('No infobox found!'));
      return;
    }
    var start = startArray.index;
    // And how big is the block. Since we cannot simply match brackets in
    // JS using RegExp, I wrote small `parse` function that iterates throught
    // the document and counts opened and closed brackets. Stupid as hell but
    // works and performance is really good
    var end = parse(content.substr(start, content.length));

    // And we truncate the string exactly where we need
    content = content.substr(start+2, end);

    // This part is very stupid, but I had no time to figure out something
    // smarter.
    // Remove all the new lines, fields in the infobox are separated with '|'
    // anyway, so it doesn't change a thing.
    content = content.replace(/\n/g, ' ');

    // Now, find all the links ([[IMMA LINK]]) and templates ({{LIKE ME}})
    var result = content.match(/\[\[(.+?)\]\]|\{\{(.+?)\}\}/ig);

    // Iterate thru all of them if any
    if (result !== null) {
      result.forEach(function(link) {
        // And replace each '|' for our custom, random separator string
        content = content.replace(link, link.replace(/\|/g, separator));
      });
    }

    // Because of the stupid thing we did before, we are sure that all the '|'
    // chars (what's the english name for this again?) are separators between
    // fields of the infobox, not special characters in links or templates.
    content = content.split('|');

    // Throw out the first element (it's something like '{{ Infobox', so has
    // no value for us)
    content.shift();

    var output = {};
    // Iterate thru all the fields of the infobox
    content.forEach(function(element) {
      // Every field is a key=value pair, separated by '='
      var splited = element.split('=');

      // Some of them have a lot of white characters what makes no sense at all,
      // so let's trim them.
      splited = splited.map(function(el) {
        return el.trim();
      });

      // This trycatch is needed because sometimes Infobox ends with |}} what is
      // not right (think of it as of additional coma at the end of the array)
      // I know it's not the best way to fix it, but it's the fastest.
      try {
        // Replace previously changed '|' chars again and parse final string
        output[splited[0]] = stringToObject(
          splited[0], // I put this in here because maybe in the future we will
                      // want to determine way of parsing the string based on
                      // type, etc. 'image' field is sometimes just and url,
                      // not a proper wikipedia image ([[File:file_patch.jpg]])
          splited[1].replace(new RegExp(separator, 'g'), '|')
        );

      } catch(e) {
        // Let's be quiet here, it's probably the thing described above
      }

    });

    // return the output to callback
    cb(null, output);

  });

  var stringToObject = function(name, value) {
    // We can find a lot of objects in one infobox field, so we
    // Gotta Catch 'Em All using simple trick with .replace() callback
    var matches = [];
    var fullMatches = [];
    var pom = value;
    value.replace(/\[\[(.*?)\]\]/g, function(g0,g1){matches.push(g1);});
    //After we get every markdown elements from the string we should chcek if
    //between them there is some text
    matches.forEach(function(entry){
        //for every match we split string for two parts and in pom[0] we will
        //have clena text
        pom = pom.split('[['+entry+']]');
      //chceck if clean text is something more than a white space && and
      //something more than , . :
      if(pom[0].match(/\S/) && pom[0].match(/^\s*[\.\,\:]*\s$/)===null) {
        //if it is some text we make object ready to deploy
        fullMatches.push({type: 'text', value: pom[0]});
      }
        fullMatches.push(entry);
        //only second part of split is going to analise
        pom=pom[1];
    });
    //we have to chceck the string that still exist after foreach
    if(pom.match(/\S/) && pom.match(/^\s*[\.\,\:]*\s$/)==null) {
      fullMatches.push({type: 'text', value: pom});
    }
    if (fullMatches.length > 0) {
      var results = [];
      var obj;
      fullMatches.forEach(function(matchElement) {
        // If it's an image, set the type to image
        if(typeof(matchElement)!='object')
        {
          if (
            matchElement.indexOf('File:') > -1 ||
            matchElement.indexOf('Image:') > -1
          ) {
            obj = {
              type: 'image'
            };
          } else {
            // If not, its almost always a link
            obj = {
              type: 'link'
            };
          }

          // Sometimes links have names (aliases) - text that is displayed
          // on the page and redirects to the given page, and is different than
          // the name of the Wiki page, for instance
          // [[Central European Summer Time|CEST]] will display CEST,
          //but clicking on it will redirect to Central European Summer
          //Time page. We need all
          // this information in out object
          matchElement = matchElement.split('|');
          if (matchElement.length > 1) {
            obj.text = matchElement[1];
            obj.url = wikiURL + matchElement[0];
          } else {
            obj.text = matchElement[0];
            obj.url = wikiURL + matchElement[0];
          }
          results.push(obj);
        } else {
          results.push(matchElement);
        }
      });

      // sometimes field is just a text, without any fireworks :(
      if (results.length === 1) {
        results = results.pop();
      }
      return results;

    } else {
      return {type:'text', value:value};
    }
  };

  // This is stupid brackets counting, I don't think it needs any explanation
  var parse = function(text) {
    var brackets = 0;

    for (var i=0, l=text.length; i<l; i++) {
      if (text.charAt(i) === '{') {
        brackets++;
      } else if (text.charAt(i) === '}') {
        brackets--;
      }

      if (brackets === 0 && i > 0) {
        return i-1;
      }
    }
  };
};
<commit_msg>review fixes<commit_after>'use strict';

var separator = require('simple-random-id')();

module.exports = function(page, language, cb, options) {
  var request = (options && options.request) || require('request');
  var apiURL = 'http://'+ language + '.wikipedia.org/w/api.php?format' +
               '=json&action=query&prop=revisions&rvprop=content&titles=' +
               page;

  var wikiURL = 'http://' + language +'.wikipedia.org/wiki/';

  request.get(apiURL, function(error, data, body) {
    if (error) {
      cb(error);
      return;
    }

    // Create a JSON object from the response
    var content = JSON.parse(body);

    // The API answers with quite complex JSON structure, similar to this:
    // {
    //   "query" : {
    //     "pages" : {
    //       "32908": {
    //         "revisions": [
    //           "*": CONTENT OF THE PAGE
    // ]}}}}
    //
    // So this is how we will get the content
    content = content.query.pages;
    var page = Object.keys(content);
    content = content[page].revisions[0]['*'];

    // Let's find the beginning of our infobox, it will start with two
    // mustache brackets (I don't know proper English workd for this),
    // unlimited number of spaces and 'infobox' label (can also start with
    // uppercase char).
    var startingPointRegex = /\{\{\s*[Ii]nfobox/;

    // What is the position of the string we are looking for
    // in the whole document?
    var startArray  =  content.match(startingPointRegex);
    if(!startArray) {
      cb(new Error('No infobox found!'));
      return;
    }
    var start = startArray.index;
    // And how big is the block. Since we cannot simply match brackets in
    // JS using RegExp, I wrote small `parse` function that iterates throught
    // the document and counts opened and closed brackets. Stupid as hell but
    // works and performance is really good
    var end = parse(content.substr(start, content.length));

    // And we truncate the string exactly where we need
    content = content.substr(start+2, end);

    // This part is very stupid, but I had no time to figure out something
    // smarter.
    // Remove all the new lines, fields in the infobox are separated with '|'
    // anyway, so it doesn't change a thing.
    content = content.replace(/\n/g, ' ');

    // Now, find all the links ([[IMMA LINK]]) and templates ({{LIKE ME}})
    var result = content.match(/\[\[(.+?)\]\]|\{\{(.+?)\}\}/ig);

    // Iterate thru all of them if any
    if (result !== null) {
      result.forEach(function(link) {
        // And replace each '|' for our custom, random separator string
        content = content.replace(link, link.replace(/\|/g, separator));
      });
    }

    // Because of the stupid thing we did before, we are sure that all the '|'
    // chars (what's the english name for this again?) are separators between
    // fields of the infobox, not special characters in links or templates.
    content = content.split('|');

    // Throw out the first element (it's something like '{{ Infobox', so has
    // no value for us)
    content.shift();

    var output = {};
    // Iterate thru all the fields of the infobox
    content.forEach(function(element) {
      // Every field is a key=value pair, separated by '='
      var splited = element.split('=');

      // Some of them have a lot of white characters what makes no sense at all,
      // so let's trim them.
      splited = splited.map(function(el) {
        return el.trim();
      });

      // This trycatch is needed because sometimes Infobox ends with |}} what is
      // not right (think of it as of additional coma at the end of the array)
      // I know it's not the best way to fix it, but it's the fastest.
      try {
        // Replace previously changed '|' chars again and parse final string
        output[splited[0]] = stringToObject(
          splited[0], // I put this in here because maybe in the future we will
                      // want to determine way of parsing the string based on
                      // type, etc. 'image' field is sometimes just and url,
                      // not a proper wikipedia image ([[File:file_patch.jpg]])
          splited[1].replace(new RegExp(separator, 'g'), '|')
        );

      } catch(e) {
        // Let's be quiet here, it's probably the thing described above
      }

    });

    // return the output to callback
    cb(null, output);

  });

  var stringToObject = function(name, value) {
    // We can find a lot of objects in one infobox field, so we
    // Gotta Catch 'Em All using simple trick with .replace() callback
    var matches = [];
    var fullMatches = [];
    var pom = value;
    value.replace(/\[\[(.*?)\]\]/g, function(g0,g1){matches.push(g1);});
    //After we get every markdown elements from the string we should check if
    //between them there is some text
    matches.forEach(function(entry){
        //for every match we split string for two parts and in pom[0] we will
        //have clean text
        pom = pom.split('[['+entry+']]');
      //chceck if clean text is something more than a white space && and
      //something more than , . :
      if(pom[0].match(/\S/) && pom[0].match(/^\s*[\.\,\:]*\s$/) === null) {
        //if it is some text we make object ready to deploy
        fullMatches.push({type: 'text', value: pom[0]});
      }
        fullMatches.push(entry);
        //only second part of split is going to analise
        pom = pom[1];
    });
    //we have to chceck the string that still exist after foreach
    if(pom.match(/\S/) && pom.match(/^\s*[\.\,\:]*\s$/) === null) {
      fullMatches.push({type: 'text', value: pom});
    }
    if (fullMatches.length > 0) {
      var results = [];
      var obj;
      fullMatches.forEach(function(matchElement) {
        // If it's an image, set the type to image
        if(typeof(matchElement)!='object')
        {
          if (
            matchElement.indexOf('File:') > -1 ||
            matchElement.indexOf('Image:') > -1
          ) {
            obj = {
              type: 'image'
            };
          } else {
            // If not, its almost always a link
            obj = {
              type: 'link'
            };
          }

          // Sometimes links have names (aliases) - text that is displayed
          // on the page and redirects to the given page, and is different than
          // the name of the Wiki page, for instance
          // [[Central European Summer Time|CEST]] will display CEST,
          //but clicking on it will redirect to Central European Summer
          //Time page. We need all this information in out object
          matchElement = matchElement.split('|');
          if (matchElement.length > 1) {
            obj.text = matchElement[1];
            obj.url = wikiURL + matchElement[0];
          } else {
            obj.text = matchElement[0];
            obj.url = wikiURL + matchElement[0];
          }
          results.push(obj);
        } else {
          results.push(matchElement);
        }
      });

      // sometimes field is just a text, without any fireworks :(
      if (results.length === 1) {
        results = results.pop();
      }
      return results;

    } else {
      return {type:'text', value:value};
    }
  };

  // This is stupid brackets counting, I don't think it needs any explanation
  var parse = function(text) {
    var brackets = 0;

    for (var i=0, l=text.length; i<l; i++) {
      if (text.charAt(i) === '{') {
        brackets++;
      } else if (text.charAt(i) === '}') {
        brackets--;
      }

      if (brackets === 0 && i > 0) {
        return i-1;
      }
    }
  };
};
<|endoftext|>


<commit_before>/**
 * The useful library to simplify your work with Telegram Bot API
 *
 * @module telekit
 * @author Denis Maslennikov <mrdenniska@gmail.com> (nofach.com)
 * @license MIT
 */

/** Dependencies */
const FormData = require('form-data');
const FileType = require('file-type');
const stream = require('stream');
const debug = require('debug');
const got = require('got');

/** Debug */
debug.error = debug('teleapi:error');
debug.error.color = 1;

debug.http = debug('teleapi:api');
debug.http.color = 2;

debug.api = debug('teleapi:api');
debug.api.color = 3;

/**
 * Variables
 * @private
 */
const API_FILE = 'https://api.telegram.org/file/bot';
const API_URL = 'https://api.telegram.org/bot';

/**
 * Available API Methods
 * @private
 */
const API_DEFAULT = require('./api.json');

/**
 * Methods
 * @private
 */

/**
 * Checks whether an object is multipart/form-data
 * @private
 *
 * @param  {Object} obj - An object with form-data
 * @return {Boolean}
 */
function isFormData(obj) {
    return Object.keys(obj).some((key) => {
        if (obj[key] instanceof stream.Stream) return true;
        if (Buffer.isBuffer(obj[key])) return true;
        return false;
    });
}

/**
 * Normalizes an object to sending into body of the request
 * @private
 *
 * @param  {Object} obj - An object with data for sending
 * @return {Object|form-data}
 */
function normalize(obj) {
    const isMultipart = isFormData(obj);
    const content = { filename: '', value: '', mime: '' };
    const result = ((isMultipart) ? new FormData() : {});
    let file = null;

    Object.keys(obj).forEach((item) => {
        if (isMultipart) {
            if (obj[item].value) content.value = obj[item].value;
            else content.value = obj[item];

            content.filename = obj[item].filename || null;
            content.mime = obj[item].mime || null;

            if (content.value instanceof stream.Stream) {
                result.append(item, content.value, {
                    contentType: content.mime,
                    filename: content.filename,
                });

                return;
            }

            if (Buffer.isBuffer(content.value)) {
                file = FileType(content.value);
                result.append(item, content.value, {
                    contentType: content.mime || file.mime || 'application/octet-stream',
                    filename: content.filename || `data-${Date.now()}.${file.ext || ''}`,
                });

                return;
            }

            if (typeof content.value === 'object') {
                result.append(item, JSON.stringify(content.value), {
                    contentType: 'application/json',
                });

                return;
            }

            result.append(item, content.value);
        } else {
            if (typeof obj[item] === 'object') {
                result[item] = JSON.stringify(obj[item]);
                return;
            }

            result[item] = obj[item];
        }
    });

    return result;
}

/**
 * Custom Errors
 * @public
 */
class APIError extends Error {
    constructor(method, params, response) {
        super();

        this.name = 'APIError';
        this.method = method;
        this.params = params;

        this.message = response.description;
        this.timeout = response.retry_after || null;
        this.migrate = response.migrate_to_chat_id || null;
        this.code = response.error_code;
    }
}

/**
 * Implementation
 * @public
 */
class API {
    /**
     * Create an instance of the teleapi
     * @public
     *
     * @param {String} token - Token of the bot
     * @param {Object} custom - An object with Custom API
     */
    constructor(token = '', api = API_DEFAULT) {
        this.version = api.version;
        this.token = token;

        debug.api('version: %s', this.version);

        this.generator(api.methods);
    }

    /**
     * Send the request to Telegram Bot API
     * @private
     *
     * @param  {String} name - Name of the method
     * @param  {Object} params - Body of the request
     * @return {Promise}
     */
    method(name, params = {}) {
        const options = { json: true };
        const form = normalize(params);
        const url = `${API_URL}${this.token}/${name}`;

        if (form.getHeaders) options.headers = form.getHeaders();
        options.body = form;

        return new Promise((resolve, reject) => {
            debug.http('use %s with params: %O', name, params);
            got(url, options).then((res) => {
                debug.http('%s is it responded: %O', name, res.body.result);
                resolve(res.body.result);
            }).catch((error) => {
                let result = error;

                if (error.name === 'HTTPError') {
                    result = new APIError(name, params, error.response.body);
                    debug.error('%s(%s) %s', result.name, result.method, result.message);
                }

                reject(result);
            });
        });
    }

    /**
     * Generates a wrapped methods from an Array of String
     *
     * @param {Array} list - An Array of String with method names
     * @private
     */
    generator(list) {
        list.forEach((item) => {
            debug.api('%s is added', item);
            this[item] = params => this.method(item, params);
        });
    }

    /**
     * Get file from the Telegram Bot API
     * @public
     *
     * @param  {String} id - File ID
     * @return {Stream}
     */
    getFile(id) {
        return got.stream(`${API_FILE + this.token}/${id}`);
    }
}

/** Exports */
module.exports = Object.assign((token, custom) => {
    if (token) return new API(token, custom);
    return API;
}, {
    version: API_DEFAULT.version,
    methods: API_DEFAULT.methods,
});
<commit_msg>[src]: Refactoring. ✍<commit_after>/**
 * The useful library to simplify your work with Telegram Bot API
 *
 * @module telekit
 * @author Denis Maslennikov <mrdenniska@gmail.com> (nofach.com)
 * @license MIT
 */

/** Dependencies */
const FormData = require('form-data');
const FileType = require('file-type');
const stream = require('stream');
const debug = require('debug');
const got = require('got');

/** Debug */
debug.error = debug('teleapi:error');
debug.error.color = 1;

debug.http = debug('teleapi:api');
debug.http.color = 2;

debug.api = debug('teleapi:api');
debug.api.color = 3;

/**
 * Variables
 * @private
 */
const API_FILE = 'https://api.telegram.org/file/bot';
const API_URL = 'https://api.telegram.org/bot';

/**
 * Available API Methods
 * @private
 */
const API_DEFAULT = require('./api.json');

/**
 * Methods
 * @private
 */

/**
 * Checks whether an object is multipart/form-data
 * @private
 *
 * @param  {Object} obj - An object with form-data
 * @return {Boolean}
 */
function isFormData(obj) {
    return Object.keys(obj).some((key) => {
        if (obj[key] instanceof stream.Stream) return true;
        if (Buffer.isBuffer(obj[key])) return true;
        return false;
    });
}

/**
 * Normalizes an object to sending into body of the request
 * @private
 *
 * @param  {Object} obj - An object with data for sending
 * @return {Object|form-data}
 */
function normalize(obj) {
    const isMultipart = isFormData(obj);
    const content = { filename: '', value: '', mime: '' };
    const result = ((isMultipart) ? new FormData() : {});
    let file = null;

    Object.keys(obj).forEach((item) => {
        if (isMultipart) {
            if (obj[item].value) content.value = obj[item].value;
            else content.value = obj[item];

            content.filename = obj[item].filename || null;
            content.mime = obj[item].mime || null;

            if (content.value instanceof stream.Stream) {
                result.append(item, content.value, {
                    contentType: content.mime,
                    filename: content.filename,
                });

                return;
            }

            if (Buffer.isBuffer(content.value)) {
                file = FileType(content.value);
                result.append(item, content.value, {
                    contentType: content.mime || file.mime || 'application/octet-stream',
                    filename: content.filename || `data-${Date.now()}.${file.ext || ''}`,
                });

                return;
            }

            if (typeof content.value === 'object') {
                result.append(item, JSON.stringify(content.value), {
                    contentType: 'application/json',
                });

                return;
            }

            result.append(item, content.value);
        } else {
            if (typeof obj[item] === 'object') {
                result[item] = JSON.stringify(obj[item]);
                return;
            }

            result[item] = obj[item];
        }
    });

    return result;
}

/**
 * Custom Errors
 * @public
 */
class APIError extends Error {
    constructor(method, params, response) {
        super();

        this.name = 'APIError';
        this.method = method;
        this.params = params;

        this.message = response.description;
        this.timeout = response.retry_after || null;
        this.migrate = response.migrate_to_chat_id || null;
        this.code = response.error_code;
    }
}

/**
 * Implementation
 * @public
 */
class API {
    /**
     * Create an instance of the teleapi
     * @public
     *
     * @param {String} token - Token of the bot
     * @param {Object} custom - An object with Custom API
     */
    constructor(token = '', api = API_DEFAULT) {
        this.version = api.version;
        this.token = token;

        debug.api('version: %s', this.version);

        this.generator(api.methods);
    }

    /**
     * Send the request to Telegram Bot API
     * @private
     *
     * @param  {String} name - Name of the method
     * @param  {Object} params - Body of the request
     * @return {Promise}
     */
    method(name, params = {}) {
        const options = { json: true };
        const form = normalize(params);
        const url = `${API_URL}${this.token}/${name}`;

        if (form.getHeaders) {
            options.headers = form.getHeaders();
        }

        options.body = form;

        debug.http('use %s with params: %O', name, params);
        return got(url, options).then((response) => {
            debug.http('%s is it responded: %O', name, response.body.result);
            return response.body.result;
        }).catch((error) => {
            let buffer = error;

            // hook
            if (buffer.name === 'HTTPError' && buffer.response.body) {
                buffer = new APIError(name, params, buffer.response.body);
                debug.error('%s(%s) %s', buffer.name, buffer.method, buffer.message);
            }

            throw buffer;
        });
    }

    /**
     * Generates a wrapped methods from an Array of String
     *
     * @param {Array} list - An Array of String with method names
     * @private
     */
    generator(list) {
        list.forEach((item) => {
            debug.api('%s is added', item);
            this[item] = params => this.method(item, params);
        });
    }

    /**
     * Get file from the Telegram Bot API
     * @public
     *
     * @param  {String} id - File ID
     * @return {Stream}
     */
    getFile(id) {
        return got.stream(`${API_FILE + this.token}/${id}`);
    }
}

/** Exports */
module.exports = Object.assign((token, custom) => {
    if (token) return new API(token, custom);
    return API;
}, {
    version: API_DEFAULT.version,
    methods: API_DEFAULT.methods,
});
<|endoftext|>


<commit_before>import React, {PropTypes} from 'react';
import {Observable, helpers} from 'rx';
import assign from 'object-assign';
import invariant from 'invariant';

export default {create: Container, fromPromise: Observable.fromPromise, fromStore};

function Container(Component, options) {
	const {
		fragments = {},
		shouldContainerUpdate = () => true,
		initialVariables = {},
	} = options;

	const componentEnum = enumerate(Component);
	const isRootContainer = options.hasOwnProperty('initialVariables');

	return React.createClass({
		displayName: `${componentEnum.success.displayName || componentEnum.success.name}Container`,

		propTypes: {
			variables: PropTypes.object,
		},

		statics: {
			isRootContainer,
			getFragment(name, variables) {},
		},

		getInitialState() {
			return {
				status: 'pending',
				fragments: {},
				error: null,
			};
		},

		success(results) {
			this.setState({
				status: 'success',
				fragments: results.reduce((a, b) => assign(a, b), {}),
			});
		},

		failure(error) {
			this.setState({
				status: 'failure',
				error: {type: 'FETCH_FAILED', error},
			});
		},

		pending() {
			this.setState({
				status: 'pending',
				error: null,
			});

			this.subscription.dispose();
		},

		fetchFragment(name, variables) {
			const fragmentContainer = fragments[name](variables);
			const observable = fromEverything(fragmentContainer);

			return observable.map(data => ({[name]: data}));
		},

		fetch(newVariables) {
			const variables = assign({}, initialVariables, newVariables);

			const streams = Object.keys(fragments)
				.map(key => this.fetchFragment(key, variables));

			return Observable.combineLatest(streams)
				.subscribe(
					results => this.success(results),
					error => this.failure(error)
				);
		},

		refetch() {
			this.pending();
			this.subscription = this.fetch(this.props.variables);
		},

		componentWillMount() {
			this.subscription = this.fetch(this.props.variables);
		},

		componentWillUnmount() {
			this.subscription.dispose();
		},

		componentWillReceiveProps(nextProps) {
			if (shouldContainerUpdate.call(this, nextProps)) {
				this.pending();
				this.subscription = this.fetch(nextProps.variables);
			}
		},

		render() {
			const {fragments, error, status} = this.state;
			const onRetry = () => this.refetch();

			switch (status) {
			case 'success':
				return React.createElement(componentEnum.success, assign(fragments, this.props));
			case 'failure':
				return React.createElement(componentEnum.failure, assign({error, onRetry}, this.props));
			case 'pending':
				// falls through
			default:
				// TODO: pass onCancel
				return React.createElement(componentEnum.pending, this.props);
			}
		},
	});
}

function EmptyComponent() {
	return null;
}

function enumerate(target) {
	const isEnumerableComponent = typeof target === 'object';

	if (isEnumerableComponent) {
		invariant(isReactComponentEnum(target), 'Success, Failure and Pending should be React components');
		invariant(hasSuccessPoint(target), 'Success component should be specified');
	}

	return isEnumerableComponent ? target : {success: target, pending: EmptyComponent, failure: EmptyComponent};
}

function isReactComponentEnum(target) {
	return ['success', 'failure', 'pending']
		.filter(type => target.hasOwnProperty(type))
		.every(type => typeof target[type] === 'function');
}

function hasSuccessPoint(target) {
	return typeof target.success === 'function';
}

function fromEverything(object) {
	if (helpers.isPromise(object)) {
		return Observable.fromPromise(object);
	}

	// assume that fragmentContainer is Observable by default
	return object;
}

function fromStore(store) {
	return Observable.create(observer => {
		const unsubscribe = store.subscribe(() => observer.onNext(store.getState()));
		return {dispose: unsubscribe};
	}).startWith(store.getState());
}
<commit_msg>moved container name to the variable<commit_after>import React, {PropTypes} from 'react';
import {Observable, helpers} from 'rx';
import assign from 'object-assign';
import invariant from 'invariant';

export default {create: Container, fromPromise: Observable.fromPromise, fromStore};

function Container(Component, options) {
	const {
		fragments = {},
		shouldContainerUpdate = () => true,
		initialVariables = {},
	} = options;

	const componentEnum = enumerate(Component);
	const containerName = componentEnum.success.displayName || componentEnum.success.name;
	const isRootContainer = options.hasOwnProperty('initialVariables');

	return React.createClass({
		displayName: `${containerName}Container`,

		propTypes: {
			variables: PropTypes.object,
		},

		statics: {
			isRootContainer,
			getFragment(name, variables) {},
		},

		getInitialState() {
			return {
				status: 'pending',
				fragments: {},
				error: null,
			};
		},

		success(results) {
			this.setState({
				status: 'success',
				fragments: results.reduce((a, b) => assign(a, b), {}),
			});
		},

		failure(error) {
			this.setState({
				status: 'failure',
				error: {type: 'FETCH_FAILED', error},
			});
		},

		pending() {
			this.setState({
				status: 'pending',
				error: null,
			});

			this.subscription.dispose();
		},

		fetchFragment(name, variables) {
			const fragmentContainer = fragments[name](variables);
			const observable = fromEverything(fragmentContainer);

			return observable.map(data => ({[name]: data}));
		},

		fetch(newVariables) {
			const variables = assign({}, initialVariables, newVariables);

			const streams = Object.keys(fragments)
				.map(key => this.fetchFragment(key, variables));

			return Observable.combineLatest(streams)
				.subscribe(
					results => this.success(results),
					error => this.failure(error)
				);
		},

		refetch() {
			this.pending();
			this.subscription = this.fetch(this.props.variables);
		},

		componentWillMount() {
			this.subscription = this.fetch(this.props.variables);
		},

		componentWillUnmount() {
			this.subscription.dispose();
		},

		componentWillReceiveProps(nextProps) {
			if (shouldContainerUpdate.call(this, nextProps)) {
				this.pending();
				this.subscription = this.fetch(nextProps.variables);
			}
		},

		render() {
			const {fragments, error, status} = this.state;
			const onRetry = () => this.refetch();

			switch (status) {
			case 'success':
				return React.createElement(componentEnum.success, assign(fragments, this.props));
			case 'failure':
				return React.createElement(componentEnum.failure, assign({error, onRetry}, this.props));
			case 'pending':
				// falls through
			default:
				// TODO: pass onCancel
				return React.createElement(componentEnum.pending, this.props);
			}
		},
	});
}

function EmptyComponent() {
	return null;
}

function enumerate(target) {
	const isEnumerableComponent = typeof target === 'object';

	if (isEnumerableComponent) {
		invariant(isReactComponentEnum(target), 'Success, Failure and Pending should be React components');
		invariant(hasSuccessPoint(target), 'Success component should be specified');
	}

	return isEnumerableComponent ? target : {success: target, pending: EmptyComponent, failure: EmptyComponent};
}

function isReactComponentEnum(target) {
	return ['success', 'failure', 'pending']
		.filter(type => target.hasOwnProperty(type))
		.every(type => typeof target[type] === 'function');
}

function hasSuccessPoint(target) {
	return typeof target.success === 'function';
}

function fromEverything(object) {
	if (helpers.isPromise(object)) {
		return Observable.fromPromise(object);
	}

	// assume that fragmentContainer is Observable by default
	return object;
}

function fromStore(store) {
	return Observable.create(observer => {
		const unsubscribe = store.subscribe(() => observer.onNext(store.getState()));
		return {dispose: unsubscribe};
	}).startWith(store.getState());
}
<|endoftext|>


<commit_before>"use strict";

var chalk = require("chalk");
// convention used : label and nodes
var archy = require("archy");

var BUILTINS = [
  "publish",
  "install",
  "uninstall",
  "test",
  "stop",
  "start",
  "restart",
  "version"
];

function archify (scripts, alpha) {
  var names = Object.keys(scripts);
  if (alpha) {
    names = names.sort();
  }
  return {
    label: `${names.length} scripts`,
    nodes: names.map(n => scripts[n])
  }
}

function getLabel (script) {
  var name = script.isPre || script.isPost
    ? chalk.cyan(script.name)
    : chalk.bold(script.name)

  return name + chalk.dim(` —  ${script.cmd}`);
}

function isPreScript (name, scripts) {
  return isLifeCycleScript("pre", name, scripts);
}

function isPostScript (name, scripts) {
  return isLifeCycleScript("post", name, scripts);
}

function isLifeCycleScript (prefix, name, scripts) {
  var re = new RegExp("^" + prefix);
  var root = name.slice(prefix.length);
  return Boolean(name.match(re) && (scripts[root] || ~BUILTINS.indexOf(root)));
}

function getPreScript (name, scripts) {
  return scripts["pre" + name];
}

function getPostScript (name, scripts) {
  return scripts["post" + name];
}

function getNodesNames (name, scripts) {
  var cmd = scripts[name];
  var m = cmd.match(/(npm run (\w*))+/gi);
  if (!m) return null;

  return m.map(c => c.slice(8));
}

function getDetailedScripts (scripts) {
  return Object.keys(scripts).reduce((all, name) => {
    var s = {
      name: name,
      cmd: scripts[name],
      isPre: isPreScript(name, scripts),
      isPost: isPostScript(name, scripts),
      pre: getPreScript(name, scripts),
      post: getPostScript(name, scripts),
      nodesNames: getNodesNames(name, scripts)
    };

    s.label = getLabel(s);

    all[name] = s;
    return all;
  }, {});
}

function attachNodes (scripts) {
  return Object.keys(scripts).reduce((all, name) => {
    var s = scripts[name];
    s.nodes = s.nodesNames
      ? s.nodesNames.map(n => scripts[n])
      : []

    if (s.pre) s.nodes.unshift(scripts["pre" + name]);
    if (s.post) s.nodes.push(scripts["post" + name]);

    all[name] = s;
    return all;
  }, {});
}

function main (scripts, options) {
  if (!scripts) throw new Error("No package.json or no scripts key in this dir");

  var detailedScripts = getDetailedScripts(scripts);
  detailedScripts = attachNodes(detailedScripts);

  // sort?
  var alpha = options.a || options.alpha;
  return archy(archify(detailedScripts, alpha));
}

module.exports = { main }
<commit_msg>feat: add basic support for npm-run-all<commit_after>"use strict";

var chalk = require("chalk");
// convention used : label and nodes
var archy = require("archy");

var BUILTINS = [
  "publish",
  "install",
  "uninstall",
  "test",
  "stop",
  "start",
  "restart",
  "version"
];

// -s, --serial…
var RE_FLAGS = '(?:\\s+\-+\\w+)*';
// build, watch, build_client, build-client, build:*
var RE_NAME = '\\s+([a-z0-9_\\-]+)';
var RE_NAMES = '((?:\\s+[a-z0-9_:\\-\\*]+)+)';

// utils

var unique = array => [...new Set(array)];

var flatten = arrays => [].concat.apply([], arrays)

function archify (scripts, alpha) {
  var names = Object.keys(scripts);
  if (alpha) {
    names = names.sort();
  }
  return {
    label: `${names.length} scripts`,
    nodes: names.map(n => scripts[n])
  }
}

function getLabel (script) {
  var name = script.isPre || script.isPost
    ? chalk.cyan(script.name)
    : chalk.bold(script.name)

  return name + chalk.dim(` — ${script.cmd}`);
}

function isPreScript (name, scripts) {
  return isLifeCycleScript("pre", name, scripts);
}

function isPostScript (name, scripts) {
  return isLifeCycleScript("post", name, scripts);
}

function isLifeCycleScript (prefix, name, scripts) {
  var re = new RegExp("^" + prefix);
  var root = name.slice(prefix.length);
  return Boolean(name.match(re) && (scripts[root] || ~BUILTINS.indexOf(root)));
}

function getPreScript (name, scripts) {
  return scripts["pre" + name];
}

function getPostScript (name, scripts) {
  return scripts["post" + name];
}

function getNodesNames (name, scripts) {
  var cmd = scripts[name];

  var subScripts = [].concat(
    getRunScripts(cmd),
    getRunAllScripts(cmd)
  ).filter(x => x); // not null

  return unique(subScripts);
}

// handled natively
function getRunScripts (cmd) {
  var re = /(?:npm run\s+(\w+))+/gi;
  var re = new RegExp('(?:npm run' + RE_NAME + ')+', 'gi');
  var cmds = [];
  var m;
  // for each npm run group
  while ((m = re.exec(cmd)) !== null) {
    cmds.push(m[1]);
  }

  return unique(cmds);
}

// handled by npm-run-all module
function getRunAllScripts (cmd) {
  var re = RegExp('(?:npm-run-all' + RE_FLAGS + RE_NAMES + ')+', 'gi');
  var cmds = [];
  var m;
  // for each npm-run-all group
  while ((m = re.exec(cmd)) !== null) {
    // clean spaces
    cmds.push(m[1].trim().split(' ').filter(x => x));
  }

  return unique(flatten(cmds));
}

function getDetailedScripts (scripts) {
  return Object.keys(scripts).reduce((all, name) => {
    var s = {
      name: name,
      cmd: scripts[name],
      isPre: isPreScript(name, scripts),
      isPost: isPostScript(name, scripts),
      pre: getPreScript(name, scripts),
      post: getPostScript(name, scripts),
      nodesNames: getNodesNames(name, scripts)
    };

    s.label = getLabel(s);

    all[name] = s;
    return all;
  }, {});
}

// sub scripts
function attachNodes (scripts) {
  return Object.keys(scripts).reduce((all, name) => {
    var s = scripts[name];
    s.nodes = s.nodesNames.map(n => scripts[n]).filter(x => x);

    if (s.pre) s.nodes.unshift(scripts["pre" + name]);
    if (s.post) s.nodes.push(scripts["post" + name]);

    all[name] = s;
    return all;
  }, {});
}

function main (scripts, options) {
  if (!scripts) throw new Error("No package.json or no scripts key in this dir");

  var detailedScripts = getDetailedScripts(scripts);
  detailedScripts = attachNodes(detailedScripts);

  // sort?
  var alpha = options.a || options.alpha;
  return archy(archify(detailedScripts, alpha));
}

module.exports = {
  main,
  // test
  getRunScripts,
  getRunAllScripts,
  getNodesNames
}
<|endoftext|>


<commit_before>var test = require('tape');
module.exports = redtape;
function redtape(setup, teardown, asserts) {
  var noop = function (cb) { (typeof cb === 'function') && cb() };
  setup = setup || noop;
  teardown = teardown || noop;
  asserts = asserts || {};
  return function (name, cb) {
    test(name, function (t) {
      var args;
      var _end = t.end;
      var ended = false;
      t.end = function () {
        if (ended) return;
        ended = true;
        var _args = args;
        var _cb = function (err) {
            if (err) return t.error(err);
            _end.call(t);
        };
        // pass setup args if needed
        if (teardown.length > 1) {
          _args = args.concat(_cb);
        } else {
          _args = [_cb];
        }
        teardown.apply(null, _args);
      };
      Object.keys(asserts).forEach(function (key) {
        if (!(key in t)) {
          t[key] = asserts[key];
        }
      });
      setup(function (err) {
        if (err) return t.error(err);
        args = Array.prototype.slice.call(arguments, 1);
        cb.apply(null, [t].concat(args));
      });
    });
  }
}
<commit_msg>Options version<commit_after>var test = require('tape');
module.exports = redtape;
function redtape(setup, teardown, asserts) {
  var noop = function (cb) { (typeof cb === 'function') && cb() };
  var options = {};
  if (arguments.length === 1 && typeof arguments[0] === 'object') {
    options = setup;
    setup = options.setup || options.beforeEach || noop;
    teardown = options.teardown || options.afterEach || noop;
    asserts = options.asserts || {};
  } else {
    setup = setup || noop;
    teardown = teardown || noop;
    asserts = asserts || {};
  }
  return function (name, cb) {
    test(name, function (t) {
      var args;
      var _end = t.end;
      var ended = false;
      t.end = function () {
        if (ended) return;
        ended = true;
        var _args = args;
        var _cb = function (err) {
            if (err) return t.error(err);
            _end.call(t);
        };
        // pass setup args if needed
        if (teardown.length > 1) {
          _args = args.concat(_cb);
        } else {
          _args = [_cb];
        }
        teardown.apply(null, _args);
      };
      Object.keys(asserts).forEach(function (key) {
        if (!(key in t)) {
          t[key] = asserts[key];
        }
      });
      setup(function (err) {
        if (err) return t.error(err);
        args = Array.prototype.slice.call(arguments, 1);
        cb.apply(null, [t].concat(args));
      });
    });
  }
}
<|endoftext|>


<commit_before>/*
Name:         pastecapi
Description:  Lightweight module for Pastec image recognition API
Author:       Franklin van de Meent (https://frankl.in)
Source code:  https://github.com/fvdm/nodejs-pastecapi
Feedback:     https://github.com/fvdm/nodejs-pastecapi/issues
License:      Unlicense (Public Domain, see LICENSE file)
*/

var httpreq = require ('httpreq');
var fs = require ('fs');

var config = {};

/**
 * Process response error
 *
 * @callback callback
 * @param message {string} - error.message
 * @param err {Error, string} - error.error
 * @param res {object} - httpreq response details
 * @param callback {function} - `function (err) {}`
 * @returns {void}
 */

function processError (message, err, res, callback) {
  var error = new Error (message);

  error.statusCode = res && res.statusCode;
  error.error = err;
  return callback (error);
}

/**
 * Process HTTP response
 *
 * @callback callback
 * @param err {Error, null} - httpreq error
 * @param res {object} - httpreq response details
 * @param callback {function} - `function (err, data) {}`
 * @returns {void}
 */

function processResponse (err, res, callback) {
  var data = res && res.body || '';

  if (err) {
    return processError ('request failed', err, res, callback);
  }

  try {
    data = JSON.parse (data);
  } catch (e) {
    return processError ('request failed', e, res, callback);
  }

  if (data.type === 'AUTHENTIFICATION_ERROR') {
    return processError ('invalid authkey', data.type, res, callback);
  }

  return callback (null, data);
}

/**
 * Communicate with API
 *
 * @callback callback
 * @param {object} options
 * @param {string} options.method=GET - HTTP method
 * @param {string} options.path=/ - Request path, i.e. /index/searcher
 * @param {object} options.parameters - Request query parameters
 * @param {object} options.json - POST JSON data
 * @param {object} options.files - Upload files paths
 * @param {number} options.timeout=5000 - Override request timeout in ms
 * @param {function} callback - Callback function
 * @returns {void}
 */

function talk (options, callback) {
  options.url = config.endpoint + options.path;
  options.method = options.method || 'GET';
  options.timeout = options.timeout || config.timeout;
  options.headers = options.headers || {};
  options.headers ['User-Agent'] = 'pastecapi node/' + process.versions.node;

  if (config.authkey) {
    options.headers.AuthKey = config.authkey;
  }

  function doResponse (err, res) {
    processResponse (err, res, callback);
  }

  httpreq.doRequest (options, doResponse);
}

/**
 * Test API access
 *
 * @callback callback
 * @param {function} callback - Process result
 * @returns {void}
 */

function ping (callback) {
  var options = {
    method: 'POST',
    path: '/',
    json: {
      type: 'PING'
    }
  };

  talk (options, callback);
}

/**
 * Load index from file on server
 *
 * @param {string} indexPath - Path to .dat file on server
 * @param {function} callback - Process result
 * @returns {void}
 */

function loadIndex (indexPath, callback) {
  var options = {
    method: 'POST',
    path: '/index/io',
    json: {
      type: 'LOAD',
      index_path: indexPath
    }
  };

  talk (options, callback);
}

/**
 * Write index to file on server
 *
 * @callback callback
 * @param {string} indexPath - Path of .dat file on server
 * @param {function} callback - Process result
 * @returns {void}
 */

function writeIndex (indexPath, callback) {
  var options = {
    method: 'POST',
    path: '/index/io',
    json: {
      type: 'WRITE',
      index_path: indexPath
    }
  };

  talk (options, callback);
}

/**
 * Clear index on server
 *
 * @callback callback
 * @param {function} callback - Process result
 * @returns {void}
 */

function clearIndex (callback) {
  var options = {
    method: 'POST',
    path: '/index/io',
    json: {
      type: 'CLEAR'
    }
  };

  talk (options, callback);
}

/**
 * Match image against index
 *
 * @callback callback
 * @param {string|buffer} image - Buffer or local path to image
 * @param {function} callback - Process result
 * @returns {void}
 */

function searchIndex (image, callback) {
  var options = {
    method: 'POST',
    path: '/index/searcher',
    binary: true
  };

  // Binary pass through
  if (image instanceof Buffer) {
    options.body = image;
    options.headers = {
      'Content-Length': image.length,
      'Content-Type': 'image/jpeg'
    };

    return talk (options, callback);
  }

  // Read file to buffer
  fs.readFile (image, function (err, data) {
    if (err) {
      return callback (err);
    }

    options.body = data;
    options.headers = {
      'Content-Length': data.length,
      'Content-Type': 'image/jpeg'
    };

    return talk (options, callback);
  });
}

/**
 * Remove image signature from index
 *
 * @callback callback
 * @param {number} imageId - Index ID of image signature
 * @param {function} callback - Process result
 * @returns {void}
 */

function deleteImage (imageId, callback) {
  var options = {
    method: 'DELETE',
    path: '/index/images/' + imageId
  };

  talk (options, callback);
}

/**
 * Add image signature to index
 *
 * @callback callback
 * @param {string|buffer} image - Buffer or local path to image
 * @param {number} imageId - Index ID for image
 * @param {function} callback - Process result
 * @returns {void}
 */

function addImage (image, imageId, callback) {
  var options = {
    method: 'PUT',
    path: '/index/images/' + imageId,
    binary: true
  };

  // Binary pass through
  if (image instanceof Buffer) {
    options.body = image;
    options.headers = {
      'Content-Length': image.length,
      'Content-Type': 'image/jpeg'
    };

    return talk (options, callback);
  }

  // Read file to buffer
  fs.readFile (image, function (err, data) {
    if (err) {
      return callback (err);
    }

    options.body = data;
    options.headers = {
      'Content-Length': data.length,
      'Content-Type': 'image/jpeg'
    };

    return talk (options, callback);
  });
}

/**
 * Module setup
 *
 * @param {string} endpoint - REST API base URL
 * @param (string} authkey - API auth key (--auth-key flag)
 * @param {number} timeout - Request wait timeout in ms
 * @returns {object} - Module methods
 */

module.exports = function (endpoint, authkey, timeout) {
  if (typeof authkey === 'number') {
    timeout = authkey;
    authkey = null;
  }

  config.endpoint = endpoint || 'http://localhost:4121';
  config.timeout = timeout || 5000;
  config.authkey = authkey || null;

  return {
    ping,
    loadIndex,
    writeIndex,
    clearIndex,
    searchIndex,
    addImage,
    deleteImage
  };
};
<commit_msg>Feat(setup): Allow config object instead of arguments<commit_after>/*
Name:         pastecapi
Description:  Lightweight module for Pastec image recognition API
Author:       Franklin van de Meent (https://frankl.in)
Source code:  https://github.com/fvdm/nodejs-pastecapi
Feedback:     https://github.com/fvdm/nodejs-pastecapi/issues
License:      Unlicense (Public Domain, see LICENSE file)
*/

var httpreq = require ('httpreq');
var fs = require ('fs');

var config = {
  endpoint: 'http://localhost:4121',
  timeout: 5000
};

/**
 * Process response error
 *
 * @callback callback
 * @param message {string} - error.message
 * @param err {Error, string} - error.error
 * @param res {object} - httpreq response details
 * @param callback {function} - `function (err) {}`
 * @returns {void}
 */

function processError (message, err, res, callback) {
  var error = new Error (message);

  error.statusCode = res && res.statusCode;
  error.error = err;
  return callback (error);
}

/**
 * Process HTTP response
 *
 * @callback callback
 * @param err {Error, null} - httpreq error
 * @param res {object} - httpreq response details
 * @param callback {function} - `function (err, data) {}`
 * @returns {void}
 */

function processResponse (err, res, callback) {
  var data = res && res.body || '';

  if (err) {
    return processError ('request failed', err, res, callback);
  }

  try {
    data = JSON.parse (data);
  } catch (e) {
    return processError ('request failed', e, res, callback);
  }

  if (data.type === 'AUTHENTIFICATION_ERROR') {
    return processError ('invalid authkey', data.type, res, callback);
  }

  return callback (null, data);
}

/**
 * Communicate with API
 *
 * @callback callback
 * @param {object} options
 * @param {string} options.method=GET - HTTP method
 * @param {string} options.path=/ - Request path, i.e. /index/searcher
 * @param {object} options.parameters - Request query parameters
 * @param {object} options.json - POST JSON data
 * @param {object} options.files - Upload files paths
 * @param {number} options.timeout=5000 - Override request timeout in ms
 * @param {function} callback - Callback function
 * @returns {void}
 */

function talk (options, callback) {
  options.url = config.endpoint + options.path;
  options.method = options.method || 'GET';
  options.timeout = options.timeout || config.timeout;
  options.headers = options.headers || {};
  options.headers ['User-Agent'] = 'pastecapi node/' + process.versions.node;

  if (config.authkey) {
    options.headers.AuthKey = config.authkey;
  }

  function doResponse (err, res) {
    processResponse (err, res, callback);
  }

  httpreq.doRequest (options, doResponse);
}

/**
 * Test API access
 *
 * @callback callback
 * @param {function} callback - Process result
 * @returns {void}
 */

function ping (callback) {
  var options = {
    method: 'POST',
    path: '/',
    json: {
      type: 'PING'
    }
  };

  talk (options, callback);
}

/**
 * Load index from file on server
 *
 * @param {string} indexPath - Path to .dat file on server
 * @param {function} callback - Process result
 * @returns {void}
 */

function loadIndex (indexPath, callback) {
  var options = {
    method: 'POST',
    path: '/index/io',
    json: {
      type: 'LOAD',
      index_path: indexPath
    }
  };

  talk (options, callback);
}

/**
 * Write index to file on server
 *
 * @callback callback
 * @param {string} indexPath - Path of .dat file on server
 * @param {function} callback - Process result
 * @returns {void}
 */

function writeIndex (indexPath, callback) {
  var options = {
    method: 'POST',
    path: '/index/io',
    json: {
      type: 'WRITE',
      index_path: indexPath
    }
  };

  talk (options, callback);
}

/**
 * Clear index on server
 *
 * @callback callback
 * @param {function} callback - Process result
 * @returns {void}
 */

function clearIndex (callback) {
  var options = {
    method: 'POST',
    path: '/index/io',
    json: {
      type: 'CLEAR'
    }
  };

  talk (options, callback);
}

/**
 * Match image against index
 *
 * @callback callback
 * @param {string|buffer} image - Buffer or local path to image
 * @param {function} callback - Process result
 * @returns {void}
 */

function searchIndex (image, callback) {
  var options = {
    method: 'POST',
    path: '/index/searcher',
    binary: true
  };

  // Binary pass through
  if (image instanceof Buffer) {
    options.body = image;
    options.headers = {
      'Content-Length': image.length,
      'Content-Type': 'image/jpeg'
    };

    return talk (options, callback);
  }

  // Read file to buffer
  fs.readFile (image, function (err, data) {
    if (err) {
      return callback (err);
    }

    options.body = data;
    options.headers = {
      'Content-Length': data.length,
      'Content-Type': 'image/jpeg'
    };

    return talk (options, callback);
  });
}

/**
 * Remove image signature from index
 *
 * @callback callback
 * @param {number} imageId - Index ID of image signature
 * @param {function} callback - Process result
 * @returns {void}
 */

function deleteImage (imageId, callback) {
  var options = {
    method: 'DELETE',
    path: '/index/images/' + imageId
  };

  talk (options, callback);
}

/**
 * Add image signature to index
 *
 * @callback callback
 * @param {string|buffer} image - Buffer or local path to image
 * @param {number} imageId - Index ID for image
 * @param {function} callback - Process result
 * @returns {void}
 */

function addImage (image, imageId, callback) {
  var options = {
    method: 'PUT',
    path: '/index/images/' + imageId,
    binary: true
  };

  // Binary pass through
  if (image instanceof Buffer) {
    options.body = image;
    options.headers = {
      'Content-Length': image.length,
      'Content-Type': 'image/jpeg'
    };

    return talk (options, callback);
  }

  // Read file to buffer
  fs.readFile (image, function (err, data) {
    if (err) {
      return callback (err);
    }

    options.body = data;
    options.headers = {
      'Content-Length': data.length,
      'Content-Type': 'image/jpeg'
    };

    return talk (options, callback);
  });
}

/**
 * Module setup
 *
 * @param {string} endpoint - REST API base URL
 * @param (string} authkey - API auth key (--auth-key flag)
 * @param {number} timeout - Request wait timeout in ms
 * @returns {object} - Module methods
 */

module.exports = function (endpoint, authkey, timeout) {
  if (typeof endpoint === 'object') {
    config.endpoint = endpoint.endpoint || config.endpoint;
    config.timeout = endpoint.timeout || config.timeout;
    config.authkey = endpoint.authkey || null;
  } else {
    if (typeof authkey === 'number') {
      timeout = authkey;
      authkey = null;
    }

    config.endpoint = endpoint || config.endpoint;
    config.timeout = timeout || config.timeout;
    config.authkey = authkey || null;
  }

  return {
    ping,
    loadIndex,
    writeIndex,
    clearIndex,
    searchIndex,
    addImage,
    deleteImage
  };
};
<|endoftext|>


<commit_before>module.exports = MultiStream

var inherits = require('inherits')
var stream = require('stream')

inherits(MultiStream, stream.Readable)

function MultiStream (streams, opts) {
  if (!(this instanceof MultiStream)) return new MultiStream(streams, opts)
  stream.Readable.call(this, opts)

  this.destroyed = false

  this._drained = false
  this._forwarding = false
  this._current = null
  this._queue = streams

  this._next()
}

MultiStream.obj = function(streams) {
  return new MultiStream(streams, {objectMode:true, highWaterMark:16})
}

MultiStream.prototype._read = function () {
  this._drained = true
  this._forward()
}

MultiStream.prototype._forward = function() {
  if (this._forwarding || !this._drained) return
  this._forwarding = true

  var chunk
  while ((chunk = this._current.read()) !== null) {
    this._drained = this.push(chunk)
  }

  this._forwarding = false
}

MultiStream.prototype.destroy = function(err) {
  if (this.destroyed) return
  this.destroyed = true

  this._queue.forEach(function(stream) {
    if (stream.destroy) stream.destroy()
  })

  if (err) this.emit('error', err)
  this.emit('close')
}

MultiStream.prototype._next = function () {
  var self = this
  var stream = this._queue.shift()

  if (!stream) {
    this.push(null)
    return
  }

  this._current = stream

  stream.on('readable', onReadable)
  stream.on('end', onEnd)
  stream.on('error', onError)
  stream.on('close', onClose)

  function onReadable () {
    self._forward()
  }

  function onClose () {
    if (!stream._readableState.ended) {
      self.destroy()
    }
  }

  function onEnd () {
    stream.removeListener('readable', onReadable)
    stream.removeListener('end', onEnd)
    stream.removeListener('error', onError)
    stream.removeListener('close', onClose)
    self._next()
  }

  function onError (err) {
    self.destroy(err)
  }
}
<commit_msg>style<commit_after>module.exports = MultiStream

var inherits = require('inherits')
var stream = require('stream')

inherits(MultiStream, stream.Readable)

function MultiStream (streams, opts) {
  if (!(this instanceof MultiStream)) return new MultiStream(streams, opts)
  stream.Readable.call(this, opts)

  this.destroyed = false

  this._drained = false
  this._forwarding = false
  this._current = null
  this._queue = streams

  this._next()
}

MultiStream.obj = function (streams) {
  return new MultiStream(streams, { objectMode: true, highWaterMark: 16 })
}

MultiStream.prototype._read = function () {
  this._drained = true
  this._forward()
}

MultiStream.prototype._forward = function () {
  if (this._forwarding || !this._drained) return
  this._forwarding = true

  var chunk
  while ((chunk = this._current.read()) !== null) {
    this._drained = this.push(chunk)
  }

  this._forwarding = false
}

MultiStream.prototype.destroy = function (err) {
  if (this.destroyed) return
  this.destroyed = true

  this._queue.forEach(function (stream) {
    if (stream.destroy) stream.destroy()
  })

  if (err) this.emit('error', err)
  this.emit('close')
}

MultiStream.prototype._next = function () {
  var self = this
  var stream = this._queue.shift()

  if (!stream) {
    this.push(null)
    return
  }

  this._current = stream

  stream.on('readable', onReadable)
  stream.on('end', onEnd)
  stream.on('error', onError)
  stream.on('close', onClose)

  function onReadable () {
    self._forward()
  }

  function onClose () {
    if (!stream._readableState.ended) {
      self.destroy()
    }
  }

  function onEnd () {
    stream.removeListener('readable', onReadable)
    stream.removeListener('end', onEnd)
    stream.removeListener('error', onError)
    stream.removeListener('close', onClose)
    self._next()
  }

  function onError (err) {
    self.destroy(err)
  }
}
<|endoftext|>


<commit_before>var STATE_CHANGES = {
        MOUNT: 'mount',
        UPDATE: 'update'
    };

module.exports = {
    TICK: 20,
    UPDATE_RENDER_LOG_POSITION_TIMEOUT_MS: 500,
    MAX_LOG_LENGTH: 20,

    renderLogContainer: null,
    renderLogDetail: null,
    renderLogRenderCount: null,
    _updateRenderLogPositionTimeout: null,

    componentDidMount: function(){
        // Reset the logs
        this._resetRenderLog();

        // Record initial mount
        this.addToRenderLog(this.state, 'Initial Render');

        // Build the monitor node
        this._buildRenderLogNode();

        // Highlight the initial mount
        this._highlightChange(STATE_CHANGES.MOUNT);

        // Set the watch to update log position
        this._updateRenderLogPositionTimeout = setInterval(this._updateRenderLogPosition, this.UPDATE_RENDER_LOG_POSITION_TIMEOUT_MS);
    },

    componentDidUpdate: function(prevProps, prevState){
        // Get the changes in state and props
        this._getReasonForReRender(prevProps, prevState);

        // Update the render log
        this._updateRenderLogNode();

        // Highlight the update
        this._highlightChange(STATE_CHANGES.UPDATE);
    },

    componentWillUnmount: function (){
        // Remove the monitor node
        this._removeRenderLogNode();

        // Clear the update position timeout
        clearInterval(this._updateRenderLogPositionTimeout);
    },

    /*
     * Reset the logs
     * @return void
     */
    _resetRenderLog: function(){
        this.state.renderLog = [];
        this.state.renderCount = 1;
    },

    /*
     * Build the renderLog node, add it to the body and assign it's position based on the monitored component
     * @return void
     */
    _buildRenderLogNode: function(){
        var self = this,
            renderLogContainer = document.createElement('div'),
            renderLogRenderCountNode = document.createElement("div"),
            renderLogDetailNode = document.createElement("div");

        renderLogContainer.className = 'renderLog';
        renderLogContainer.addEventListener('click', function(){
            self.renderLogContainer.classList.toggle('show');
        });

        renderLogRenderCountNode.className = 'renderLogCounter';
        renderLogRenderCountNode.innerText = 1;

        renderLogDetailNode.className = 'renderLogDetail';
        renderLogDetailNode.innerText = '';

        renderLogContainer.appendChild(renderLogRenderCountNode);
        renderLogContainer.appendChild(renderLogDetailNode);

        this.renderLogContainer = renderLogContainer;
        this.renderLogDetail = renderLogDetailNode;
        this.renderLogRenderCount = renderLogRenderCountNode;

        // Append to the body
        document.getElementsByTagName('body')[0].appendChild(renderLogContainer);

        // Set initial position
        this._updateRenderLogPosition();
    },

    /*
     * Update the render log position based on its parent position
     * @return void
     */
    _updateRenderLogPosition: function(){
        var parentNode = this.getDOMNode(),
            parentNodeRect = parentNode && parentNode.getBoundingClientRect();

        if (this.renderLogContainer) {
            this.renderLogContainer.style.top = (window.pageYOffset + parentNodeRect.top) + 'px';
            this.renderLogContainer.style.left = parentNodeRect.left + 'px';
        }
    },

    /*
     * Update the render log count and details
     * @return void
     */
    _updateRenderLogNode: function() {
        var logFragment = document.createDocumentFragment();

        if (this.renderLogRenderCount) {
            this.renderLogRenderCount.innerText = (this.state.renderCount - 1 );
        }

        if (this.renderLogDetail) {
            this.renderLogDetail.innerHTML = '';
            for(var i = 0; i < this.state.renderLog.length; i++){
                var item = document.createElement('div');
                item.innerText = this.state.renderLog[i];
                logFragment.appendChild(item);
            }

            this.renderLogDetail.appendChild(logFragment);
        }
        //this.state.renderCount++;
    },

    /*
     * Remove the render log node from the body
     * @return void
     */
    _removeRenderLogNode: function() {
        if (this.renderLogContainer) {
            document.getElementsByTagName('body')[0].removeChild(this.renderLogContainer);
        }
    },

    /*
     * Add a detail message to the render log and update the count
     * @param object nextState - The most current state of the component
     * @param String message
     * @return void
     */
    addToRenderLog: function(state, message){
        state.renderLog.unshift(state.renderCount + ') ' + message);
        state.renderCount++;

        // Trim the log
        state.renderLog.splice(this.MAX_LOG_LENGTH, 1);
    },

    /*
     * Get the changes made to props or state.  In the event this component has its own shouldComponentUpdate, don't do
     * anything
     * @param object prevProps
     * @param object prevState
     * @return boolean
     */
    _getReasonForReRender: function(prevProps, prevState){
        var nextState = this.state,
            nextProps = this.props,
            key;

        if (this.shouldComponentUpdate) return false;

        for (key in nextState){
            if (nextState.hasOwnProperty(key) && nextState[key] !== prevState[key]){
                if (typeof nextState[key] === 'object')
                    return this.addToRenderLog(this.state, 'this.state['+key+'] changed');
                else
                    return this.addToRenderLog(this.state, 'this.state['+key+'] changed from ' + prevState[key] + ' => ' + nextState[key]);
            }
        }

        for (key in nextProps) {
            if (nextProps.hasOwnProperty(key) && nextProps[key] !== prevProps[key]) {
                if (typeof nextProps[key] === 'object')
                    return this.addToRenderLog(this.state, 'this.props['+key+'] changed');
                else
                    return this.addToRenderLog(this.state, 'this.props['+key+'] changed from ' + prevProps[key] + ' => ' + nextProps[key]);
            }
        }

        return this.addToRenderLog(this.state, 'force update called in ' + this.constructor.displayName);
    },

    /*
     * Highlight any change by adding an animation style to the component DOM node
     * @param String change - The type of change being made to the node
     * @return void
     */
    _highlightChange: function(change) {
        var parentNode = this.getDOMNode();

        if (parentNode) {
            parentNode.classList.remove('highlight', 'highlight-update','highlight-mount');

            setTimeout(function() {
                parentNode.classList.add('highlight', 'highlight-' + change);
            }, this.TICK);
        }
    }
};
<commit_msg>Added module support for bower and removed TICKs<commit_after>;(function (root, factory) {
  "use strict";
  /*if (typeof define === "function" && define.amd) {
    // AMD
    define([], function() {
      return (root.ReactRenderVisualizer = factory());
    });
  } else*/ if (typeof exports === "object") {
    // CommonJS
    module.exports = factory();
  } else {
    // Global variables
    root.ReactRenderVisualizer = factory();
  }
}(this, function() {
  "use strict";

var ReactRenderVisualizer = {
        UPDATE_RENDER_LOG_POSITION_TIMEOUT_MS: 500,
        MAX_LOG_LENGTH: 20,
        STATE_CHANGES: {
            MOUNT: 'mount',
            UPDATE: 'update'
        },

        renderLogContainer: null,
        renderLogDetail: null,
        renderLogRenderCount: null,
        _updateRenderLogPositionTimeout: null,

        componentDidMount: function(){
            // Reset the logs
            this._resetRenderLog();7

            // Record initial mount
            this.addToRenderLog(this.state, 'Initial Render');

            // Build the monitor node
            this._buildRenderLogNode();

            // Highlight the initial mount
            this._highlightChange(this.STATE_CHANGES.MOUNT);

            // Set the watch to update log position
            this._updateRenderLogPositionTimeout = setInterval(this._updateRenderLogPosition, this.UPDATE_RENDER_LOG_POSITION_TIMEOUT_MS);
        },

        componentDidUpdate: function(prevProps, prevState){
            // Get the changes in state and props
            this._getReasonForReRender(prevProps, prevState);

            // Update the render log
            this._updateRenderLogNode();

            // Highlight the update
            this._highlightChange(this.STATE_CHANGES.UPDATE);
        },

        componentWillUnmount: function (){
            // Remove the monitor node
            this._removeRenderLogNode();

            // Clear the update position timeout
            clearInterval(this._updateRenderLogPositionTimeout);
        },

        /*
         * Reset the logs
         * @return void
         */
        _resetRenderLog: function(){
            this.state.renderLog = [];
            this.state.renderCount = 1;
        },

        /*
         * Build the renderLog node, add it to the body and assign it's position based on the monitored component
         * @return void
         */
        _buildRenderLogNode: function(){
            var self = this,
                renderLogContainer = document.createElement('div'),
                renderLogRenderCountNode = document.createElement("div"),
                renderLogDetailNode = document.createElement("div");

            renderLogContainer.className = 'renderLog';
            renderLogContainer.addEventListener('click', function(){
                self.renderLogContainer.classList.toggle('show');
            });

            renderLogRenderCountNode.className = 'renderLogCounter';
            renderLogRenderCountNode.innerText = 1;

            renderLogDetailNode.className = 'renderLogDetail';
            renderLogDetailNode.innerText = '';

            renderLogContainer.appendChild(renderLogRenderCountNode);
            renderLogContainer.appendChild(renderLogDetailNode);

            this.renderLogContainer = renderLogContainer;
            this.renderLogDetail = renderLogDetailNode;
            this.renderLogRenderCount = renderLogRenderCountNode;

            // Append to the body
            document.getElementsByTagName('body')[0].appendChild(renderLogContainer);

            // Set initial position
            this._updateRenderLogPosition();
        },

        /*
         * Update the render log position based on its parent position
         * @return void
         */
        _updateRenderLogPosition: function(){
            var parentNode = this.getDOMNode(),
                parentNodeRect = parentNode && parentNode.getBoundingClientRect();

            if (this.renderLogContainer) {
                this.renderLogContainer.style.top = (window.pageYOffset + parentNodeRect.top) + 'px';
                this.renderLogContainer.style.left = parentNodeRect.left + 'px';
            }
        },

        /*
         * Update the render log count and details
         * @return void
         */
        _updateRenderLogNode: function() {
            var logFragment = document.createDocumentFragment();

            if (this.renderLogRenderCount) {
                this.renderLogRenderCount.innerText = (this.state.renderCount - 1 );
            }

            if (this.renderLogDetail) {
                this.renderLogDetail.innerHTML = '';
                for(var i = 0; i < this.state.renderLog.length; i++){
                    var item = document.createElement('div');
                    item.innerText = this.state.renderLog[i];
                    logFragment.appendChild(item);
                }

                this.renderLogDetail.appendChild(logFragment);
            }
            //this.state.renderCount++;
        },

        /*
         * Remove the render log node from the body
         * @return void
         */
        _removeRenderLogNode: function() {
            if (this.renderLogContainer) {
                document.getElementsByTagName('body')[0].removeChild(this.renderLogContainer);
            }
        },

        /*
         * Add a detail message to the render log and update the count
         * @param object nextState - The most current state of the component
         * @param String message
         * @return void
         */
        addToRenderLog: function(state, message){
            state.renderLog.unshift(state.renderCount + ') ' + message);
            state.renderCount++;

            // Trim the log
            state.renderLog.splice(this.MAX_LOG_LENGTH, 1);
        },

        /*
         * Get the changes made to props or state.  In the event this component has its own shouldComponentUpdate, don't do
         * anything
         * @param object prevProps
         * @param object prevState
         * @return boolean
         */
        _getReasonForReRender: function(prevProps, prevState){
            var nextState = this.state,
                nextProps = this.props,
                key;

            // This component has custom logic, so we don't know why it did or did not update
            if (this.shouldComponentUpdate) this.addToRenderLog(this.state, 'custom shouldComponentUpdate() handled update');

            for (key in nextState){
                if (nextState.hasOwnProperty(key) && nextState[key] !== prevState[key]){
                    if (typeof nextState[key] === 'object')
                        return this.addToRenderLog(this.state, 'this.state['+key+'] changed');
                    else
                        return this.addToRenderLog(this.state, 'this.state['+key+'] changed from ' + prevState[key] + ' => ' + nextState[key]);
                }
            }

            for (key in nextProps) {
                if (nextProps.hasOwnProperty(key) && nextProps[key] !== prevProps[key]) {
                    if (typeof nextProps[key] === 'object')
                        return this.addToRenderLog(this.state, 'this.props['+key+'] changed');
                    else
                        return this.addToRenderLog(this.state, 'this.props['+key+'] changed from ' + prevProps[key] + ' => ' + nextProps[key]);
                }
            }

            return this.addToRenderLog(this.state, 'unknown reason for update, possibly from forceUpdate()');
        },

        /*
         * Highlight any change by adding an animation style to the component DOM node
         * @param String change - The type of change being made to the node
         * @return void
         */
        _highlightChange: function(change) {
            var parentNode = this.getDOMNode();

            if (parentNode) {
                parentNode.classList.remove('highlight-update','highlight-mount');

                window.requestAnimationFrame(function(){
                    parentNode.classList.add('highlight', 'highlight-' + change);

                    window.requestAnimationFrame(function(){
                        parentNode.classList.remove('highlight-update','highlight-mount');
                    });
                });
            }
        }
    };
    return ReactRenderVisualizer;
}));<|endoftext|>


<commit_before>/*
  An Orangejuice plugin is a function that decorates an
  Orangejuice instance with functionality.

  The typical use-case looks like:

      var OJ = require('orangejuice');
      var myPlugin = require('orangejuice-my-plugin');

      myPlugin(OJ);

  The following is a "kitchen sink" implementation of the
  Orangejuice API, to showcase the various ways a plugin
  can interact with Orangejuice.

  By convention the first argument to your plugin
  function should be the Orangejuice instance.

  Feel free to add any number of additional arguments,
  for instance to pass in a plugin-specific config object.
*/

module.exports = function(oj, myPluginConfig) {

  /*
    ORANGEJUICE EVENTS
    ##################

    Orangejuice allows you to register event listeners
    to get notified of the various stages of execution.

    The event API is:

    Register an event listener:
    oj.bind('eventName', callbackFunction);

    Register an event listener that will be fired only once:
    oj.one('eventName', callbackFunction);

    Remove an event listener:
    oj.unbind('eventName', callbackFunction);

  */

  oj.one('beforeBuild', function() {
    console.log('Happens only once, before the first build');
  });

  oj.bind('afterBuild', function() {
    console.log('Happens after every build');
  });

  oj.bind('beforeBuild', function() {
    console.log('Happens before every build');
  });

  /*

  */

};<commit_msg>Added an example of accessing the internal connect server<commit_after>/*
  An Orangejuice plugin is a function that decorates an
  Orangejuice instance with functionality.

  The typical use-case looks like:

      var OJ = require('orangejuice');
      var myPlugin = require('orangejuice-my-plugin');

      myPlugin(OJ);

  The following is a "kitchen sink" implementation of the
  Orangejuice API, to showcase the various ways a plugin
  can interact with Orangejuice.

  By convention the first argument to your plugin
  function should be the Orangejuice instance.

  Feel free to add any number of additional arguments,
  for instance to pass in a plugin-specific config object.
*/

module.exports = function(oj, myPluginConfig) {

  /*
    ORANGEJUICE EVENTS
    ##################

    Orangejuice allows you to register event listeners
    to get notified of the various stages of execution.

    The event API is:

    Register an event listener:
    oj.bind('eventName', callbackFunction);

    Register an event listener that will be fired only once:
    oj.one('eventName', callbackFunction);

    Remove an event listener:
    oj.unbind('eventName', callbackFunction);

  */

  oj.one('beforeBuild', function() {
    console.log('Happens only once, before the first build');
  });

  oj.bind('afterBuild', function() {
    console.log('Happens after every build');
  });

  oj.bind('beforeBuild', function() {
    console.log('Happens before every build');
  });

  /*
    If OJ is in server mode you can access the
    internal connect server instance:
  */

  if(oj.server) {
    /*
      Example: Add a proxy middleware to the connect server

      oj.server.use('/api', proxy(url.parse('http://some.server.com/api')));
    */
  }

};<|endoftext|>


<commit_before>import Bot from './lib/Bot';
import request from 'request';
import Q from 'q';
import { parseString, Parser } from 'xml2js'
import token from './token';

let bot = new Bot({token: });

let parser = new Parser({
    normalizeTags: true
});

var frontenders = ['@buhaev', '@BorisHorenko', '@glibin', '@scribblex', '@isnifer'];

bot.on('message', function (message) {
    var self = this;
    console.log(message);

    if (message.text && message.text.toLowerCase() === '@pgbot village') {
        request.get({url: 'http://www.the-village.ru/feeds/posts.atom?city=1&flow=new-place'}, function (err, res, body) {
            parser.parseString(body, function (err, result) {
                // console.dir(result.feed.entry[0].title);
                self.sendMessage({
                    chat_id: message.chat.id,
                    text: result.feed.entry[0].title + '\n' +result.feed.entry[0].id[0],
                    function () {
                       console.log('Сообщение отправлено!');
                    }
                });
            });
        });
    }

    if (message.text && message.text.toLowerCase() === '@pgbot привет') {
        this.sendMessage({
            chat_id: message.chat.id,
            text: 'Привет ' + message.from.first_name + ' ' + message.from.last_name},
            function () {
               console.log('Сообщение отправлено!');
            }
        );
    }

    if (message.text && message.text.toLowerCase().startsWith('/randomreview') ) {
        this.sendMessage({
            chat_id: message.chat.id,
            text: 'Попроси, например, ' + frontenders[Math.floor(Math.random() * 4) + 1]},
            function () {
               console.log('Сообщение отправлено!');
            }
        );
    }

    /*if (message.text) {
        this.sendMessage({
            chat_id: message.chat.id,
            text: 'УБЛЮДОК МАТЬ ТВОЮ А НУ ИДИ СЮДА ГОВНО СОБАЧЬЕ РЕШИЛ КО МНЕ ЛЕЗТЬ? ТЫ ЗАСРАНЕЦ ВОНЮЧИЙ МАТЬ ТВОЮ А? НУ ИДИ СЮДА ПОПРОБУЙ МЕНЯ ТРАХНУТЬ Я ТЕБЯ САМ ТРАХНУ УБЛЮДОК ОНАНИСТ ЧЁРТОВ БУДЬ ТЫ ПРОКЛЯТ ИДИ ИДИОТ ТРАХАТЬ ТЕБЯ И ВСЮ ТВОЮ СЕМЬЮ ГОВНО СОБАЧЬЕ ЖЛОБ ВОНЮЧИЙ ДЕРЬМО СУКА ПАДЛА ИДИ СЮДА МЕРЗАВЕЦ НЕГОДЯЙ ГАД ИДИ СЮДА ТЫ ГОВНО ЖОПА'},
            function () {
               console.log('Сообщение отправлено!');
            }
        );
    }*/
});

bot.start();
<commit_msg>Token fix<commit_after>import Bot from './lib/Bot';
import request from 'request';
import Q from 'q';
import { parseString, Parser } from 'xml2js'
import token from './token';

let bot = new Bot({token: token});

let parser = new Parser({
    normalizeTags: true
});

var frontenders = ['@buhaev', '@BorisHorenko', '@glibin', '@scribblex', '@isnifer'];

bot.on('message', function (message) {
    var self = this;
    console.log(message);

    if (message.text && message.text.toLowerCase() === '@pgbot village') {
        request.get({url: 'http://www.the-village.ru/feeds/posts.atom?city=1&flow=new-place'}, function (err, res, body) {
            parser.parseString(body, function (err, result) {
                // console.dir(result.feed.entry[0].title);
                self.sendMessage({
                    chat_id: message.chat.id,
                    text: result.feed.entry[0].title + '\n' +result.feed.entry[0].id[0],
                    function () {
                       console.log('Сообщение отправлено!');
                    }
                });
            });
        });
    }

    if (message.text && message.text.toLowerCase() === '@pgbot привет') {
        this.sendMessage({
            chat_id: message.chat.id,
            text: 'Привет ' + message.from.first_name + ' ' + message.from.last_name},
            function () {
               console.log('Сообщение отправлено!');
            }
        );
    }

    if (message.text && message.text.toLowerCase().startsWith('/randomreview') ) {
        this.sendMessage({
            chat_id: message.chat.id,
            text: 'Попроси, например, ' + frontenders[Math.floor(Math.random() * 4) + 1]},
            function () {
               console.log('Сообщение отправлено!');
            }
        );
    }

    /*if (message.text) {
        this.sendMessage({
            chat_id: message.chat.id,
            text: 'УБЛЮДОК МАТЬ ТВОЮ А НУ ИДИ СЮДА ГОВНО СОБАЧЬЕ РЕШИЛ КО МНЕ ЛЕЗТЬ? ТЫ ЗАСРАНЕЦ ВОНЮЧИЙ МАТЬ ТВОЮ А? НУ ИДИ СЮДА ПОПРОБУЙ МЕНЯ ТРАХНУТЬ Я ТЕБЯ САМ ТРАХНУ УБЛЮДОК ОНАНИСТ ЧЁРТОВ БУДЬ ТЫ ПРОКЛЯТ ИДИ ИДИОТ ТРАХАТЬ ТЕБЯ И ВСЮ ТВОЮ СЕМЬЮ ГОВНО СОБАЧЬЕ ЖЛОБ ВОНЮЧИЙ ДЕРЬМО СУКА ПАДЛА ИДИ СЮДА МЕРЗАВЕЦ НЕГОДЯЙ ГАД ИДИ СЮДА ТЫ ГОВНО ЖОПА'},
            function () {
               console.log('Сообщение отправлено!');
            }
        );
    }*/
});

bot.start();
<|endoftext|>