<commit_before>/*
List.js 1.1.1
By Jonny Strömberg (www.jonnystromberg.com, www.listjs.com)
*/
(function( window, undefined ) {
"use strict";

var document = window.document,
  getByClass = require('./src/utils/get-by-class'),
  extend = require('./src/utils/extend'),
  indexOf = require('./src/utils/index-of'),
  events = require('./src/utils/events'),
  toString = require('./src/utils/to-string'),
  naturalSort = require('./src/utils/natural-sort'),
  classes = require('./src/utils/classes'),
  getAttribute = require('./src/utils/get-attribute'),
  toArray = require('./src/utils/to-array');

var List = function(id, options, values) {

  var self = this,
    init,
    Item = require('./src/item')(self),
    addAsync = require('./src/add-async')(self);

  init = {
    start: function() {
      self.listClass      = "list";
      self.searchClass    = "search";
      self.sortClass      = "sort";
      self.page           = 10000;
      self.i              = 1;
      self.items          = [];
      self.visibleItems   = [];
      self.matchingItems  = [];
      self.searched       = false;
      self.filtered       = false;
      self.searchColumns  = undefined;
      self.handlers       = { 'updated': [] };
      self.plugins        = {};
      self.valueNames     = [];
      self.utils          = {
        getByClass: getByClass,
        extend: extend,
        indexOf: indexOf,
        events: events,
        toString: toString,
        naturalSort: naturalSort,
        classes: classes,
        getAttribute: getAttribute,
        toArray: toArray
      };

      self.utils.extend(self, options);

      self.listContainer = (typeof(id) === 'string') ? document.getElementById(id) : id;
      if (!self.listContainer) { return; }
      self.list       = getByClass(self.listContainer, self.listClass, true);

      self.parse      = require('./src/parse')(self);
      self.templater  = require('./src/templater')(self);
      self.search     = require('./src/search')(self);
      self.filter     = require('./src/filter')(self);
      self.sort       = require('./src/sort')(self);

      this.handlers();
      this.items();
      self.update();
      this.plugins();
    },
    handlers: function() {
      for (var handler in self.handlers) {
        if (self[handler]) {
          self.on(handler, self[handler]);
        }
      }
    },
    items: function() {
      self.parse(self.list);
      if (values !== undefined) {
        self.add(values);
      }
    },
    plugins: function() {
      for (var i = 0; i < self.plugins.length; i++) {
        var plugin = self.plugins[i];
        self[plugin.name] = plugin;
        plugin.init(self, List);
      }
    }
  };

  /*
  * Re-parse the List, use if html have changed
  */
  this.reIndex = function() {
    self.items          = [];
    self.visibleItems   = [];
    self.matchingItems  = [];
    self.searched       = false;
    self.filtered       = false;
    self.parse(self.list);
  };

  this.toJSON = function() {
    var json = [];
    for (var i = 0, il = self.items.length; i < il; i++) {
      json.push(self.items[i].values());
    }
    return json;
  };

  /*
  * Add object to list
  */
  this.add = function(values, callback) {
    if (values.length === 0) {
      return;
    }
    if (callback) {
      addAsync(values, callback);
      return;
    }
    var added = [],
      notCreate = false;
    if (values[0] === undefined){
      values = [values];
    }
    for (var i = 0, il = values.length; i < il; i++) {
      var item = null;
      notCreate = (self.items.length > self.page) ? true : false;
      item = new Item(values[i], undefined, notCreate);
      self.items.push(item);
      added.push(item);
    }
    self.update();
    return added;
  };

	this.show = function(i, page) {
		this.i = i;
		this.page = page;
		self.update();
    return self;
	};

  /* Removes object from list.
  * Loops through the list and removes objects where
  * property "valuename" === value
  */
  this.remove = function(valueName, value, options) {
    var found = 0;
    for (var i = 0, il = self.items.length; i < il; i++) {
      if (self.items[i].values()[valueName] == value) {
        self.templater.remove(self.items[i], options);
        self.items.splice(i,1);
        il--;
        i--;
        found++;
      }
    }
    self.update();
    return found;
  };

  /* Gets the objects in the list which
  * property "valueName" === value
  */
  this.get = function(valueName, value) {
    var matchedItems = [];
    for (var i = 0, il = self.items.length; i < il; i++) {
      var item = self.items[i];
      if (item.values()[valueName] == value) {
        matchedItems.push(item);
      }
    }
    return matchedItems;
  };

  /*
  * Get size of the list
  */
  this.size = function() {
    return self.items.length;
  };

  /*
  * Removes all items from the list
  */
  this.clear = function() {
    self.templater.clear();
    self.items = [];
    return self;
  };

  this.on = function(event, callback) {
    self.handlers[event].push(callback);
    return self;
  };

  this.off = function(event, callback) {
    var e = self.handlers[event];
    var index = indexOf(e, callback);
    if (index > -1) {
      e.splice(index, 1);
    }
    return self;
  };

  this.trigger = function(event) {
    var i = self.handlers[event].length;
    while(i--) {
      self.handlers[event][i](self);
    }
    return self;
  };

  this.reset = {
    filter: function() {
      var is = self.items,
        il = is.length;
      while (il--) {
        is[il].filtered = false;
      }
      return self;
    },
    search: function() {
      var is = self.items,
        il = is.length;
      while (il--) {
        is[il].found = false;
      }
      return self;
    }
  };

  this.update = function() {
    var is = self.items,
			il = is.length;

    self.visibleItems = [];
    self.matchingItems = [];
    self.templater.clear();
    for (var i = 0; i < il; i++) {
      if (is[i].matching() && ((self.matchingItems.length+1) >= self.i && self.visibleItems.length < self.page)) {
        is[i].show();
        self.visibleItems.push(is[i]);
        self.matchingItems.push(is[i]);
      } else if (is[i].matching()) {
        self.matchingItems.push(is[i]);
        is[i].hide();
      } else {
        is[i].hide();
      }
    }
    self.trigger('updated');
    return self;
  };

  init.start();
};

// AMD support
if (typeof define === 'function' && define.amd) {
  define(function () { return List; });
}
module.exports = List;
window.List = List;

})(window);
<commit_msg>Update version in index.js<commit_after>/*
List.js 1.2
By Jonny Strömberg (www.jonnystromberg.com, www.listjs.com)
*/
(function( window, undefined ) {
"use strict";

var document = window.document,
  getByClass = require('./src/utils/get-by-class'),
  extend = require('./src/utils/extend'),
  indexOf = require('./src/utils/index-of'),
  events = require('./src/utils/events'),
  toString = require('./src/utils/to-string'),
  naturalSort = require('./src/utils/natural-sort'),
  classes = require('./src/utils/classes'),
  getAttribute = require('./src/utils/get-attribute'),
  toArray = require('./src/utils/to-array');

var List = function(id, options, values) {

  var self = this,
    init,
    Item = require('./src/item')(self),
    addAsync = require('./src/add-async')(self);

  init = {
    start: function() {
      self.listClass      = "list";
      self.searchClass    = "search";
      self.sortClass      = "sort";
      self.page           = 10000;
      self.i              = 1;
      self.items          = [];
      self.visibleItems   = [];
      self.matchingItems  = [];
      self.searched       = false;
      self.filtered       = false;
      self.searchColumns  = undefined;
      self.handlers       = { 'updated': [] };
      self.plugins        = {};
      self.valueNames     = [];
      self.utils          = {
        getByClass: getByClass,
        extend: extend,
        indexOf: indexOf,
        events: events,
        toString: toString,
        naturalSort: naturalSort,
        classes: classes,
        getAttribute: getAttribute,
        toArray: toArray
      };

      self.utils.extend(self, options);

      self.listContainer = (typeof(id) === 'string') ? document.getElementById(id) : id;
      if (!self.listContainer) { return; }
      self.list       = getByClass(self.listContainer, self.listClass, true);

      self.parse      = require('./src/parse')(self);
      self.templater  = require('./src/templater')(self);
      self.search     = require('./src/search')(self);
      self.filter     = require('./src/filter')(self);
      self.sort       = require('./src/sort')(self);

      this.handlers();
      this.items();
      self.update();
      this.plugins();
    },
    handlers: function() {
      for (var handler in self.handlers) {
        if (self[handler]) {
          self.on(handler, self[handler]);
        }
      }
    },
    items: function() {
      self.parse(self.list);
      if (values !== undefined) {
        self.add(values);
      }
    },
    plugins: function() {
      for (var i = 0; i < self.plugins.length; i++) {
        var plugin = self.plugins[i];
        self[plugin.name] = plugin;
        plugin.init(self, List);
      }
    }
  };

  /*
  * Re-parse the List, use if html have changed
  */
  this.reIndex = function() {
    self.items          = [];
    self.visibleItems   = [];
    self.matchingItems  = [];
    self.searched       = false;
    self.filtered       = false;
    self.parse(self.list);
  };

  this.toJSON = function() {
    var json = [];
    for (var i = 0, il = self.items.length; i < il; i++) {
      json.push(self.items[i].values());
    }
    return json;
  };

  /*
  * Add object to list
  */
  this.add = function(values, callback) {
    if (values.length === 0) {
      return;
    }
    if (callback) {
      addAsync(values, callback);
      return;
    }
    var added = [],
      notCreate = false;
    if (values[0] === undefined){
      values = [values];
    }
    for (var i = 0, il = values.length; i < il; i++) {
      var item = null;
      notCreate = (self.items.length > self.page) ? true : false;
      item = new Item(values[i], undefined, notCreate);
      self.items.push(item);
      added.push(item);
    }
    self.update();
    return added;
  };

	this.show = function(i, page) {
		this.i = i;
		this.page = page;
		self.update();
    return self;
	};

  /* Removes object from list.
  * Loops through the list and removes objects where
  * property "valuename" === value
  */
  this.remove = function(valueName, value, options) {
    var found = 0;
    for (var i = 0, il = self.items.length; i < il; i++) {
      if (self.items[i].values()[valueName] == value) {
        self.templater.remove(self.items[i], options);
        self.items.splice(i,1);
        il--;
        i--;
        found++;
      }
    }
    self.update();
    return found;
  };

  /* Gets the objects in the list which
  * property "valueName" === value
  */
  this.get = function(valueName, value) {
    var matchedItems = [];
    for (var i = 0, il = self.items.length; i < il; i++) {
      var item = self.items[i];
      if (item.values()[valueName] == value) {
        matchedItems.push(item);
      }
    }
    return matchedItems;
  };

  /*
  * Get size of the list
  */
  this.size = function() {
    return self.items.length;
  };

  /*
  * Removes all items from the list
  */
  this.clear = function() {
    self.templater.clear();
    self.items = [];
    return self;
  };

  this.on = function(event, callback) {
    self.handlers[event].push(callback);
    return self;
  };

  this.off = function(event, callback) {
    var e = self.handlers[event];
    var index = indexOf(e, callback);
    if (index > -1) {
      e.splice(index, 1);
    }
    return self;
  };

  this.trigger = function(event) {
    var i = self.handlers[event].length;
    while(i--) {
      self.handlers[event][i](self);
    }
    return self;
  };

  this.reset = {
    filter: function() {
      var is = self.items,
        il = is.length;
      while (il--) {
        is[il].filtered = false;
      }
      return self;
    },
    search: function() {
      var is = self.items,
        il = is.length;
      while (il--) {
        is[il].found = false;
      }
      return self;
    }
  };

  this.update = function() {
    var is = self.items,
			il = is.length;

    self.visibleItems = [];
    self.matchingItems = [];
    self.templater.clear();
    for (var i = 0; i < il; i++) {
      if (is[i].matching() && ((self.matchingItems.length+1) >= self.i && self.visibleItems.length < self.page)) {
        is[i].show();
        self.visibleItems.push(is[i]);
        self.matchingItems.push(is[i]);
      } else if (is[i].matching()) {
        self.matchingItems.push(is[i]);
        is[i].hide();
      } else {
        is[i].hide();
      }
    }
    self.trigger('updated');
    return self;
  };

  init.start();
};

// AMD support
if (typeof define === 'function' && define.amd) {
  define(function () { return List; });
}
module.exports = List;
window.List = List;

})(window);
<|endoftext|>


<commit_before>'use strict';
var xmlChars = require('xml-char-classes');

function getRange(re) {
	return re.toString().slice(2).slice(0, -2);
}

// http://www.w3.org/TR/1999/REC-xml-names-19990114/#NT-NCName
module.exports = new RegExp('^[' + getRange(xmlChars.letter) + '_][' + getRange(xmlChars.letter) + getRange(xmlChars.digit) + '\\.\\-_' + getRange(xmlChars.combiningChar) + getRange(xmlChars.extender) + ']*$');
<commit_msg>simplify extraction logic<commit_after>'use strict';
var xmlChars = require('xml-char-classes');

function getRange(re) {
	return re.source.slice(1, -1);
}

// http://www.w3.org/TR/1999/REC-xml-names-19990114/#NT-NCName
module.exports = new RegExp('^[' + getRange(xmlChars.letter) + '_][' + getRange(xmlChars.letter) + getRange(xmlChars.digit) + '\\.\\-_' + getRange(xmlChars.combiningChar) + getRange(xmlChars.extender) + ']*$');
<|endoftext|>


<commit_before>'use strict';

var juice = require('juice'),
    fs = require('fs'),
    _ = require('lodash'),
    path = require('path');

// Load Closure Library
require('./vendor/closure-library/closure/goog/bootstrap/nodejs');

goog.require('goog.date.DateTime');
goog.require('goog.i18n.DateTimeFormat');
goog.require('goog.i18n.DateTimeSymbols_es');
goog.require('goog.i18n.DateTimeSymbols_en');
goog.require('goog.i18n.DateTimeSymbols_fr');

var input = [];
process.stdin.setEncoding('utf8');
process.stdin.on('data', function (chunk) {
    input.push(chunk);
});

process.stdin.on('end', function () {
  input = JSON.parse(input);

  if (input.datetimes && !input.lang) {
    throw new Error('lang is required if you are using datetimes');
  }

  if (input.datetimes) {
    switch (input.lang) {
      case 'es':
        goog.i18n.DateTimeSymbols = goog.i18n.DateTimeSymbols_es;
        goog.i18n.DateTimePatterns = goog.i18n.DateTimePatterns_es;
        break;

      case 'en':
        goog.i18n.DateTimeSymbols = goog.i18n.DateTimeSymbols_en;
        goog.i18n.DateTimePatterns = goog.i18n.DateTimePatterns_en;
        break;

      case 'fr':
        goog.i18n.DateTimeSymbols = goog.i18n.DateTimeSymbols_fr;
        goog.i18n.DateTimePatterns = goog.i18n.DateTimePatterns_fr;
        break;

      default:
        throw new Error('unrecognized lang: ' + input.lang);
    }
  }

  _.each(input.datetimes, function (datetime) {
    datetime.name = datetime.name.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
    datetime.name = datetime.name.toUpperCase();
    var variable = new RegExp('\\[\\[\\$' + datetime.name + '\\]\\]', 'g');

    var formatter = new goog.i18n.DateTimeFormat(datetime.format);
    var date = goog.date.fromIsoString(datetime.value);
    var output = formatter.format(date);

    input.contents = input.contents.replace(variable, output);
  });

  var options = {
    webResources: {
      relativeTo: path.resolve(process.cwd(), input.cwd)+'/',
    },
  };
  juice.juiceResources(input.contents, options, function(err, html) {
    if (err) {
      throw err;
    }

    console.log(html);
  });
});
<commit_msg>Don't inline images in emails (we don't want it, also it's a DNS error).<commit_after>'use strict';

var juice = require('juice'),
    fs = require('fs'),
    _ = require('lodash'),
    path = require('path');

// Load Closure Library
require('./vendor/closure-library/closure/goog/bootstrap/nodejs');

goog.require('goog.date.DateTime');
goog.require('goog.i18n.DateTimeFormat');
goog.require('goog.i18n.DateTimeSymbols_es');
goog.require('goog.i18n.DateTimeSymbols_en');
goog.require('goog.i18n.DateTimeSymbols_fr');

var input = [];
process.stdin.setEncoding('utf8');
process.stdin.on('data', function (chunk) {
    input.push(chunk);
});

process.stdin.on('end', function () {
  input = JSON.parse(input);

  if (input.datetimes && !input.lang) {
    throw new Error('lang is required if you are using datetimes');
  }

  if (input.datetimes) {
    switch (input.lang) {
      case 'es':
        goog.i18n.DateTimeSymbols = goog.i18n.DateTimeSymbols_es;
        goog.i18n.DateTimePatterns = goog.i18n.DateTimePatterns_es;
        break;

      case 'en':
        goog.i18n.DateTimeSymbols = goog.i18n.DateTimeSymbols_en;
        goog.i18n.DateTimePatterns = goog.i18n.DateTimePatterns_en;
        break;

      case 'fr':
        goog.i18n.DateTimeSymbols = goog.i18n.DateTimeSymbols_fr;
        goog.i18n.DateTimePatterns = goog.i18n.DateTimePatterns_fr;
        break;

      default:
        throw new Error('unrecognized lang: ' + input.lang);
    }
  }

  _.each(input.datetimes, function (datetime) {
    datetime.name = datetime.name.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
    datetime.name = datetime.name.toUpperCase();
    var variable = new RegExp('\\[\\[\\$' + datetime.name + '\\]\\]', 'g');

    var formatter = new goog.i18n.DateTimeFormat(datetime.format);
    var date = goog.date.fromIsoString(datetime.value);
    var output = formatter.format(date);

    input.contents = input.contents.replace(variable, output);
  });

  var options = {
    webResources: {
      relativeTo: path.resolve(process.cwd(), input.cwd)+'/',

      // Don't request and inline images
      images: false,
    },
  };
  juice.juiceResources(input.contents, options, function(err, html) {
    if (err) {
      throw err;
    }

    console.log(html);
  });
});
<|endoftext|>


<commit_before>
/**
 * Expose 'grout'
 */

module.exports = grout;

/**
 * x constructor.
 * @api public
 */

function grout(tag, attrs, nodes) {
  var dom = document.createElement(tag);
  return function(data) {
    if(attrs instanceof Array) {
      children(dom, attrs);
    } else if(typeof attrs === 'object') {
      for(var key in attrs) {
        var attr = attrs[key];
        if(typeof attr === 'function') {
          if(key.substring(0,2) === 'on') {
            dom[key] = attr;
            break;
          } else {
            attr = attr.call(data);
          }
        }
        dom.setAttribute(key, attr);
      }
      if(nodes) children(dom, nodes);
    } else {
      text(dom, attrs);
    }
    return dom;
  };
}

/**
 * Create and append text node.
 *
 * @param  {Element} dom
 * @param  {String} str
 * @api private
 */

function text(dom, str) {
  dom.appendChild(document.createTextNode(str));
}

/**
 * Set node children elements.
 *
 * @param  {Element} dom
 * @param  {Array} nodes
 * @api private
 */

function children(dom, nodes) {
  if(typeof nodes === 'string') {
    dom.appendChild(document.createTextNode(nodes));
  } else {
    for(var i = 0, l = nodes.length; i < l; i++) {
      var node = nodes[i];
      if(typeof node === 'string') {
        var text = document.createTextNode(node);
        dom.appendChild(text);
      } else {
        dom.appendChild(node());
      }
    }
  }
}
<commit_msg>first refactorin - pretty bad<commit_after>
/**
 * Expose 'grout'
 */

module.exports = function grout(tag, attrs, nodes) {
  var dom = document.createElement(tag);
  var array = attrs instanceof Array;
  var object = typeof attrs === 'object';
  return function(data) {
    if(array) {
      children(dom, attrs);
    } else if(object) {
      attributes(dom, attrs, data);
      if(nodes) children(dom, nodes);
    } else {
      text(dom, attrs);
    }
    return dom;
  };
};

/**
 * Set attributes.
 *
 * @param  {Element} dom
 * @param  {Object} obj
 * @param  {Object} data
 * @api private
 */

function attributes(dom, obj, data) {
  for(var key in obj) {
    var attr = obj[key];
    if(typeof attr === 'function') {
      if(key.substring(0,2) === 'on') {
        dom[key] = attr;
        break;
      }
      attr = attr.call(data);
    }
    dom.setAttribute(key, attr);
  }
}

/**
 * Create and append text node.
 *
 * @param  {Element} dom
 * @param  {String} str
 * @api private
 */

function text(dom, str) {
  dom.appendChild(document.createTextNode(str));
}

/**
 * Set node children elements.
 *
 * @param  {Element} dom
 * @param  {Array} nodes
 * @api private
 */

function children(dom, nodes) {
  for(var i = 0, l = nodes.length; i < l; i++) {
    var node = nodes[i];
    if(typeof node === 'string') text(dom, node);
    else dom.appendChild(node());
  }
}
<|endoftext|>


<commit_before>var ogs = require('open-graph-scraper');
var express = require('express');
var ElasticSearch = require('elasticsearch');
var moment = require("moment-timezone");
var camoUrl = require('camo-url')({
	host : process.env.CAMO_HOST,
	key : process.env.CAMO_KEY
});
var URL = require('url');
var app = express();
var es = new ElasticSearch.Client({
	host : process.env.ES_URL,
	apiVersion : process.env.ES_VERSION
});

var esIndex = process.env.ES_INDEX;
var esType = process.env.ES_TYPE;

var INFO = "INFO";
var WARN = "WARN";
var ERR = "ERROR";

var BLOCKED_EXTENSIONS = ['pdf', 'gif', 'jpg', 'jpeg', 'png', 'svg'];

var CACHABLE_NETWORK_ERRORS = [
	'HPE_INVALID_CONSTANT', // May trigger if eg chipsoft Sharepoint send a content-length of 0 but secretly appends data
];
var NETWORK_ERRORS = [].concat(CACHABLE_NETWORK_ERRORS);
var CACHABLE_PAGE_ERRORS = ['Page Not Found'];
var CACHABLE_ERRORS = CACHABLE_NETWORK_ERRORS.concat(CACHABLE_PAGE_ERRORS);

var cacheInDays = parseInt(process.env.CACHE_IN_DAYS, 10) || 28;

function stringToUnderscore(input) {
	return input.replace(/([A-Z])/g, function ($1) {
		return "_" + $1.toLowerCase();
	});
}

function log(level, message) {
	console.log(JSON.stringify({time : moment(new Date()).format(), severity : level, message : message}));
}

function cacheExpired(date) {
	return moment(date).add(cacheInDays, 'days').isBefore(moment(new Date()));
}

function defaultOutput(url) {
	return Object.assign({}, {
		_url : url,
		_scrapedAt : parseInt(moment(new Date()).format('x'), 10),
		_cacheResponse : false,
		data : {}
	});
}

function postProcess(url, data) {
	var result = defaultOutput(url);

	// Format images for their special cases
	['ogImage', 'twitterImage'].forEach(function (key) {
		if (data[key]) {
			if (!data[key].url) {
				delete data[key];
			} else if (data[key].url) {
				var imageUrl = resolveRelative(data[key].url, url);
				if (process.env.CAMO_KEY && process.env.CAMO_HOST) {
					imageUrl = camoUrl(imageUrl);
				}
				var image = Object.assign({}, {value : imageUrl});
				Object.keys(data[key]).filter(function (e) {
					return e !== 'url';
				}).forEach(function (innerKey) {
					image[innerKey] = [{value : data[key][innerKey]}];
				});
				data[key] = image;
			}
		}
	});

	// Now map this to useful structures
	Object.keys(data).forEach(function (originalKey) {
		if (data[originalKey] === null || typeof data[originalKey] === 'undefined') {
			return;
		}

		var key;
		if (originalKey.startsWith('og')) {
			key = stringToUnderscore(originalKey.substring(2)).substring(1);
		}
		else if (originalKey.startsWith('twitter')) {
			key = stringToUnderscore(originalKey);
		} else {
			return;
		}

		if (data[originalKey].value) {
			result.data[key] = [data[originalKey]]
		} else {
			result.data[key] = [{value : data[originalKey]}]
		}
	});

	if (!result.data.url) {
		result.data.url = [{value : url}];
	}

	return result;
}

function resolveRelative(path, base) {
	// Somebody forgot to properly set a protocol on an otherwise absolute url
	if (path.indexOf("www.") === 0) {
		return 'http://' + path;
	}

	// Absolute URL
	if (path.match(/^[a-z]*:\/\//)) {
		return path;
	}
	// Protocol relative URL
	if (path.indexOf("//") === 0) {
		return base.replace(/\/\/.*/, path)
	}
	// Upper directory
	if (path.indexOf("../") === 0) {
		return resolveRelative(path.slice(3), base.replace(/\/[^\/]*$/, ''));
	}
	// Relative to the root
	if (path.indexOf('/') === 0) {
		if (!base.endsWith('/')) {
			base += '/';
		}
		var match = base.match(/(\w*:\/\/)?[^\/]*\//) || [base];
		return match[0] + path.slice(1);
	}
	//relative to the current directory
	return base.replace(/\/[^\/]*$/, "") + '/' + path.replace(/^\.\//, '');
}

if (process.env.ES_URL) {
	log(INFO, "Connected to Elasticsearch " + process.env.ES_VERSION + " on " + process.env.ES_URL + " using index '" + esIndex + "' with type '" + esType + "'. Using a cache of " + cacheInDays + " days.");
}

function cacheEntryIsValid(error, response, url) {
	if (!process.env.ES_URL) {
		// No ES cache entry is set
		log(WARN, "No ES cache specified, so skipping it");
		return false;
	}
	if (error) {
		if (error.status === 404) {
			log(INFO, "Getting new value for '" + url + "' since never seen that before");
		} else {
			log(WARN, "Got an error [" + error.status + "] while fetching URL '" + url + "' from ES cache");
		}
		return false;
	}
	if (!response._source || !response._source._scrapedAt) {
		log(WARN, 'Formatting error in cache, refetching ' + url);
		return false;
	}
	if (cacheExpired(response._source._scrapedAt)) {
		// cache is just expired
		log(INFO, "Getting new value for '" + url + "' since the cache expired");
		return false;
	}
	return true;
}

function workWorkWork(req, res) {
	var urlToFetch = req.query.url;
	var pathname = URL.parse(urlToFetch).pathname;
	var blockedResource = BLOCKED_EXTENSIONS.filter(function (extension) {
			return pathname.endsWith(extension);
		}).length > 0;
	if (blockedResource) {
		// Return standard format for misbehaving clients
		var blockedError = defaultOutput(urlToFetch);
		blockedError.err = 'This resource is blocked from fetching opengraph data';
		res.status(403).json(blockedError);
		return;
	}

	var encodedUrl = encodeURI(urlToFetch);
	es.get({index : esIndex, type : esType, id : encodedUrl}, function (err, response) {
		if (cacheEntryIsValid(err, response, urlToFetch)) {
			// If there is an error, we do not have the opengraph data so we return a 404
			var statusCode = !response._source.err ? 200 : 404;
			res.status(statusCode).json(response._source);
		} else {
			var options = {
				url : encodeURI(urlToFetch),
				timeout : 10000
			};
			ogs(options, function (err, ogData) {
				var resultData;
				if (err || !ogData.success) {
					// Return the data to the client
					resultData = defaultOutput(urlToFetch);
					resultData.err = ogData.err;

					var status = ogData.errorDetails && NETWORK_ERRORS.indexOf(ogData.errorDetails.code) !== -1 ?
						406 : // If the network request is borked
						404; // If the page was not found

					res.status(status).json(resultData);

					if (CACHABLE_ERRORS.indexOf(ogData.err) === -1) {
						// If this is a more permanent failure, we cache it
						log(ERR, 'Error while fetching OG data for ' + urlToFetch + ': ' + JSON.stringify(ogData));
						return;
					}
				} else {
					// All went well, postprocess and send to client
					resultData = postProcess(urlToFetch, ogData.data);
					res.json(resultData);
				}

				if (process.env.ES_URL) {
					resultData._cacheResponse = true;
					es.index({index : esIndex, type : esType, id : encodedUrl, body : resultData}, function (err) {
						if (err) {
							log(WARN, 'Could not save value to cache due to error: ' + err);
						}
					});
				}
			});
		}
	});
}

function ditchDitchDitch(req, res) {
	var urlToDelete = req.query.url;

	var encodedUrl = encodeURI(urlToDelete);
	if (!process.env.ES_URL) {
		// Technically not, but the effect is the same for the caller
		res.status(200).json({message: 'The url has been deleted from the cache', url: urlToDelete});
		return;
	}
	es.delete({index : esIndex, type : esType, id : encodedUrl}, function (err, response) {
		if (err && err.statusCode !== 404) {
			// If there is an error, we do not have the opengraph data so we return a 404
			log(ERR, 'An error occured while deleting data from the cache: ' + err);
			res.status(500).json({message: 'The url could not be deleted due to an internal error', url: urlToDelete});
		} else {
			res.status(200).json({message: 'The url has been deleted from the cache', url: urlToDelete});
		}
	});
}

app.get('/opengraph', workWorkWork);
app.delete('/opengraph', ditchDitchDitch);
app.get('/_health', function (req, res) {
	res.end('Jolly good here');
});
app.listen(7070, function () {
	log(INFO, 'Server is listening');
});

<commit_msg>Remove dangling comma<commit_after>var ogs = require('open-graph-scraper');
var express = require('express');
var ElasticSearch = require('elasticsearch');
var moment = require("moment-timezone");
var camoUrl = require('camo-url')({
	host : process.env.CAMO_HOST,
	key : process.env.CAMO_KEY
});
var URL = require('url');
var app = express();
var es = new ElasticSearch.Client({
	host : process.env.ES_URL,
	apiVersion : process.env.ES_VERSION
});

var esIndex = process.env.ES_INDEX;
var esType = process.env.ES_TYPE;

var INFO = "INFO";
var WARN = "WARN";
var ERR = "ERROR";

var BLOCKED_EXTENSIONS = ['pdf', 'gif', 'jpg', 'jpeg', 'png', 'svg'];

var CACHABLE_NETWORK_ERRORS = [
	'HPE_INVALID_CONSTANT' // May trigger if eg chipsoft Sharepoint send a content-length of 0 but secretly appends data
];
var NETWORK_ERRORS = [].concat(CACHABLE_NETWORK_ERRORS);
var CACHABLE_PAGE_ERRORS = ['Page Not Found'];
var CACHABLE_ERRORS = CACHABLE_NETWORK_ERRORS.concat(CACHABLE_PAGE_ERRORS);

var cacheInDays = parseInt(process.env.CACHE_IN_DAYS, 10) || 28;

function stringToUnderscore(input) {
	return input.replace(/([A-Z])/g, function ($1) {
		return "_" + $1.toLowerCase();
	});
}

function log(level, message) {
	console.log(JSON.stringify({time : moment(new Date()).format(), severity : level, message : message}));
}

function cacheExpired(date) {
	return moment(date).add(cacheInDays, 'days').isBefore(moment(new Date()));
}

function defaultOutput(url) {
	return Object.assign({}, {
		_url : url,
		_scrapedAt : parseInt(moment(new Date()).format('x'), 10),
		_cacheResponse : false,
		data : {}
	});
}

function postProcess(url, data) {
	var result = defaultOutput(url);

	// Format images for their special cases
	['ogImage', 'twitterImage'].forEach(function (key) {
		if (data[key]) {
			if (!data[key].url) {
				delete data[key];
			} else if (data[key].url) {
				var imageUrl = resolveRelative(data[key].url, url);
				if (process.env.CAMO_KEY && process.env.CAMO_HOST) {
					imageUrl = camoUrl(imageUrl);
				}
				var image = Object.assign({}, {value : imageUrl});
				Object.keys(data[key]).filter(function (e) {
					return e !== 'url';
				}).forEach(function (innerKey) {
					image[innerKey] = [{value : data[key][innerKey]}];
				});
				data[key] = image;
			}
		}
	});

	// Now map this to useful structures
	Object.keys(data).forEach(function (originalKey) {
		if (data[originalKey] === null || typeof data[originalKey] === 'undefined') {
			return;
		}

		var key;
		if (originalKey.startsWith('og')) {
			key = stringToUnderscore(originalKey.substring(2)).substring(1);
		}
		else if (originalKey.startsWith('twitter')) {
			key = stringToUnderscore(originalKey);
		} else {
			return;
		}

		if (data[originalKey].value) {
			result.data[key] = [data[originalKey]]
		} else {
			result.data[key] = [{value : data[originalKey]}]
		}
	});

	if (!result.data.url) {
		result.data.url = [{value : url}];
	}

	return result;
}

function resolveRelative(path, base) {
	// Somebody forgot to properly set a protocol on an otherwise absolute url
	if (path.indexOf("www.") === 0) {
		return 'http://' + path;
	}

	// Absolute URL
	if (path.match(/^[a-z]*:\/\//)) {
		return path;
	}
	// Protocol relative URL
	if (path.indexOf("//") === 0) {
		return base.replace(/\/\/.*/, path)
	}
	// Upper directory
	if (path.indexOf("../") === 0) {
		return resolveRelative(path.slice(3), base.replace(/\/[^\/]*$/, ''));
	}
	// Relative to the root
	if (path.indexOf('/') === 0) {
		if (!base.endsWith('/')) {
			base += '/';
		}
		var match = base.match(/(\w*:\/\/)?[^\/]*\//) || [base];
		return match[0] + path.slice(1);
	}
	//relative to the current directory
	return base.replace(/\/[^\/]*$/, "") + '/' + path.replace(/^\.\//, '');
}

if (process.env.ES_URL) {
	log(INFO, "Connected to Elasticsearch " + process.env.ES_VERSION + " on " + process.env.ES_URL + " using index '" + esIndex + "' with type '" + esType + "'. Using a cache of " + cacheInDays + " days.");
}

function cacheEntryIsValid(error, response, url) {
	if (!process.env.ES_URL) {
		// No ES cache entry is set
		log(WARN, "No ES cache specified, so skipping it");
		return false;
	}
	if (error) {
		if (error.status === 404) {
			log(INFO, "Getting new value for '" + url + "' since never seen that before");
		} else {
			log(WARN, "Got an error [" + error.status + "] while fetching URL '" + url + "' from ES cache");
		}
		return false;
	}
	if (!response._source || !response._source._scrapedAt) {
		log(WARN, 'Formatting error in cache, refetching ' + url);
		return false;
	}
	if (cacheExpired(response._source._scrapedAt)) {
		// cache is just expired
		log(INFO, "Getting new value for '" + url + "' since the cache expired");
		return false;
	}
	return true;
}

function workWorkWork(req, res) {
	var urlToFetch = req.query.url;
	var pathname = URL.parse(urlToFetch).pathname;
	var blockedResource = BLOCKED_EXTENSIONS.filter(function (extension) {
			return pathname.endsWith(extension);
		}).length > 0;
	if (blockedResource) {
		// Return standard format for misbehaving clients
		var blockedError = defaultOutput(urlToFetch);
		blockedError.err = 'This resource is blocked from fetching opengraph data';
		res.status(403).json(blockedError);
		return;
	}

	var encodedUrl = encodeURI(urlToFetch);
	es.get({index : esIndex, type : esType, id : encodedUrl}, function (err, response) {
		if (cacheEntryIsValid(err, response, urlToFetch)) {
			// If there is an error, we do not have the opengraph data so we return a 404
			var statusCode = !response._source.err ? 200 : 404;
			res.status(statusCode).json(response._source);
		} else {
			var options = {
				url : encodeURI(urlToFetch),
				timeout : 10000
			};
			ogs(options, function (err, ogData) {
				var resultData;
				if (err || !ogData.success) {
					// Return the data to the client
					resultData = defaultOutput(urlToFetch);
					resultData.err = ogData.err;

					var status = ogData.errorDetails && NETWORK_ERRORS.indexOf(ogData.errorDetails.code) !== -1 ?
						406 : // If the network request is borked
						404; // If the page was not found

					res.status(status).json(resultData);

					if (CACHABLE_ERRORS.indexOf(ogData.err) === -1) {
						// If this is a more permanent failure, we cache it
						log(ERR, 'Error while fetching OG data for ' + urlToFetch + ': ' + JSON.stringify(ogData));
						return;
					}
				} else {
					// All went well, postprocess and send to client
					resultData = postProcess(urlToFetch, ogData.data);
					res.json(resultData);
				}

				if (process.env.ES_URL) {
					resultData._cacheResponse = true;
					es.index({index : esIndex, type : esType, id : encodedUrl, body : resultData}, function (err) {
						if (err) {
							log(WARN, 'Could not save value to cache due to error: ' + err);
						}
					});
				}
			});
		}
	});
}

function ditchDitchDitch(req, res) {
	var urlToDelete = req.query.url;

	var encodedUrl = encodeURI(urlToDelete);
	if (!process.env.ES_URL) {
		// Technically not, but the effect is the same for the caller
		res.status(200).json({message: 'The url has been deleted from the cache', url: urlToDelete});
		return;
	}
	es.delete({index : esIndex, type : esType, id : encodedUrl}, function (err, response) {
		if (err && err.statusCode !== 404) {
			// If there is an error, we do not have the opengraph data so we return a 404
			log(ERR, 'An error occured while deleting data from the cache: ' + err);
			res.status(500).json({message: 'The url could not be deleted due to an internal error', url: urlToDelete});
		} else {
			res.status(200).json({message: 'The url has been deleted from the cache', url: urlToDelete});
		}
	});
}

app.get('/opengraph', workWorkWork);
app.delete('/opengraph', ditchDitchDitch);
app.get('/_health', function (req, res) {
	res.end('Jolly good here');
});
app.listen(7070, function () {
	log(INFO, 'Server is listening');
});

<|endoftext|>


<commit_before>var Scuttlebutt = require("scuttlebutt")
    , filter = Scuttlebutt.filter
    , inherits = require("util").inherits

inherits(AppendOnly, Scuttlebutt)

var proto = AppendOnly.prototype

proto.push = push
proto.remove = remove
proto.applyUpdate = applyUpdate
proto.history = history
proto.toJSON = proto.createArray = createArray

module.exports = AppendOnly

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

    Scuttlebutt.call(this, options)

    this._store = []
    this._hash = {}
}

function push(item) {
    this.localUpdate({ push: item })
}

function remove(id) {
    this.localUpdate({ remove: id })
}

function applyUpdate(update) {
    var value = update[0]
        , ts = update[1]
        , source = update[2]

    // console.log("applyUpdate", update)

    this._store.push(update)

    if (value.push) {
        var item = value.push
            , id = source + ":" + ts

        Object.defineProperty(item, "__id", {
            value: id
            , configurable: true
        })
        this._hash[id] = item
        this.emit("item", item)
    } else if (value.remove) {
        var id = value.remove
            , item = this._hash[id]

        ;delete this._hash[id]
        this.emit("remove", item)
    }
    return true
}

function history(sources) {
    return this._store.filter(function (update) {
        return filter(update, sources)
    })
}

function createArray() {
    var hash = this._hash

    return Object.keys(hash).map(findKey, hash)
}

function findKey(key) {
    return this[key]
}
<commit_msg>emit remove event, so that db knows it can remove an old push.<commit_after>var Scuttlebutt = require("scuttlebutt")
    , filter = Scuttlebutt.filter
    , inherits = require("util").inherits

inherits(AppendOnly, Scuttlebutt)

var proto = AppendOnly.prototype

proto.push = push
proto.remove = remove
proto.applyUpdate = applyUpdate
proto.history = history
proto.toJSON = proto.createArray = createArray

module.exports = AppendOnly

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

    Scuttlebutt.call(this, options)

    this._store = []
    this._hash = {}

    this.on('_remove', function removeUpdateFromStore (update) {
        var i = this._store.indexOf(update)
        if(~i) this._store.splice(i, 1)
    })
}

function push(item) {
    this.localUpdate({ push: item })
}

function remove(id) {
    this.localUpdate({ remove: id.__id ? id.__id : id })
}

function toId (update) {
    var ts = update[1]
      , source = update[2]
    return source + ':' + ts
}

function applyUpdate(update) {
    var value = update[0]

    this._store.push(update)

    if (value.push) {
        var item = value.push
            , id = toId(update)

        Object.defineProperty(item, "__id", {
            value: id
            , configurable: true
        })
        this._hash[id] = update
        this.emit("item", item)
    } else if (value.remove) {
        var id = value.remove
            , _update = this._hash[id]

        ;delete this._hash[id]

        this.emit("_remove", _update)
        this.emit("remove", _update[0].push)
    }
    return true
}

function history(sources) {
    return this._store.filter(function (update) {
        return filter(update, sources)
    })
}

function createArray() {
    var hash = this._hash

    return Object.keys(hash).map(findKey, hash)
}

function findKey(key) {
    return this[key]
}
<|endoftext|>


<commit_before>var promise = require("bloody-promise")
  , klass = require("bloody-class")
  , _hasOwnProperty = {}.hasOwnProperty

function each(object, callback, thisValue){
  var key
  if(!object) return
  for(key in object) {
    if(!_hasOwnProperty.call(object, key)) continue
    callback.call(thisValue, object[key], key, object)
  }
}

module.exports = klass.extend({
  constructor : function(object){
    if(typeof object == "string") {
      object = {url:object}
    }
    each(object, this._options, this)
  },
  _options : function(item, key){
    this[key] = item
  },
  destructor : function(){
    if(!this.xhr) return
    this.xhr.aborted = true
    this.xhr.abort()
    this.xhr = null
  },
  _createXHR : function(){
    return new XMLHttpRequest()
  },
  _setHeader: function(item, key){
    this.setRequestHeader(key, item)
  },
  _setHeaders : function(xhr){
    if(this.method == "POST") {
      xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest")
      xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
    }
    each(this.headers, this._setHeader, xhr)
  },
  _createXHRCallback : function(boundPromise){
    return function(){
      var readyState = this.readyState
        , status = this.status
      if(readyState != 4 || this.aborted) return
      if(status >= 200 && status < 300 || status == 304) {
        return boundPromise.fulfill(this)
      }
      if((status < 200 || 300 < status) && status != 304) {
        boundPromise.reject(this)
      }
    }
  },
  _resolveUrl : function(baseUrl, queryString){
    if(!queryString) return baseUrl
    switch(baseUrl.indexOf("?")) {
      case -1:
      return baseUrl + "?" + queryString
      break
      case baseUrl.length - 1:
      return baseUrl + queryString
      break
      default:
      return baseUrl + "&" + queryString
    }
  },
  load : function(){
    this.destroy()
    var xhr = this._createXHR()
      , xhrPromise = promise.create()
      , callback = this._createXHRCallback(xhrPromise)
      , url = this._resolveUrl(this.url, this.queryString)
    this.xhr = xhr
    xhr.open(this.method, url, true)
    this._setHeaders(xhr)
    xhr.withCredentials = !!this.withCredentials
    xhr.onreadystatechange = callback
    xhr.send(this.data || null)
    return xhrPromise
  },
  headers : null,
  method : "GET",
  url : null,
  queryString : null,
  data : null,
  withCredentials : false,
  xhr : null
})
<commit_msg>IE9 fix<commit_after>var promise = require("bloody-promise")
  , klass = require("bloody-class")
  , _hasOwnProperty = {}.hasOwnProperty

function each(object, callback, thisValue){
  var key
  if(!object) return
  for(key in object) {
    if(!_hasOwnProperty.call(object, key)) continue
    callback.call(thisValue, object[key], key, object)
  }
}

module.exports = klass.extend({
  constructor : function(object){
    if(typeof object == "string") {
      object = {url:object}
    }
    each(object, this._options, this)
  },
  _options : function(item, key){
    this[key] = item
  },
  destructor : function(){
    if(!this.xhr) return
    if(this.xhr.readyState != 4){
      this.xhr.aborted = true
      this.xhr.abort()
    }
    this.xhr = null
  },
  _createXHR : function(){
    return new XMLHttpRequest()
  },
  _setHeader: function(item, key){
    this.setRequestHeader(key, item)
  },
  _setHeaders : function(xhr){
    if(this.method == "POST") {
      xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest")
      xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
    }
    each(this.headers, this._setHeader, xhr)
  },
  _createXHRCallback : function(boundPromise){
    return function(){
      var readyState = this.readyState
        , status = this.status
      if(readyState != 4 || this.aborted) return
      if(status >= 200 && status < 300 || status == 304) {
        return boundPromise.fulfill(this)
      }
      if((status < 200 || 300 < status) && status != 304) {
        boundPromise.reject(this)
      }
    }
  },
  _resolveUrl : function(baseUrl, queryString){
    if(!queryString) return baseUrl
    switch(baseUrl.indexOf("?")) {
      case -1:
      return baseUrl + "?" + queryString
      break
      case baseUrl.length - 1:
      return baseUrl + queryString
      break
      default:
      return baseUrl + "&" + queryString
    }
  },
  load : function(){
    this.destroy()
    var xhr = this._createXHR()
      , xhrPromise = promise.create()
      , callback = this._createXHRCallback(xhrPromise)
      , url = this._resolveUrl(this.url, this.queryString)
    this.xhr = xhr
    xhr.open(this.method, url, true)
    this._setHeaders(xhr)
    xhr.withCredentials = !!this.withCredentials
    xhr.onreadystatechange = callback
    xhr.send(this.data || null)
    return xhrPromise
  },
  headers : null,
  method : "GET",
  url : null,
  queryString : null,
  data : null,
  withCredentials : false,
  xhr : null
})
<|endoftext|>


<commit_before>/**
 * Module dependencies.
 */

var express = require('express');
var http = require('http');

/*
 * Create and expose app
 */
var app = exports.app = express();

/**
 * Set `app` configure settings
 */

require('./config')(app)

/*
 * Register Models and Launch Mongoose
 * with `app` configuration settings
 */

require('lib/models')(app);

// Each module has its own routes and views
// receives app as parameter to sincronize
// custom settings

/*
 * PassportJS Auth Strategies and Routes
 */

require('lib/auth')(app);

/*
 * Local signin routes
 */

app.use('/signin', require('lib/signin'));

/*
 * Local signup routes
 */

app.use('/signup', require('lib/signup'));

/*
 * Forgot password routes
 */

app.use('/forgot', require('lib/forgot'));

/**
 * Tag API Service
 */

app.use('/api', require('lib/tag'));

/**
 * Proposal API Service
 */

app.use('/api', require('lib/proposal'));

/**
 * Law API Service
 */

app.use('/api', require('lib/law'));

/**
 * Comment API Service
 */

app.use('/api', require('lib/comment'));

/**
 * Citizen API Service
 */

app.use('/api', require('lib/citizen'));

/**
 * Delegation API Service
 */

app.use('/api', require('lib/delegation'));

/**
 * Mount BootUp
 */

app.use(require('lib/boot'));

/*
 * Start Web server
 */

exports.server = http.createServer(app).listen(app.get('port'), function() {
  console.log('Application started on port %d', app.get('port'));
});
<commit_msg>[democracyos] - Apply new balance module for application clustering<commit_after>/**
 * Module dependencies.
 */

var express = require('express');
var http = require('http');
var balance = require('lib/balance');

/*
 * Create and expose app
 */

var app = exports.app = express();

/**
 * Create and expose server
 */

var server = exports.server = http.createServer(app);

/**
 * Set `app` configure settings
 */

require('./config')(app)

/*
 * Register Models and Launch Mongoose
 * with `app` configuration settings
 */

require('lib/models')(app);

// Each module has its own routes and views
// receives app as parameter to sincronize
// custom settings

/*
 * PassportJS Auth Strategies and Routes
 */

require('lib/auth')(app);

/*
 * Local signin routes
 */

app.use('/signin', require('lib/signin'));

/*
 * Local signup routes
 */

app.use('/signup', require('lib/signup'));

/*
 * Forgot password routes
 */

app.use('/forgot', require('lib/forgot'));

/**
 * Tag API Service
 */

app.use('/api', require('lib/tag'));

/**
 * Proposal API Service
 */

app.use('/api', require('lib/proposal'));

/**
 * Law API Service
 */

app.use('/api', require('lib/law'));

/**
 * Comment API Service
 */

app.use('/api', require('lib/comment'));

/**
 * Citizen API Service
 */

app.use('/api', require('lib/citizen'));

/**
 * Delegation API Service
 */

app.use('/api', require('lib/delegation'));

/**
 * Mount BootUp
 */

app.use(require('lib/boot'));

/*
 * Start Web server
 */

if (module === require.main) {
  balance(function() {
    server.listen(app.get('port'), function() {
      console.log('Application started on port %d', app.get('port'));
    });
  });
}
<|endoftext|>


<commit_before>var component = {};
component.props = ["useCustomSlot"];
if (process.browser) {
  component = require('vue2-dropzone/dist/vue2Dropzone.js')
}
component.render = function (createElement) {
  var that = this._self;
  return createElement('div', {
    props: that.props,
    attrs: {
      class: 'vue-dropzone dropzone',
      id: that.id || ''
    },
    ref: 'dropzoneElement'
  }, [this.useCustomSlot === "" || this.useCustomSlot === true ? createElement("div", {staticClass: "dz-message"}, [this._t("default", [this._v("Drop files here to upload")])], 2) : this._e()])
};
component.name = 'dropzone';

module.exports = component;
<commit_msg>Cleaned index.js<commit_after>var component = {};
component.props = ["useCustomSlot"];
if (process.browser) {
  component = require('vue2-dropzone/dist/vue2Dropzone.js')
}
component.render = function (createElement) {
  var that = this._self;
  return createElement('div', {
    props: that.props,
    attrs: {
      class: 'vue-dropzone dropzone',
      id: that.id || ''
    },
    ref: 'dropzoneElement'
  }, this.useCustomSlot === "" || this.useCustomSlot === true ? [createElement("div", {staticClass: "dz-message"}, this.$slots.default)] : this.$slots.default)
};
component.name = 'dropzone';

module.exports = component;
<|endoftext|>


<commit_before>var net = require('net'),
    protobuf = require('protobuf.js'),
    butils = require('butils');

var messageCodes = {
    '0': 'RpbErrorResp',
    '1': 'RpbPingReq',
    '2': 'RpbPingResp',
    '3': 'RpbGetClientIdReq',
    '4': 'RpbGetClientIdResp',
    '5': 'RpbSetClientIdReq',
    '6': 'RpbSetClientIdResp',
    '7': 'RpbGetServerInfoReq',
    '8': 'RpbGetServerInfoResp',
    '9': 'RpbGetReq',
    '10': 'RpbGetResp',
    '11': 'RpbPutReq',
    '12': 'RpbPutResp',
    '13': 'RpbDelReq',
    '14': 'RpbDelResp',
    '15': 'RpbListBucketsReq',
    '16': 'RpbListBucketsResp',
    '17': 'RpbListKeysReq',
    '18': 'RpbListKeysResp',
    '19': 'RpbGetBucketReq',
    '20': 'RpbGetBucketResp',
    '21': 'RpbSetBucketReq',
    '22': 'RpbSetBucketResp',
    '23': 'RpbMapRedReq',
    '24': 'RpbMapRedResp',
    '25': 'RpbIndexReq',
    '26': 'RpbIndexResp',
    '27': 'RpbSearchQueryReq',
    '28': 'RpbSearchQueryResp'
};
Object.keys(messageCodes).forEach(function (key) {
    messageCodes[messageCodes[key]] = Number(key);
});

function RiakPBC(options) {
    var self = this;
    options = options || {};
    self.host = options.host || '127.0.0.1';
    self.port = options.port || 8087;
    self.bucket = options.bucket || undefined;
    self.translator = protobuf.loadSchema('./spec/riak_kv.proto');
    self.client = new net.Socket();
    self.connected = false;
    self.client.on('end', self.disconnect);
    self.client.on('error', self.disconnect);
    self.paused = false;
    self.queue = [];
    var mc, reply = {};

    function splitPacket(pkt) {
        var ret = [], len, pos = 0, end = pkt.length;
        while (pos < end) {
            len = butils.readInt32(pkt, pos);
            ret.push(pkt.slice(pos + 4, pos + len + 4));
            pos += len + 4;
        }
        return ret;
    }

    self.client.on('data', function (chunk) {
        splitPacket(chunk).forEach(function (packet) {
            mc = messageCodes['' + packet[0]];
            reply = _merge(reply, self.translator.decode(mc, packet.slice(1)));
            if (!self.task.expectMultiple || reply.done || mc === 'RpbErrorResp') {
                self.task.callback(reply);
                mc = undefined;
                self.task = undefined;
                reply = {};
                self.paused = false;
                self.processNext();
            }
        });
    });

    self.processNext = function () {
        if (self.queue.length && !self.paused) {
            self.paused = true;
            self.connect(function () {
                self.task = self.queue.shift();
                self.client.write(self.task.message);
            });
        }
    };
}

function _merge(obj1, obj2) {
    var obj = {};
    if (obj2.hasOwnProperty('phase')) {
        obj = obj1;
        if (obj[obj2.phase] === undefined) obj[obj2.phase] = [];
        obj[obj2.phase] = obj[obj2.phase].concat(JSON.parse(obj2.response));
    } else {
        [obj1, obj2].forEach(function (old) {
            Object.keys(old).forEach(function (key) {
                if (!old.hasOwnProperty(key)) return;
                if (Array.isArray(old[key])) {
                    if (!obj[key]) obj[key] = [];
                    obj[key] = obj[key].concat(old[key]);
                } else {
                    obj[key] = old[key];
                }
            });
        });
    }
    return obj;
}

RiakPBC.prototype.makeRequest = function (type, data, callback, expectMultiple) {
    var self = this,
        reply = {},
        buffer = this.translator.encode(type, data),
        message = [];

    butils.writeInt32(message, buffer.length + 1);
    butils.writeInt(message, messageCodes[type], 4);
    message = message.concat(buffer);
    self.queue.push({ message: new Buffer(message), callback: callback, expectMultiple: expectMultiple });
    process.nextTick(self.processNext);
};

RiakPBC.prototype.getBuckets = function (callback) {
    this.makeRequest('RpbListBucketsReq', null, callback);
};

RiakPBC.prototype.getBucket = function (params, callback) {
    this.makeRequest('RpbGetBucketReq', params, callback);
};

RiakPBC.prototype.setBucket = function (params, callback) {
    this.makeRequest('RpbSetBucketReq', params, callback);
};

RiakPBC.prototype.getKeys = function (params, callback) {
    this.makeRequest('RpbListKeysReq', params, callback, true);
};

RiakPBC.prototype.put = function (params, callback) {
    this.makeRequest('RpbPutReq', params, callback);
};

RiakPBC.prototype.get = function (params, callback) {
    this.makeRequest('RpbGetReq', params, callback);
};

RiakPBC.prototype.del = function (params, callback) {
    this.makeRequest('RpbDelReq', params, callback);
};

RiakPBC.prototype.mapred = function (params, callback) {
    this.makeRequest('RpbMapRedReq', params, callback, true);
};

RiakPBC.prototype.getIndex = function (params, callback) {
    this.makeRequest('RpbIndexReq', params, callback);
};

RiakPBC.prototype.search = function (params, callback) {
    this.makeRequest('RpbSearchQueryReq', params, callback);
};

RiakPBC.prototype.getClientId = function (callback) {
    this.makeRequest('RpbGetClientIdReq', null, callback);
};

RiakPBC.prototype.setClientId = function (params, callback) {
    this.makeRequest('RpbSetClientIdReq', params, callback);
};

RiakPBC.prototype.getServerInfo = function (callback) {
    this.makeRequest('RpbGetServerInfoReq', null, callback);
};

RiakPBC.prototype.ping = function (callback) {
    this.makeRequest('RpbPingReq', null, callback);
};

RiakPBC.prototype.connect = function (callback) {
    if (this.connected) return callback();
    var self = this;
    self.client.connect(self.port, self.host, function () {
        self.connected = true;
        callback();
    });
};

RiakPBC.prototype.disconnect = function () {
    if (!this.connected) return;
    this.client.end();
    this.connected = false;
    if (this.task) {
        this.queue.unshift(this.task);
        this.task = undefined;
    }
};

exports.createClient = function (options) {
    return new RiakPBC(options);
};
<commit_msg>Using path+__dirname to resolve schema file, should work with nested modules<commit_after>var net = require('net'),
    protobuf = require('protobuf.js'),
    butils = require('butils'),
 path = require('path');

var messageCodes = {
    '0': 'RpbErrorResp',
    '1': 'RpbPingReq',
    '2': 'RpbPingResp',
    '3': 'RpbGetClientIdReq',
    '4': 'RpbGetClientIdResp',
    '5': 'RpbSetClientIdReq',
    '6': 'RpbSetClientIdResp',
    '7': 'RpbGetServerInfoReq',
    '8': 'RpbGetServerInfoResp',
    '9': 'RpbGetReq',
    '10': 'RpbGetResp',
    '11': 'RpbPutReq',
    '12': 'RpbPutResp',
    '13': 'RpbDelReq',
    '14': 'RpbDelResp',
    '15': 'RpbListBucketsReq',
    '16': 'RpbListBucketsResp',
    '17': 'RpbListKeysReq',
    '18': 'RpbListKeysResp',
    '19': 'RpbGetBucketReq',
    '20': 'RpbGetBucketResp',
    '21': 'RpbSetBucketReq',
    '22': 'RpbSetBucketResp',
    '23': 'RpbMapRedReq',
    '24': 'RpbMapRedResp',
    '25': 'RpbIndexReq',
    '26': 'RpbIndexResp',
    '27': 'RpbSearchQueryReq',
    '28': 'RpbSearchQueryResp'
};
Object.keys(messageCodes).forEach(function (key) {
    messageCodes[messageCodes[key]] = Number(key);
});

function RiakPBC(options) {
    var self = this;
    options = options || {};
    self.host = options.host || '127.0.0.1';
    self.port = options.port || 8087;
    self.bucket = options.bucket || undefined;
    self.translator = protobuf.loadSchema(path.join(__dirname, './spec/riak_kv.proto'));
    self.client = new net.Socket();
    self.connected = false;
    self.client.on('end', self.disconnect);
    self.client.on('error', self.disconnect);
    self.paused = false;
    self.queue = [];
    var mc, reply = {};

    function splitPacket(pkt) {
        var ret = [], len, pos = 0, end = pkt.length;
        while (pos < end) {
            len = butils.readInt32(pkt, pos);
            ret.push(pkt.slice(pos + 4, pos + len + 4));
            pos += len + 4;
        }
        return ret;
    }

    self.client.on('data', function (chunk) {
        splitPacket(chunk).forEach(function (packet) {
            mc = messageCodes['' + packet[0]];
            reply = _merge(reply, self.translator.decode(mc, packet.slice(1)));
            if (!self.task.expectMultiple || reply.done || mc === 'RpbErrorResp') {
                self.task.callback(reply);
                mc = undefined;
                self.task = undefined;
                reply = {};
                self.paused = false;
                self.processNext();
            }
        });
    });

    self.processNext = function () {
        if (self.queue.length && !self.paused) {
            self.paused = true;
            self.connect(function () {
                self.task = self.queue.shift();
                self.client.write(self.task.message);
            });
        }
    };
}

function _merge(obj1, obj2) {
    var obj = {};
    if (obj2.hasOwnProperty('phase')) {
        obj = obj1;
        if (obj[obj2.phase] === undefined) obj[obj2.phase] = [];
        obj[obj2.phase] = obj[obj2.phase].concat(JSON.parse(obj2.response));
    } else {
        [obj1, obj2].forEach(function (old) {
            Object.keys(old).forEach(function (key) {
                if (!old.hasOwnProperty(key)) return;
                if (Array.isArray(old[key])) {
                    if (!obj[key]) obj[key] = [];
                    obj[key] = obj[key].concat(old[key]);
                } else {
                    obj[key] = old[key];
                }
            });
        });
    }
    return obj;
}

RiakPBC.prototype.makeRequest = function (type, data, callback, expectMultiple) {
    var self = this,
        reply = {},
        buffer = this.translator.encode(type, data),
        message = [];

    butils.writeInt32(message, buffer.length + 1);
    butils.writeInt(message, messageCodes[type], 4);
    message = message.concat(buffer);
    self.queue.push({ message: new Buffer(message), callback: callback, expectMultiple: expectMultiple });
    process.nextTick(self.processNext);
};

RiakPBC.prototype.getBuckets = function (callback) {
    this.makeRequest('RpbListBucketsReq', null, callback);
};

RiakPBC.prototype.getBucket = function (params, callback) {
    this.makeRequest('RpbGetBucketReq', params, callback);
};

RiakPBC.prototype.setBucket = function (params, callback) {
    this.makeRequest('RpbSetBucketReq', params, callback);
};

RiakPBC.prototype.getKeys = function (params, callback) {
    this.makeRequest('RpbListKeysReq', params, callback, true);
};

RiakPBC.prototype.put = function (params, callback) {
    this.makeRequest('RpbPutReq', params, callback);
};

RiakPBC.prototype.get = function (params, callback) {
    this.makeRequest('RpbGetReq', params, callback);
};

RiakPBC.prototype.del = function (params, callback) {
    this.makeRequest('RpbDelReq', params, callback);
};

RiakPBC.prototype.mapred = function (params, callback) {
    this.makeRequest('RpbMapRedReq', params, callback, true);
};

RiakPBC.prototype.getIndex = function (params, callback) {
    this.makeRequest('RpbIndexReq', params, callback);
};

RiakPBC.prototype.search = function (params, callback) {
    this.makeRequest('RpbSearchQueryReq', params, callback);
};

RiakPBC.prototype.getClientId = function (callback) {
    this.makeRequest('RpbGetClientIdReq', null, callback);
};

RiakPBC.prototype.setClientId = function (params, callback) {
    this.makeRequest('RpbSetClientIdReq', params, callback);
};

RiakPBC.prototype.getServerInfo = function (callback) {
    this.makeRequest('RpbGetServerInfoReq', null, callback);
};

RiakPBC.prototype.ping = function (callback) {
    this.makeRequest('RpbPingReq', null, callback);
};

RiakPBC.prototype.connect = function (callback) {
    if (this.connected) return callback();
    var self = this;
    self.client.connect(self.port, self.host, function () {
        self.connected = true;
        callback();
    });
};

RiakPBC.prototype.disconnect = function () {
    if (!this.connected) return;
    this.client.end();
    this.connected = false;
    if (this.task) {
        this.queue.unshift(this.task);
        this.task = undefined;
    }
};

exports.createClient = function (options) {
    return new RiakPBC(options);
};
<|endoftext|>


<commit_before>'use strict';

/**
 * Module dependencies
 */

var fs = require('fs');
var path = require('path');
var relative = require('relative');

/**
 * Return an object for all files matching the given `patterns`
 * and `options`. The full filepath of the file is used as the key.
 *
 * @param  {String} `patterns` Glob patterns to pass to [globby]
 * @param  {Object} `opts` Options for globby, or pass a custom `parse` or `name`.
 * @return {Object}
 * @api public
 */

module.exports = function mapFiles(patterns, options) {
  var files = globber(patterns, options);
  var cwd = options && options.cwd || process.cwd();

  return files.reduce(function (cache, filepath) {
    filepath = relative(path.resolve(cwd, filepath));
    var key = name(filepath, options);
    var str = read(filepath, options);

    cache[key] = str;
    return cache;
  }, {});
};

function globber(patterns, options) {
  if (options && options.glob) {
    return options.glob(patterns, options);
  }
  var glob = require('globby');
  return glob.sync(patterns, options);
}

function name(filepath, options) {
  if (options && options.name) {
    return options.name(filepath, options);
  }
  var ext = path.extname(filepath);
  return path.basename(filepath, ext);
}

function read(filepath, options) {
  if (options && options.read) {
    return options.read(filepath, options);
  }
  var str = fs.readFileSync(filepath, 'utf8');
  return {path: filepath, content: str};
}
<commit_msg>expose `cache` to custom functions, to allow lookups on properties if necessary. Like for when duplicate keys are created (ex. `a.yml` and `a.json`)<commit_after>'use strict';

/**
 * Module dependencies
 */

var fs = require('fs');
var path = require('path');
var relative = require('relative');

/**
 * Return an object for all files matching the given `patterns`
 * and `options`. The full filepath of the file is used as the key.
 *
 * @param  {String} `patterns` Glob patterns to pass to [globby]
 * @param  {Object} `opts` Options for globby, or pass a custom `parse` or `name`.
 * @return {Object}
 * @api public
 */

module.exports = function mapFiles(patterns, options) {
  var files = glob(patterns, options);
  var cwd = options && options.cwd || process.cwd();

  return files.reduce(function (cache, filepath) {
    filepath = relative(path.resolve(cwd, filepath));
    var key = name(filepath, cache, options);
    var str = read(filepath, cache, options);

    cache[key] = str;
    return cache;
  }, {});
};

function glob(patterns, options) {
  if (options && options.glob) {
    return options.glob(patterns, options);
  }
  var globby = require('globby');
  return globby.sync(patterns, options);
}

function name(filepath, cache, options) {
  if (options && options.name) {
    return options.name(filepath, cache, options);
  }
  var ext = path.extname(filepath);
  return path.basename(filepath, ext);
}

function read(filepath, cache, options) {
  if (options && options.read) {
    return options.read(filepath, cache, options);
  }
  var str = fs.readFileSync(filepath, 'utf8');
  return {path: filepath, content: str};
}
<|endoftext|>


<commit_before>'use strict';

var BaseBinaryTree = require('./base-binary-tree');
var BinaryTreeNode = require('./binary-tree-node');

/**
  * Creates a splay tree.
  *
  * @constructor
  * @param {function} customCompare An optional custom node comparison
  * function.
  */
var SplayTree = function (customCompare) {
  BaseBinaryTree.call(this);

  this.nodeCount = 0;

  if (customCompare) {
    this.compare = customCompare;
  }
};

SplayTree.prototype = Object.create(BaseBinaryTree.prototype);

SplayTree.prototype.constructor = SplayTree;

/**
  * Adds a key to the tree.
  *
  * @param {Object} key The key to add.
  * @return {boolean} Whether the node was added.
  */
SplayTree.prototype.add = function (key) {
  if (!this.root) {
    this.root = new BinaryTreeNode(key);
    this.nodeCount++;
    return true;
  }

  var wasAdded = insertInternal(this, key, this.root);
  this.contains(key);
  return wasAdded;
};

/**
  * Determines whether the tree contains a key.
  *
  * @param {Object} key The key to check.
  * @return {boolean} Whether the node contains the key.
  */
SplayTree.prototype.contains = function (key) {
  if (!this.root) {
    return false;
  }

  var node = containsInternal(this, key, this.root);
  if (node) {
    splay(this, node);
  }
  return !!node;
};

/**
  * @return {Object} The maximum key of the tree.
  */
SplayTree.prototype.findMaximum = function () {
  if (!this.root) {
    return undefined;
  }

  var current = this.root;
  while (true) {
    if (current.right) {
      current = current.right;
    } else {
      return current.key;
    }
  }
};

/**
  * @return {Object} The minimum key of the tree.
  */
SplayTree.prototype.findMinimum = function () {
  if (!this.root) {
    return undefined;
  }

  var current = this.root;
  while (true) {
    if (current.left) {
      current = current.left;
    } else {
      return current.key;
    }
  }
};

/**
  * @return {boolean} Whether the tree is empty.
  */
SplayTree.prototype.isEmpty = function () {
  return !this.root;
};

/**
  * Removes a key from the tree.
  *
  * @param {Object} key The key to remove.
  * @return {boolean} Whether the key was removed.
  */
SplayTree.prototype.remove = function (key) {
  if (!this.root) {
    return false;
  }

  this.contains(key);
  return removeInternal(this, key, this.root);
};

/**
  * @return The size of the tree.
  */
SplayTree.prototype.size = function () {
  return this.nodeCount;
};

/**
  * Compares two nodes with each other.
  *
  * @param {Object} a The first key to compare.
  * @param {Object} b The second key to compare.
  * @return -1, 0 or 1 if a < b, a == b or a > b respectively.
  */
SplayTree.prototype.compare = function (a, b) {
  if (a > b) {
    return 1;
  }
  if (a < b) {
    return -1;
  }
  return 0;
};

/**
  * Rotates a node in a tree left.
  *
  *     a                             b
  *    / \                           / \
  *   c   b   -> rotateLeft(a) ->   a   e
  *      / \                       / \
  *     d   e                     c   d
  *
  * @param {SplayTree} tree The splay tree.
  * @param {BinaryTreeNode} x The node being rotated.
  */
function rotateLeft(tree, x) {
  var y = x.right;
  x.right = y.left;
  if (y.left) {
    y.left.parent = x;
  }
  y.parent = x.parent;
  if (!x.parent) {
    tree.root = y;
  } else {
    if (x === x.parent.left) {
      x.parent.left = y;
    } else {
      x.parent.right = y;
    }
  }
  y.left = x;
  x.parent = y;
}

/**
  * Rotates a node in a tree right.
  *
  *       b                          a
  *      / \                        / \
  *     a   e -> rotateRight(b) -> c   b
  *    / \                            / \
  *   c   d                          d   e
  *
  * @param {SplayTree} tree The splay tree.
  * @param {BinaryTreeNode} x The node being rotated.
  */
function rotateRight(tree, x) {
  var y = x.left;
  x.left = y.right;
  if (y.right) {
    y.right.parent = x;
  }
  y.parent = x.parent;
  if (!x.parent) {
    tree.root = y;
  } else {
    if (x === x.parent.left) {
      x.parent.left = y;
    } else {
      x.parent.right = y;
    }
  }
  y.right = x;
  x.parent = y;
}

/**
  * Inserts a key into the tree rooted on a particular node.
  *
  * @param {SplayTree} tree The tree to insert into.
  * @param {Object} key The key to insert.
  * @param {BinaryTreeNode} mode The tree's node to insert until.
  */
function insertInternal(tree, key, node) {
  if (tree.compare(key, node.key) < 0) {
    if (node.left) {
      return insertInternal(tree, key, node.left);
    } else {
      node.left = new BinaryTreeNode(key, node);
      tree.nodeCount++;
      return true;
    }
  }

  if (tree.compare(key, node.key) > 0) {
    if (node.right) {
      return insertInternal(tree, key, node.right);
    } else {
      node.right = new BinaryTreeNode(key, node);
      tree.nodeCount++;
      return true;
    }
  }

  return false;
}

function containsInternal(tree, key, node) {
  if (key === node.key) {
    return node;
  }

  if (tree.compare(key, node.key) < 0) {
    if (!node.left) {
      return undefined;
    }
    return containsInternal(tree, key, node.left);
  }

  if (tree.compare(key, node.key) > 0) {
    if (!node.right) {
      return undefined;
    }
    return containsInternal(tree, key, node.right);
  }

  return undefined;
}

function removeInternal(tree, key, node) {
  if (tree.compare(key, node.key) < 0) {
    if (node.left) {
      return removeInternal(tree, key, node.left);
    }
    return false;
  }

  if (tree.compare(key, node.key) > 0) {
    if (node.right) {
      return removeInternal(tree, key, node.right);
    }
    return false;
  }

  return removeInternal2(tree, node);
}

function removeInternal2(tree, node) {
  if (!node.left && !node.right) {
    removeNodeWithNoChildren(tree, node);
    return true;
  }

  if (node.left && !node.right) {
    removeNodeWithLeftOnly(tree, node);
    return true;
  }

  if (node.right && !node.left) {
    removeNodeWithRightOnly(tree, node);
    return true;
  }

  // both exist, replace with node minimum from right sub-tree and delete the
  // node from the right sub-tree
  var minParent = findParentOfMinimum(node.right, node);
  var minNode = minParent.left ? minParent.left : minParent.right;
  var newKey = minNode.key;
  removeInternal2(tree, minNode);
  node.key = newKey;

  return true;
}

/**
  * Removes a node with no children.
  *
  * @param {SplayTree} tree The tree to remove the node from.
  * @param {BinaryTreeNode} node The node to remove.
  */
function removeNodeWithNoChildren(tree, node) {
  if (node.parent) {
    node.parent.removeChild(node);
  } else {
    tree.root = undefined;
  }
  tree.nodeCount--;
}

/**
  * Removes a node with a left child only, moving the left child in to the
  * node's place.
  *
  * @param {SplayTree} tree The tree to remove the node from.
  * @param {BinaryTreeNode} node The node to remove.
  */
function removeNodeWithLeftOnly(tree, node) {
  node.key = node.left.key;
  node.right = node.left.right;
  if (node.right) {
    node.right.parent = node;
  }
  node.left = node.left.left;
  if (node.left) {
    node.left.parent = node;
  }
  tree.nodeCount--;
}

/**
  * Removes a node with a right child only, moving the right child in to the
  * node's place.
  *
  * @param {SplayTree} tree The tree to remove the node from.
  * @param {BinaryTreeNode} node The node to remove.
  */
function removeNodeWithRightOnly(tree, node) {
  node.key = node.right.key;
  node.left = node.right.left;
  if (node.left) {
    node.left.parent = node;
  }
  node.right = node.right.right;
  if (node.right) {
    node.right.parent = node;
  }
  tree.nodeCount--;
}

/**
  * Splay the tree on a node, bringing it to the root using a series of
  * rotation operations.
  *
  * @param {SplayTree} tree The tree being splayed.
  * @param {BinaryTreeNode} node The node being splayed on.
  */
function splay(tree, node) {
  while (node.parent) {
    var parent = node.parent;
    if (!parent.parent) {
      if (parent.left === node) {
        rotateRight(tree, parent);
      } else {
        rotateLeft(tree, parent);
      }
    } else {
      var gparent = parent.parent;
      if (parent.left === node && gparent.left === parent) {
        rotateRight(tree, gparent);
        rotateRight(tree, node.parent);
      } else if (parent.right === node && gparent.right === parent) {
        rotateLeft(tree, gparent);
        rotateLeft(tree, node.parent);
      } else if (parent.left === node && gparent.right === parent) {
        rotateRight(tree, parent);
        rotateLeft(tree, node.parent);
      } else {
        rotateLeft(tree, parent);
        rotateRight(tree, node.parent);
      }
    }
  }
}

/**
  * @return {BinaryTreeNode} The parent of the minimum key node in the tree.
  */
function findParentOfMinimum(node, parent) {
  if (!node.left) {
    return parent;
  }

  return findParentOfMinimum(node.left, node);
}

module.exports = SplayTree;
<commit_msg>Fix comment indentation<commit_after>'use strict';

var BaseBinaryTree = require('./base-binary-tree');
var BinaryTreeNode = require('./binary-tree-node');

/**
 * Creates a splay tree.
 *
 * @constructor
 * @param {function} customCompare An optional custom node comparison
 * function.
 */
var SplayTree = function (customCompare) {
  BaseBinaryTree.call(this);

  this.nodeCount = 0;

  if (customCompare) {
    this.compare = customCompare;
  }
};

SplayTree.prototype = Object.create(BaseBinaryTree.prototype);

SplayTree.prototype.constructor = SplayTree;

/**
 * Adds a key to the tree.
 *
 * @param {Object} key The key to add.
 * @return {boolean} Whether the node was added.
 */
SplayTree.prototype.add = function (key) {
  if (!this.root) {
    this.root = new BinaryTreeNode(key);
    this.nodeCount++;
    return true;
  }

  var wasAdded = insertInternal(this, key, this.root);
  this.contains(key);
  return wasAdded;
};

/**
 * Determines whether the tree contains a key.
 *
 * @param {Object} key The key to check.
 * @return {boolean} Whether the node contains the key.
 */
SplayTree.prototype.contains = function (key) {
  if (!this.root) {
    return false;
  }

  var node = containsInternal(this, key, this.root);
  if (node) {
    splay(this, node);
  }
  return !!node;
};

/**
 * @return {Object} The maximum key of the tree.
 */
SplayTree.prototype.findMaximum = function () {
  if (!this.root) {
    return undefined;
  }

  var current = this.root;
  while (true) {
    if (current.right) {
      current = current.right;
    } else {
      return current.key;
    }
  }
};

/**
 * @return {Object} The minimum key of the tree.
 */
SplayTree.prototype.findMinimum = function () {
  if (!this.root) {
    return undefined;
  }

  var current = this.root;
  while (true) {
    if (current.left) {
      current = current.left;
    } else {
      return current.key;
    }
  }
};

/**
 * @return {boolean} Whether the tree is empty.
 */
SplayTree.prototype.isEmpty = function () {
  return !this.root;
};

/**
 * Removes a key from the tree.
 *
 * @param {Object} key The key to remove.
 * @return {boolean} Whether the key was removed.
 */
SplayTree.prototype.remove = function (key) {
  if (!this.root) {
    return false;
  }

  this.contains(key);
  return removeInternal(this, key, this.root);
};

/**
 * @return The size of the tree.
 */
SplayTree.prototype.size = function () {
  return this.nodeCount;
};

/**
 * Compares two nodes with each other.
 *
 * @param {Object} a The first key to compare.
 * @param {Object} b The second key to compare.
 * @return -1, 0 or 1 if a < b, a == b or a > b respectively.
 */
SplayTree.prototype.compare = function (a, b) {
  if (a > b) {
    return 1;
  }
  if (a < b) {
    return -1;
  }
  return 0;
};

/**
 * Rotates a node in a tree left.
 *
 *     a                             b
 *    / \                           / \
 *   c   b   -> rotateLeft(a) ->   a   e
 *      / \                       / \
 *     d   e                     c   d
 *
 * @param {SplayTree} tree The splay tree.
 * @param {BinaryTreeNode} x The node being rotated.
 */
function rotateLeft(tree, x) {
  var y = x.right;
  x.right = y.left;
  if (y.left) {
    y.left.parent = x;
  }
  y.parent = x.parent;
  if (!x.parent) {
    tree.root = y;
  } else {
    if (x === x.parent.left) {
      x.parent.left = y;
    } else {
      x.parent.right = y;
    }
  }
  y.left = x;
  x.parent = y;
}

/**
 * Rotates a node in a tree right.
 *
 *       b                          a
 *      / \                        / \
 *     a   e -> rotateRight(b) -> c   b
 *    / \                            / \
 *   c   d                          d   e
 *
 * @param {SplayTree} tree The splay tree.
 * @param {BinaryTreeNode} x The node being rotated.
 */
function rotateRight(tree, x) {
  var y = x.left;
  x.left = y.right;
  if (y.right) {
    y.right.parent = x;
  }
  y.parent = x.parent;
  if (!x.parent) {
    tree.root = y;
  } else {
    if (x === x.parent.left) {
      x.parent.left = y;
    } else {
      x.parent.right = y;
    }
  }
  y.right = x;
  x.parent = y;
}

/**
 * Inserts a key into the tree rooted on a particular node.
 *
 * @param {SplayTree} tree The tree to insert into.
 * @param {Object} key The key to insert.
 * @param {BinaryTreeNode} mode The tree's node to insert until.
 */
function insertInternal(tree, key, node) {
  if (tree.compare(key, node.key) < 0) {
    if (node.left) {
      return insertInternal(tree, key, node.left);
    } else {
      node.left = new BinaryTreeNode(key, node);
      tree.nodeCount++;
      return true;
    }
  }

  if (tree.compare(key, node.key) > 0) {
    if (node.right) {
      return insertInternal(tree, key, node.right);
    } else {
      node.right = new BinaryTreeNode(key, node);
      tree.nodeCount++;
      return true;
    }
  }

  return false;
}

function containsInternal(tree, key, node) {
  if (key === node.key) {
    return node;
  }

  if (tree.compare(key, node.key) < 0) {
    if (!node.left) {
      return undefined;
    }
    return containsInternal(tree, key, node.left);
  }

  if (tree.compare(key, node.key) > 0) {
    if (!node.right) {
      return undefined;
    }
    return containsInternal(tree, key, node.right);
  }

  return undefined;
}

function removeInternal(tree, key, node) {
  if (tree.compare(key, node.key) < 0) {
    if (node.left) {
      return removeInternal(tree, key, node.left);
    }
    return false;
  }

  if (tree.compare(key, node.key) > 0) {
    if (node.right) {
      return removeInternal(tree, key, node.right);
    }
    return false;
  }

  return removeInternal2(tree, node);
}

function removeInternal2(tree, node) {
  if (!node.left && !node.right) {
    removeNodeWithNoChildren(tree, node);
    return true;
  }

  if (node.left && !node.right) {
    removeNodeWithLeftOnly(tree, node);
    return true;
  }

  if (node.right && !node.left) {
    removeNodeWithRightOnly(tree, node);
    return true;
  }

  // both exist, replace with node minimum from right sub-tree and delete the
  // node from the right sub-tree
  var minParent = findParentOfMinimum(node.right, node);
  var minNode = minParent.left ? minParent.left : minParent.right;
  var newKey = minNode.key;
  removeInternal2(tree, minNode);
  node.key = newKey;

  return true;
}

/**
 * Removes a node with no children.
 *
 * @param {SplayTree} tree The tree to remove the node from.
 * @param {BinaryTreeNode} node The node to remove.
 */
function removeNodeWithNoChildren(tree, node) {
  if (node.parent) {
    node.parent.removeChild(node);
  } else {
    tree.root = undefined;
  }
  tree.nodeCount--;
}

/**
 * Removes a node with a left child only, moving the left child in to the
 * node's place.
 *
 * @param {SplayTree} tree The tree to remove the node from.
 * @param {BinaryTreeNode} node The node to remove.
 */
function removeNodeWithLeftOnly(tree, node) {
  node.key = node.left.key;
  node.right = node.left.right;
  if (node.right) {
    node.right.parent = node;
  }
  node.left = node.left.left;
  if (node.left) {
    node.left.parent = node;
  }
  tree.nodeCount--;
}

/**
 * Removes a node with a right child only, moving the right child in to the
 * node's place.
 *
 * @param {SplayTree} tree The tree to remove the node from.
 * @param {BinaryTreeNode} node The node to remove.
 */
function removeNodeWithRightOnly(tree, node) {
  node.key = node.right.key;
  node.left = node.right.left;
  if (node.left) {
    node.left.parent = node;
  }
  node.right = node.right.right;
  if (node.right) {
    node.right.parent = node;
  }
  tree.nodeCount--;
}

/**
 * Splay the tree on a node, bringing it to the root using a series of
 * rotation operations.
 *
 * @param {SplayTree} tree The tree being splayed.
 * @param {BinaryTreeNode} node The node being splayed on.
 */
function splay(tree, node) {
  while (node.parent) {
    var parent = node.parent;
    if (!parent.parent) {
      if (parent.left === node) {
        rotateRight(tree, parent);
      } else {
        rotateLeft(tree, parent);
      }
    } else {
      var gparent = parent.parent;
      if (parent.left === node && gparent.left === parent) {
        rotateRight(tree, gparent);
        rotateRight(tree, node.parent);
      } else if (parent.right === node && gparent.right === parent) {
        rotateLeft(tree, gparent);
        rotateLeft(tree, node.parent);
      } else if (parent.left === node && gparent.right === parent) {
        rotateRight(tree, parent);
        rotateLeft(tree, node.parent);
      } else {
        rotateLeft(tree, parent);
        rotateRight(tree, node.parent);
      }
    }
  }
}

/**
 * @return {BinaryTreeNode} The parent of the minimum key node in the tree.
 */
function findParentOfMinimum(node, parent) {
  if (!node.left) {
    return parent;
  }

  return findParentOfMinimum(node.left, node);
}

module.exports = SplayTree;
<|endoftext|>