<commit_before>"use strict";

const coerce = require("tiny-coerce"),
	defer = require("tiny-defer"),
	lru = require("tiny-lru"),
	path = require("path"),
	http = require("http"),
	parse = require("tiny-parse"),
	mmh3 = require("murmurhash3js").x86.hash32,
	retsu = require("retsu"),
	utility = require(path.join(__dirname, "utility.js")),
	all = "all",
	allMethod = all.toUpperCase(),
	delimiter = ":",
	startSlash = /^\//,
	endSlash = /\/$/,
	isParam = /^:/,
	hasParam = /\/:(\w*)/,
	head = /^(HEAD)$/,
	methods = http.METHODS;

class Woodland {
	constructor (defaultHost, defaultHeaders, cacheSize, seed) {
		this.blacklisted = new Set();
		this.cache = lru(cacheSize);
		this.defaultHost = defaultHost;
		this.defaultHeaders = Reflect.ownKeys(defaultHeaders).map(key => [key, defaultHeaders[key]]);
		this.hosts = new Map();
		this.permissions = lru(cacheSize);
		this.middleware = new Map();
		this.seed = seed;
	}

	allowed (method, uri, host, override = false) {
		return this.routes(uri, host, method, override).middleware.filter(i => !this.blacklisted.has(i.hash || this.hash(i))).length > 0;
	}

	allows (uri, host, override = false) {
		const key = this.hash(host + delimiter + uri);
		let result = !override ? this.permissions.get(key) : undefined,
			list;

		if (override || !result) {
			list = methods.filter(i => this.allowed(i, uri, host, override));

			if (retsu.contains(list, "OPTIONS") && retsu.contains(list, "GET")) {
				list.splice(list.indexOf("OPTIONS"), 1);
			}

			result = list.join(", ").replace("GET", "GET, HEAD, OPTIONS");
			this.permissions.set(key, result);
		}

		return result;
	}

	blacklist (fn) {
		let key;

		if (fn.hash) {
			key = fn.hash;
		} else {
			key = fn.hash = this.hash(fn.toString());
		}

		if (!this.blacklisted.has(key)) {
			this.blacklisted.add(key);
		}

		return this;
	}

	decorate (req, res) {
		let parsed = parse(req),
			remotes = req.headers["x-forwarded-for"] ? req.headers["x-forwarded-for"].split(/\s*,\s*/g) : [req.connection.remoteAddress];

		// Decorating useful hints
		req.body = "";
		req.ip = remotes[remotes.length - 1];
		req.parsed = parsed;
		req.query = parsed.query;
		req.host = this.host(parsed.hostname);
		req.allow = this.allows(req.parsed.pathname, req.host);

		// Express interop
		req.params = {};
		res.header = res.setHeader;
		res.locals = {};

		// Setting headers
		retsu.each(this.defaultHeaders, header => res.header(header[0], header[1]));

		if (req.allow) {
			res.header("Allow", req.allow);
		}
	}

	hash (arg) {
		return mmh3(arg, this.seed);
	}

	host (arg) {
		let result = "";

		retsu.each(this.hosts, (reg, host) => {
			let output = true;

			if (reg.test(arg)) {
				result = host;
				output = false;
			}

			return output;
		});

		return result || this.defaultHost;
	}

	onclose () {}

	onerror (req, res, err) {
		const numeric = !isNaN(err.message),
			status = !isNaN(res.statusCode) && res.statusCode >= 400 ? res.statusCode : numeric ? Number(err.message) : 500,
			body = numeric ? http.STATUS_CODES[status] : err.message;

		res.writeHead(status, {"Content-Type": "text/plain"});
		res.end(body);
	}

	onfinish () {}

	params (req, pos) {
		const uri = req.parsed.path.replace(startSlash, "").replace(endSlash, "").split("/");

		retsu.each(pos, i => {
			req.params[i[1]] = coerce(uri[i[0]]);
		});
	}

	route (req, res) {
		let deferred = defer(),
			method = head.test(req.method) ? "GET" : req.method,
			middleware, result;

		let last = err => {
			let allowed, errorCode, status;

			if (!err) {
				// Double checking `this.allows()` (middleware memoization)
				if (!req.allow) {
					allowed = this.allows(req.parsed.pathname, req.host);

					if (allowed) {
						req.allow = allowed;
					}
				}

				deferred.reject(req.allow.indexOf("GET") > -1 ? new Error(405) : new Error(404));
			} else if (!isNaN(res.statusCode) && res.statusCode >= 400) {
				deferred.reject(err);
			} else {
				errorCode = !isNaN(err.message) ? err.message : http.STATUS_CODES[err.message || err] || 500;
				status = res.statusCode >= 400 ? res.statusCode : errorCode;
				deferred.reject(new Error(status));
			}
		};

		let next = err => {
			process.nextTick(() => {
				let arity, iter;

				if (!res._headerSent) {
					iter = middleware.next();
					arity = !iter.done ? utility.getArity(iter.value) : 0;

					if (!iter.done) {
						if (err) {
							do {
								arity = utility.getArity(iter.value);
							} while (arity < 4 && (iter = middleware.next()) && !iter.done);
						}

						if (!iter.done) {
							if (err && arity === 4) {
								try {
									iter.value(err, req, res, next);
								} catch (e) {
									next(e);
								}
							} else if (!err && arity <= 3) {
								try {
									iter.value(req, res, next);
								} catch (e) {
									next(e);
								}
							} else {
								next(); // Error handler in the middle
							}
						} else {
							last(err); // Unhandled error
						}
					} else {
						last(err); // Called next() in the last middleware
					}
				}
			});
		};

		res.on("close", () => {
			this.onclose(req, res);
			deferred.reject(new Error("Connection closed before response was flushed"));
		});

		res.on("finish", () => {
			deferred.resolve();
		});

		this.decorate(req, res);
		result = this.routes(req.parsed.pathname, req.host, method);

		if (result.params) {
			this.params(req, result.pos);
		}

		middleware = result.middleware[Symbol.iterator]();
		next();

		return deferred.promise.then(() => this.onfinish(req, res), err => {
			this.onerror(req, res, err);
			this.onfinish(req, res);
		});
	}

	routes (uri, host, method, override = false) {
		let key = this.hash(method + delimiter + host + delimiter + uri),
			cached = !override ? this.cache.get(key) : undefined,
			params = false,
			allMap, hostMap, middleware, pos, result;

		if (cached) {
			result = cached;
		} else {
			allMap = this.middleware.get(all) || new Map();
			hostMap = this.middleware.get(host) || new Map();
			middleware = [];
			pos = [];

			retsu.each([allMap.get(allMethod), allMap.get(method), hostMap.get(allMethod), hostMap.get(method)], map => {
				if (map) {
					retsu.each(Array.from(map.keys()).filter(route => {
						let now = false,
							valid;

						if (hasParam.test(route) && route.indexOf("(") === -1 && !params) {
							params = true;
							now = true;

							retsu.each(route.replace(startSlash, "").replace(endSlash, "").split("/"), (i, idx) => {
								if (isParam.test(i)) {
									pos.push([idx, i.replace(isParam, "")]);
								}
							});

							route = route.replace(/\/:(\w*)/g, "/(.*)");
						}

						try {
							valid = new RegExp("^" + route + "$", "i").test(uri);
						} catch (e) {
							valid = new RegExp("^" + utility.escape(route) + "$", "i").test(uri);
						}

						if (now && !valid) {
							params = false;
							pos = [];
						}

						return valid;
					}), route => {
						middleware = middleware.concat(map.get(route));
					});
				}
			});

			result = {middleware: middleware, params: params, pos: pos};
			this.cache.set(key, result);
		}

		return result;
	}

	setHost (arg) {
		if (!this.hosts.has(arg)) {
			this.hosts.set(arg, new RegExp("^" + arg.replace(/\*/g, ".*") + "$"));
		}

		return this;
	}

	use (rpath, fn, method, host = all) {
		let lpath = rpath,
			lfn = fn,
			lmethod = method,
			lhost = host,
			mhost, mmethod;

		if (typeof lpath !== "string") {
			lhost = lmethod || lhost;
			lmethod = lfn;
			lfn = lpath;
			lpath = "/.*";
		}

		lmethod = lmethod ? lmethod.toUpperCase() : "GET";

		if (typeof lfn !== "function") {
			throw new Error("Invalid middleware");
		}

		if (!retsu.contains(methods, lmethod)) {
			throw new Error("Invalid HTTP method");
		}

		if (!this.middleware.has(lhost)) {
			this.middleware.set(lhost, new Map());
		}

		mhost = this.middleware.get(lhost);

		if (!mhost.has(lmethod)) {
			mhost.set(lmethod, new Map());
		}

		mmethod = mhost.get(lmethod);

		if (!mmethod.has(lpath)) {
			mmethod.set(lpath, []);
		}

		lfn.hash = this.hash(lfn.toString());
		mmethod.get(lpath).push(lfn);

		return this;
	}
}

module.exports = Woodland;
<commit_msg>Adding a `@todo` for myself<commit_after>"use strict";

const coerce = require("tiny-coerce"),
	defer = require("tiny-defer"),
	lru = require("tiny-lru"),
	path = require("path"),
	http = require("http"),
	parse = require("tiny-parse"),
	mmh3 = require("murmurhash3js").x86.hash32,
	retsu = require("retsu"),
	utility = require(path.join(__dirname, "utility.js")),
	all = "all",
	allMethod = all.toUpperCase(),
	delimiter = ":",
	startSlash = /^\//,
	endSlash = /\/$/,
	isParam = /^:/,
	hasParam = /\/:(\w*)/,
	head = /^(HEAD)$/,
	methods = http.METHODS;

class Woodland {
	constructor (defaultHost, defaultHeaders, cacheSize, seed) {
		this.blacklisted = new Set();
		this.cache = lru(cacheSize);
		this.defaultHost = defaultHost;
		this.defaultHeaders = Reflect.ownKeys(defaultHeaders).map(key => [key, defaultHeaders[key]]);
		this.hosts = new Map();
		this.permissions = lru(cacheSize);
		this.middleware = new Map();
		this.seed = seed;
	}

	allowed (method, uri, host, override = false) {
		return this.routes(uri, host, method, override).middleware.filter(i => !this.blacklisted.has(i.hash || this.hash(i))).length > 0;
	}

	allows (uri, host, override = false) {
		const key = this.hash(host + delimiter + uri);
		let result = !override ? this.permissions.get(key) : undefined,
			list;

		if (override || !result) {
			list = methods.filter(i => this.allowed(i, uri, host, override));

			if (retsu.contains(list, "OPTIONS") && retsu.contains(list, "GET")) {
				list.splice(list.indexOf("OPTIONS"), 1);
			}

			result = list.join(", ").replace("GET", "GET, HEAD, OPTIONS");
			this.permissions.set(key, result);
		}

		return result;
	}

	blacklist (fn) {
		let key;

		if (fn.hash) {
			key = fn.hash;
		} else {
			key = fn.hash = this.hash(fn.toString());
		}

		if (!this.blacklisted.has(key)) {
			this.blacklisted.add(key);
		}

		return this;
	}

	decorate (req, res) {
		let parsed = parse(req),
			remotes = req.headers["x-forwarded-for"] ? req.headers["x-forwarded-for"].split(/\s*,\s*/g) : [req.connection.remoteAddress];

		// Decorating useful hints
		req.body = "";
		req.ip = remotes[remotes.length - 1];
		req.parsed = parsed;
		req.query = parsed.query;
		req.host = this.host(parsed.hostname);
		req.allow = this.allows(req.parsed.pathname, req.host);

		// Express interop
		req.params = {};
		res.header = res.setHeader;
		res.locals = {};

		// Setting headers
		retsu.each(this.defaultHeaders, header => res.header(header[0], header[1]));

		if (req.allow) {
			res.header("Allow", req.allow);
		}
	}

	hash (arg) {
		return mmh3(arg, this.seed);
	}

	host (arg) {
		let result = "";

		retsu.each(this.hosts, (reg, host) => {
			let output = true;

			if (reg.test(arg)) {
				result = host;
				output = false;
			}

			return output;
		});

		return result || this.defaultHost;
	}

	onclose () {}

	onerror (req, res, err) {
		const numeric = !isNaN(err.message),
			status = !isNaN(res.statusCode) && res.statusCode >= 400 ? res.statusCode : numeric ? Number(err.message) : 500,
			body = numeric ? http.STATUS_CODES[status] : err.message;

		res.writeHead(status, {"Content-Type": "text/plain"});
		res.end(body);
	}

	onfinish () {}

	params (req, pos) {
		const uri = req.parsed.path.replace(startSlash, "").replace(endSlash, "").split("/");

		retsu.each(pos, i => {
			req.params[i[1]] = coerce(uri[i[0]]);
		});
	}

	route (req, res) {
		let deferred = defer(),
			method = [head.test(req.method) ? "GET" : req.method], // @todo support implicit GET & explicit OPTIONS
			middleware, result;

		let last = err => {
			let allowed, errorCode, status;

			if (!err) {
				// Double checking `this.allows()` (middleware memoization)
				if (!req.allow) {
					allowed = this.allows(req.parsed.pathname, req.host);

					if (allowed) {
						req.allow = allowed;
					}
				}

				deferred.reject(req.allow.indexOf("GET") > -1 ? new Error(405) : new Error(404));
			} else if (!isNaN(res.statusCode) && res.statusCode >= 400) {
				deferred.reject(err);
			} else {
				errorCode = !isNaN(err.message) ? err.message : http.STATUS_CODES[err.message || err] || 500;
				status = res.statusCode >= 400 ? res.statusCode : errorCode;
				deferred.reject(new Error(status));
			}
		};

		let next = err => {
			process.nextTick(() => {
				let arity, iter;

				if (!res._headerSent) {
					iter = middleware.next();
					arity = !iter.done ? utility.getArity(iter.value) : 0;

					if (!iter.done) {
						if (err) {
							do {
								arity = utility.getArity(iter.value);
							} while (arity < 4 && (iter = middleware.next()) && !iter.done);
						}

						if (!iter.done) {
							if (err && arity === 4) {
								try {
									iter.value(err, req, res, next);
								} catch (e) {
									next(e);
								}
							} else if (!err && arity <= 3) {
								try {
									iter.value(req, res, next);
								} catch (e) {
									next(e);
								}
							} else {
								next(); // Error handler in the middle
							}
						} else {
							last(err); // Unhandled error
						}
					} else {
						last(err); // Called next() in the last middleware
					}
				}
			});
		};

		res.on("close", () => {
			this.onclose(req, res);
			deferred.reject(new Error("Connection closed before response was flushed"));
		});

		res.on("finish", () => {
			deferred.resolve();
		});

		this.decorate(req, res);
		result = this.routes(req.parsed.pathname, req.host, method);

		if (result.params) {
			this.params(req, result.pos);
		}

		middleware = result.middleware[Symbol.iterator]();
		next();

		return deferred.promise.then(() => this.onfinish(req, res), err => {
			this.onerror(req, res, err);
			this.onfinish(req, res);
		});
	}

	routes (uri, host, method, override = false) {
		let key = this.hash(method + delimiter + host + delimiter + uri),
			cached = !override ? this.cache.get(key) : undefined,
			params = false,
			allMap, hostMap, middleware, pos, result;

		if (cached) {
			result = cached;
		} else {
			allMap = this.middleware.get(all) || new Map();
			hostMap = this.middleware.get(host) || new Map();
			middleware = [];
			pos = [];

			retsu.each([allMap.get(allMethod), allMap.get(method), hostMap.get(allMethod), hostMap.get(method)], map => {
				if (map) {
					retsu.each(Array.from(map.keys()).filter(route => {
						let now = false,
							valid;

						if (hasParam.test(route) && route.indexOf("(") === -1 && !params) {
							params = true;
							now = true;

							retsu.each(route.replace(startSlash, "").replace(endSlash, "").split("/"), (i, idx) => {
								if (isParam.test(i)) {
									pos.push([idx, i.replace(isParam, "")]);
								}
							});

							route = route.replace(/\/:(\w*)/g, "/(.*)");
						}

						try {
							valid = new RegExp("^" + route + "$", "i").test(uri);
						} catch (e) {
							valid = new RegExp("^" + utility.escape(route) + "$", "i").test(uri);
						}

						if (now && !valid) {
							params = false;
							pos = [];
						}

						return valid;
					}), route => {
						middleware = middleware.concat(map.get(route));
					});
				}
			});

			result = {middleware: middleware, params: params, pos: pos};
			this.cache.set(key, result);
		}

		return result;
	}

	setHost (arg) {
		if (!this.hosts.has(arg)) {
			this.hosts.set(arg, new RegExp("^" + arg.replace(/\*/g, ".*") + "$"));
		}

		return this;
	}

	use (rpath, fn, method, host = all) {
		let lpath = rpath,
			lfn = fn,
			lmethod = method,
			lhost = host,
			mhost, mmethod;

		if (typeof lpath !== "string") {
			lhost = lmethod || lhost;
			lmethod = lfn;
			lfn = lpath;
			lpath = "/.*";
		}

		lmethod = lmethod ? lmethod.toUpperCase() : "GET";

		if (typeof lfn !== "function") {
			throw new Error("Invalid middleware");
		}

		if (!retsu.contains(methods, lmethod)) {
			throw new Error("Invalid HTTP method");
		}

		if (!this.middleware.has(lhost)) {
			this.middleware.set(lhost, new Map());
		}

		mhost = this.middleware.get(lhost);

		if (!mhost.has(lmethod)) {
			mhost.set(lmethod, new Map());
		}

		mmethod = mhost.get(lmethod);

		if (!mmethod.has(lpath)) {
			mmethod.set(lpath, []);
		}

		lfn.hash = this.hash(lfn.toString());
		mmethod.get(lpath).push(lfn);

		return this;
	}
}

module.exports = Woodland;
<|endoftext|>


<commit_before>/**
 * Daimyo - utilities for dealing with XML
 * Copyright (c)2011, by Branko Vukelic <branko@herdhound.com>
 * Licensed under MIT license (see LICENSE)
 */

var xmlutils = exports;

/**
 * Generate regex for parsing a single tag
 *
 * @param {String} tagName The exact tag name as it appears in the XML
 * @returns {RegExp} Regular expresson object that will parse the given tag
 * @private
 */
function getTagRe(tagName) {
  return new RegExp('<' + tagName + '[^>]*>([^<]*)<', 'g');
}

/**
 * Run a regex multiple times until matches are exhausted
 *
 * @param {String} s Source string
 * @param {RegExp} rxp RegExp object to run on the source
 * @returns {Array} Array of results
 * @private
 */
function matchAll(s, rxp) {
  var matches = [];
  var match = rxp.exec(s);

  while (match) {
    matches.push(match[1]);
    match = rxp.exec(s);
  }

  return matches;
}

/**
 * Convert a string to integer
 *
 * @param {String} s String to be parsed
 * @returns {Integer} Converted integer
 */
xmlutils.toInt = function(s) {
  return parseInt(s, 10);
};

/**
 * Convert a string to Date object
 *
 * @param {String} s String to be parsed
 * @returns {Date} Converted date
 */
xmlutils.toDate = function(s) {
  return new Date(s);
};

/**
 * Convert a string to Bool
 *
 * This function treats `'true'` as `true`, and everything else as false.
 *
 * @param {String} s String to be parsed
 * @returns {Bool} Converted boolean
 */
xmlutils.toBool = function(s) {
  return s === 'true' ? true : false;
};

/**
 * Pass-through function that does nothing
 *
 * @param {String} s Strning to be passed through
 * @returns {String} Same string that came in
 */
xmlutils.toString = function(s) {
  return s;
};

/**
 * Extract data from XML string using recipe mappings
 *
 * Recipe object contains a mapping between tag names and coercion functions
 * like `toInt` and `toDate`. Each key in the recipe object will be treated
 * as a valid tag name, and searched for within the XML. Data found within the
 * XML string will be coerced and assigned to a key in the result object. The
 * key name in the result object will match the key name from the recipe
 * object.
 *
 * An example recipe object:
 *
 *     {
 *       'payment_method_token': xmlutils.toString,
 *       'created_at': xmlutils.toDate,
 *       ....
 *     }
 *
 * @param {String} xml The source XML string
 * @param {Object} recipe The recipe object
 * @returns {Object} Name-value pairs of extracted data
 */
xmlutils.extractData = function(xml, recipe) {
  var result = {};
  Object.keys(recipe).forEach(function(key) {
    // Get the Regex for the recipe
    var rxp = getTagRe(key);
    var matches = matchAll(xml, rxp);

    if (matches.length === 1) {
      result[key] = recipe[key](matches[0]);
    } else if (matches.length > 1) {
      result[key] = [];
      matches.forEach(function(match) {
        result[key].push(recipe[key](match));
      });
    }
  });

  return result;
};

/**
 * ## xmlutils.hasMessages(xml)
 * *Checks the XML to see if there is a `<messsages>` block*
 *
 * Returns `true` if there is a `<messages>` block.
 *
 * @param {String} xml The XML string
 * @returns {Boolean} Whether it found the `<messages>` block
 */
xmlutils.hasMessages = function(xml) {
  return Boolean((/<messages[^>]*>/).exec(xml));
};

/**
 * Extract messages from XML string
 *
 * The messages can be of the following classes:
 * - _error_: errors and declines
 * - _info_: success and other information
 *
 * The messages will also have a context in which it was transmitted, and the
 * message that describes the details.
 *
 * The return object may look like this:
 *
 *     {
 *       error: [{'input.card_number': 'failed_checksum'}]
 *     }
 *
 * @param {String} xml The XML string to be parsed
 * @returns {Array} Array of error messages.
 */
xmlutils.extractMessages = function(xml) {
  var messageRe = /<message ([^>]+)>/g;
  var classRe = /class="([^"]+)"/;
  var contextRe = /context="([^"]+)"/;
  var keyRe = /key="([^"]+)"/;
  var attrs;
  var message;
  var messages = [];
  var match = messageRe.exec(xml);

  while(match) {
    attrs = match[1];
    message = {};
    message.cls = classRe.exec(attrs)[1];
    message.context = contextRe.exec(attrs)[1];
    message.key = keyRe.exec(attrs)[1];
    messages.push(message);
    match = messageRe.exec(xml);
  }

  return messages;
};

/**
 * Decamelizes a string
 *
 * Converts 'CamelCase' to 'camel_case'.
 *
 * @param {String} s String to convert
 * @returns {String} Decamelized string
 */
xmlutils.decamelize = function(s) {
  s = s.replace(/^[A-Z]/, function(match) {
    return match.toLowerCase();
  });
  s = s.replace(/[A-Z]/g, function(match) {
    return '_' + match.toLowerCase();
  });
  return s;
};

/**
 * Shallow conversion of JavaScript object to XML
 *
 * It converts each key to a single XML node and converts the contents of the
 * key to a text node by calling `toString` on it.
 *
 * Optionally, the whole XML string can be wrapped in a top-level tag.
 *
 * This function _does not_ care about the order of keys, so if you need the
 * nodes to be in a certain order, you should supply an array of keys.
 *
 * @param {Object} o Object to be converted
 * @param {String} [topLevel] Top level tag
 * @param {Array} [keys] Array of keys to use so that nodes are ordered
 * @returns {String} XML version of the object
 */
xmlutils.toXML = function(o, topLevel, keys) {
  var xml = '';

  // Was topLevel arg skipped?
  if (typeof topLevel != 'string') {
    keys = topLevel;
    topLevel = null;
  } else {
    xml += '<' + xmlutils.decamelize(topLevel) + '>\n';
  }

  keys = keys || Object.keys(o);

  keys.forEach(function(key) {
    var tagName = xmlutils.decamelize(key);
    xml += '<' + tagName + '>' + o[key].toString() + '</' + tagName + '>\n';
  });

  if (topLevel) {
    xml += '</' + xmlutils.decamelize(topLevel) + '>\n';
  }

  return xml;
};
<commit_msg>Reformatted xmlutils docs to match the project conventions<commit_after>/**
 * # xmlutils
 *
 * Copyright (c)2011, by Branko Vukelic <branko@herdhound.com>
 *
 * Utitilities for parsing Samurai XML responses. These utilities are not
 * general-purpose XML parsers and generators. Some of them can be quite useful
 * outside the Daimyo context, but there's no guarantee of that.
 *
 * In general, you shouldn't need to touch these methods yoursef ever, unless
 * you are considering developing Daimyo.
 *
 * @author Branko Vukelic <branko@herdhound.com>
 * @license MIT (see LICENSE)
 */

var xmlutils = exports;

/**
 * ## getTagRe(tagName)
 * *Generate regex for parsing a single tag*
 *
 * @param {String} tagName The exact tag name as it appears in the XML
 * @returns {RegExp} Regular expresson object that will parse the given tag
 * @private
 */
function getTagRe(tagName) {
  return new RegExp('<' + tagName + '[^>]*>([^<]*)<', 'g');
}

/**
 * # matchAll(s, rxp)
 * *Run a regex multiple times until matches are exhausted*
 *
 * @param {String} s Source string
 * @param {RegExp} rxp RegExp object to run on the source
 * @returns {Array} Array of results
 * @private
 */
function matchAll(s, rxp) {
  var matches = [];
  var match = rxp.exec(s);

  while (match) {
    matches.push(match[1]);
    match = rxp.exec(s);
  }

  return matches;
}

/**
 * ## xmlutils.toInt(s)
 * *Convert a string to integer*
 *
 * @param {String} s String to be parsed
 * @returns {Integer} Converted integer
 */
xmlutils.toInt = function(s) {
  return parseInt(s, 10);
};

/**
 * ## xmlutils.toDate(s)
 * *Convert a string to Date object*
 *
 * @param {String} s String to be parsed
 * @returns {Date} Converted date
 */
xmlutils.toDate = function(s) {
  return new Date(s);
};

/**
 * ## xmlutils.toBool(s)
 * *Convert a string to Bool*
 *
 * This function treats `'true'` as `true`, and everything else as false.
 *
 * @param {String} s String to be parsed
 * @returns {Bool} Converted boolean
 */
xmlutils.toBool = function(s) {
  return s === 'true' ? true : false;
};

/**
 * ## xmlutils.toString(s)
 * *Pass-through function that does nothing*
 *
 * @param {String} s Strning to be passed through
 * @returns {String} Same string that came in
 */
xmlutils.toString = function(s) {
  return s;
};

/**
 * ## xmlutils.extractData(xml, recipe)
 * *Extract data from XML string using recipe mappings*
 *
 * Recipe object contains a mapping between tag names and coercion functions
 * like `xmlutils.toInt` and `xmlutils.toDate`. Each key in the recipe object
 * will be treated as a valid tag name, and searched for within the XML. Data
 * found within the XML string will be coerced and assigned to a key in the
 * result object. The key name in the result object will match the key name
 * from the recipe object.
 *
 * An example recipe object:
 *
 *     {
 *       'payment_method_token': xmlutils.toString,
 *       'created_at': xmlutils.toDate,
 *       ....
 *     }
 *
 * @param {String} xml The source XML string
 * @param {Object} recipe The recipe object
 * @returns {Object} Name-value pairs of extracted data
 */
xmlutils.extractData = function(xml, recipe) {
  var result = {};
  Object.keys(recipe).forEach(function(key) {
    // Get the Regex for the recipe
    var rxp = getTagRe(key);
    var matches = matchAll(xml, rxp);

    if (matches.length === 1) {
      result[key] = recipe[key](matches[0]);
    } else if (matches.length > 1) {
      result[key] = [];
      matches.forEach(function(match) {
        result[key].push(recipe[key](match));
      });
    }
  });

  return result;
};

/**
 * ## xmlutils.hasMessages(xml)
 * *Checks the XML to see if there is a `<messsages>` block*
 *
 * Returns `true` if there is a `<messages>` block.
 *
 * @param {String} xml The XML string
 * @returns {Boolean} Whether it found the `<messages>` block
 */
xmlutils.hasMessages = function(xml) {
  return Boolean((/<messages[^>]*>/).exec(xml));
};

/**
 * ##xmlutils.extractMessages(xml)
 * *Extract messages from XML string*
 *
 * The messages can be of the following classes:
 *
 *  + _error_: errors and declines
 *  + _info_: success and other information
 *
 * The messages will also have a context in which it was transmitted, and the
 * message that describes the details.
 *
 * The return object may look like this:
 *
 *     {
 *       error: [{'input.card_number': 'failed_checksum'}]
 *     }
 *
 * @param {String} xml The XML string to be parsed
 * @returns {Array} Array of error messages.
 */
xmlutils.extractMessages = function(xml) {
  var messageRe = /<message ([^>]+)>/g;
  var classRe = /class="([^"]+)"/;
  var contextRe = /context="([^"]+)"/;
  var keyRe = /key="([^"]+)"/;
  var attrs;
  var message;
  var messages = [];
  var match = messageRe.exec(xml);

  while(match) {
    attrs = match[1];
    message = {};
    message.cls = classRe.exec(attrs)[1];
    message.context = contextRe.exec(attrs)[1];
    message.key = keyRe.exec(attrs)[1];
    messages.push(message);
    match = messageRe.exec(xml);
  }

  return messages;
};

/**
 * ## xmlutils.decamelize(s)
 * *Converts 'CamelCase' to 'camel_case'*
 *
 * @param {String} s String to convert
 * @returns {String} Decamelized string
 */
xmlutils.decamelize = function(s) {
  s = s.replace(/^[A-Z]/, function(match) {
    return match.toLowerCase();
  });
  s = s.replace(/[A-Z]/g, function(match) {
    return '_' + match.toLowerCase();
  });
  return s;
};

/**
 * ## xmlutils.toXML(o, [topLevel], [keys])
 * *Shallow conversion of JavaScript object to XML*
 *
 * This method converts each key to a single XML node and converts the contents
 * of the key to a text node by calling `toString` on it.
 *
 * Optionally, the whole XML string can be wrapped in a top-level tag.
 *
 * This function _does not_ care about the order of keys, so if you need the
 * nodes to be in a certain order, you should supply an array of keys.
 *
 * @param {Object} o Object to be converted
 * @param {String} [topLevel] Top level tag
 * @param {Array} [keys] Array of keys to use so that nodes are ordered
 * @returns {String} XML version of the object
 */
xmlutils.toXML = function(o, topLevel, keys) {
  var xml = '';

  // Was topLevel arg skipped?
  if (typeof topLevel != 'string') {
    keys = topLevel;
    topLevel = null;
  } else {
    xml += '<' + xmlutils.decamelize(topLevel) + '>\n';
  }

  keys = keys || Object.keys(o);

  keys.forEach(function(key) {
    var tagName = xmlutils.decamelize(key);
    xml += '<' + tagName + '>' + o[key].toString() + '</' + tagName + '>\n';
  });

  if (topLevel) {
    xml += '</' + xmlutils.decamelize(topLevel) + '>\n';
  }

  return xml;
};
<|endoftext|>


<commit_before>var ZipmentsResource = require('./ZipmentsResource');

Zipments.DEFAULT_HOST = 'api.zipments.com';
Zipments.DEFAULT_PORT = '443';
Zipments.DEFAULT_BASE_PATH = '/v1/';
Zipments.DEFAULT_TIMEOUT = require('http').createServer().timeout;

function Zipments(key){

  if (!(this instanceof Zipments)) {
    return new Zipments(key);
  }

  this._api = {
    auth: null,
    host: Zipments.DEFAULT_HOST,
    port: Zipments.DEFAULT_PORT,
    basePath: Zipments.DEFAULT_BASE_PATH,
    timeout: Zipments.DEFAULT_TIMEOUT,
    dev: false
  };

  this._prepResources();
  this.setApiKey(key);
}

Zipments.prototype = {

  getApiField: function(key) {
    return this._api[key];
  },

  setApiKey: function(key) {
    if (key){
      this._setApiField('auth', key);
    }
  },

  _setApiField: function(key) {
    this._api[key] = field;
  },

  _prepResources: function() {
    this.jobs = new ZipmentsResource(this);
  }

};

module.exports = Zipments;<commit_msg>proper setApiField with value arg<commit_after>var ZipmentsResource = require('./ZipmentsResource');

Zipments.DEFAULT_HOST = 'api.zipments.com';
Zipments.DEFAULT_PORT = '443';
Zipments.DEFAULT_BASE_PATH = '/v1/';
Zipments.DEFAULT_TIMEOUT = require('http').createServer().timeout;

function Zipments(key){

  if (!(this instanceof Zipments)) {
    return new Zipments(key);
  }

  this._api = {
    auth: null,
    host: Zipments.DEFAULT_HOST,
    port: Zipments.DEFAULT_PORT,
    basePath: Zipments.DEFAULT_BASE_PATH,
    timeout: Zipments.DEFAULT_TIMEOUT,
    dev: false
  };

  this._prepResources();
  this.setApiKey(key);
}

Zipments.prototype = {

  getApiField: function(key) {
    return this._api[key];
  },

  setApiKey: function(key) {
    if (key){
      this._setApiField('auth', key);
    }
  },

  _setApiField: function(key, value) {
    this._api[key] = value;
  },

  _prepResources: function() {
    this.jobs = new ZipmentsResource(this);
  }

};

module.exports = Zipments;<|endoftext|>


<commit_before>/*
 * Copyright (c) Novedia Group 2012.
 *
 *     This file is part of Hubiquitus.
 *
 *     Hubiquitus is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     Hubiquitus is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with Hubiquitus.  If not, see <http://www.gnu.org/licenses/>.
 */

var status = require('../codes.js').hResultStatus;
var xmpp = require('node-xmpp');

var hPublish = function(){
};

/**
 * hPublish publishes a hMessage to a channel and, if selected, will store the message in Mongo.
 * Once the execution finishes cb is called.
 * @param hCommand - hCommand received with cmd = 'hPublish'
 * @param context - Auxiliary functions,attrs from the controller/ db models.
 * @param cb(status, result) - function that receives args:
 *    status: //Constant from var status to indicate the result of the hCommand
 *    result: undefined if ok.
 */
hPublish.prototype.exec = function(hCommand, context, cb){
    var self = this;
    var hMessage = hCommand.params;
    var paths = ['chid', 'convid', 'type', 'priority', 'relevance', 'payload',
        'location', 'author', 'publisher', 'published', 'headers'];

    if( !hMessage || typeof hMessage !== 'object'){
        cb(status.MISSING_ATTR, 'invalid params object received');
        return;
    }

    var publisher = hMessage.publisher.replace(/\/.*/,'');

    //Test sender against publisher (ignore the resource from both of them)
    if( hCommand.sender.replace(/\/.*/,'') != publisher ){
        cb(status.NOT_AUTHORIZED, 'owner does not match sender');
        return;
    }

    //Test for missing chid
    if( !hMessage.chid ){
        cb(status.MISSING_ATTR, 'hMessage missing chid');
        return;
    }

    var channel = context.cache.hChannels[hMessage.chid];
    if(!channel || channel.participants.indexOf(publisher) == -1){
        cb(status.NOT_AUTHORIZED, 'error publishing to channel with current credentials');
        return;
    }

    var instance = hMessage['transient'] === false ? new context.models.hMessage() : {};

    //Fill default values from channel
    instance.priority = channel.priority;
    if(channel.location)
        instance.location = JSON.parse(JSON.stringify(channel.location)); //Deep copy without mongo attributes.

    //Copy values from received message
    for(var i = 0; i < paths.length; i++)
        if(hMessage[paths[i]])
            instance[paths[i]] = hMessage[paths[i]];

    //Fill values
    instance.msgid = UUID();
    instance.convid = instance.convid || instance.msgid;
    instance.published = new Date();
    instance.headers = instance.headers || [];

    //If hAlert force at least minimum priority
    if( /hAlert/i.test(instance.type) && instance.priority < 2 )
        instance.priority = 2;

    //If not transient store it (If it does not exist it is transient)
    if(hMessage['transient'] === false)
        instance.save(function(errSave){
            if(!errSave)
                log.info('Saved publication ' + instance.msgid + ' correctly');
            else
                log.warn('Error saving publication ' + instance.msgid, errSave);
        });

    //Publish it to XMPP
    self.publishXMPP(instance, context, function(err){
        log.info('Published ' + instance.msgid + ' correctly');
        cb(status.OK);
    })
};

hPublish.prototype.publishXMPP = function(hMessage, context, cb){
    //http://xmpp.org/extensions/xep-0060.html#publisher-publish
    var attrs = {
        type: 'set',

        //Because our jid is well formatted there is no risk doing this
        to: 'pubsub.' + context.jid.replace(/\w+\./,'')
    };

    var content = new xmpp.Element('pubsub', {xmlns: 'http://jabber.org/protocol/pubsub'})
        .c('publish', {node : hMessage.chid})
        .c('item')
        .c('entry', {xmlns: 'http://jabber.org/protocol/pubsub'}).t(JSON.stringify(hMessage));

    context.sendIQ(attrs, content, function(stanza){
        cb();
    });

};

//Taken from https://gist.github.com/982883
function UUID(a){return a?(a^Math.random()*16>>a/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,UUID)}

exports.Command = hPublish;<commit_msg>Verifying publisher before publishing<commit_after>/*
 * Copyright (c) Novedia Group 2012.
 *
 *     This file is part of Hubiquitus.
 *
 *     Hubiquitus is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     Hubiquitus is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with Hubiquitus.  If not, see <http://www.gnu.org/licenses/>.
 */

var status = require('../codes.js').hResultStatus;
var xmpp = require('node-xmpp');

var hPublish = function(){
};

/**
 * hPublish publishes a hMessage to a channel and, if selected, will store the message in Mongo.
 * Once the execution finishes cb is called.
 * @param hCommand - hCommand received with cmd = 'hPublish'
 * @param context - Auxiliary functions,attrs from the controller/ db models.
 * @param cb(status, result) - function that receives args:
 *    status: //Constant from var status to indicate the result of the hCommand
 *    result: undefined if ok.
 */
hPublish.prototype.exec = function(hCommand, context, cb){
    var self = this;
    var hMessage = hCommand.params;
    var paths = ['chid', 'convid', 'type', 'priority', 'relevance', 'payload',
        'location', 'author', 'publisher', 'published', 'headers'];

    if( !hMessage || typeof hMessage !== 'object'){
        cb(status.MISSING_ATTR, 'invalid params object received');
        return;
    }

    if( !hMessage.publisher ){
        cb(status.MISSING_ATTR, 'hMessage missing publisher');
        return;
    }

    var publisher = hMessage.publisher.replace(/\/.*/,'');

    //Test sender against publisher (ignore the resource from both of them)
    if( hCommand.sender.replace(/\/.*/,'') != publisher ){
        cb(status.NOT_AUTHORIZED, 'owner does not match sender');
        return;
    }

    //Test for missing chid
    if( !hMessage.chid ){
        cb(status.MISSING_ATTR, 'hMessage missing chid');
        return;
    }

    var channel = context.cache.hChannels[hMessage.chid];
    if(!channel || channel.participants.indexOf(publisher) == -1){
        cb(status.NOT_AUTHORIZED, 'error publishing to channel with current credentials');
        return;
    }

    var instance = hMessage['transient'] === false ? new context.models.hMessage() : {};

    //Fill default values from channel
    instance.priority = channel.priority;
    if(channel.location)
        instance.location = JSON.parse(JSON.stringify(channel.location)); //Deep copy without mongo attributes.

    //Copy values from received message
    for(var i = 0; i < paths.length; i++)
        if(hMessage[paths[i]])
            instance[paths[i]] = hMessage[paths[i]];

    //Fill values
    instance.msgid = UUID();
    instance.convid = instance.convid || instance.msgid;
    instance.published = new Date();
    instance.headers = instance.headers || [];

    //If hAlert force at least minimum priority
    if( /hAlert/i.test(instance.type) && instance.priority < 2 )
        instance.priority = 2;

    //If not transient store it (If it does not exist it is transient)
    if(hMessage['transient'] === false)
        instance.save(function(errSave){
            if(!errSave)
                log.info('Saved publication ' + instance.msgid + ' correctly');
            else
                log.warn('Error saving publication ' + instance.msgid, errSave);
        });

    //Publish it to XMPP
    self.publishXMPP(instance, context, function(err){
        log.info('Published ' + instance.msgid + ' correctly');
        cb(status.OK);
    })
};

hPublish.prototype.publishXMPP = function(hMessage, context, cb){
    //http://xmpp.org/extensions/xep-0060.html#publisher-publish
    var attrs = {
        type: 'set',

        //Because our jid is well formatted there is no risk doing this
        to: 'pubsub.' + context.jid.replace(/\w+\./,'')
    };

    var content = new xmpp.Element('pubsub', {xmlns: 'http://jabber.org/protocol/pubsub'})
        .c('publish', {node : hMessage.chid})
        .c('item')
        .c('entry', {xmlns: 'http://jabber.org/protocol/pubsub'}).t(JSON.stringify(hMessage));

    context.sendIQ(attrs, content, function(stanza){
        cb();
    });

};

//Taken from https://gist.github.com/982883
function UUID(a){return a?(a^Math.random()*16>>a/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,UUID)}

exports.Command = hPublish;<|endoftext|>


<commit_before>/**
 * Module dependencies
 */
var _ = require('lodash')
	, fsx = require('fs-extra')
	, report = require('reportback')()
	, FileHelper = require('../file');

/**
 * Copy file from one place to another.
 *
 * @option {String}    rootPath
 * @option {String}    templatePath
 * @option {Boolean}   force[=false]
 *
 * @sb.success
 * @sb.error
 * @sb.alreadyExists
 * @sb.invalid
 */
module.exports = function (options, sb) {
	sb = report.extend({
		alreadyExists: sb.error,
		invalid: sb.error
	});

	fs.readFile(options.templatePath, 'utf8', function(err, contents) {
		if (err) return sb,error(err);
		return FileHelper(_.merge(options, { contents: contents }), sb);
	});
};<commit_msg>Fixed a couple of issues with copy.js<commit_after>/**
 * Module dependencies
 */
var _ = require('lodash')
	, fs = require('fs-extra')
	, report = require('reportback')()
	, FileHelper = require('../file');

/**
 * Copy file from one place to another.
 *
 * @option {String}    rootPath
 * @option {String}    templatePath
 * @option {Boolean}   force[=false]
 *
 * @sb.success
 * @sb.error
 * @sb.alreadyExists
 * @sb.invalid
 */
module.exports = function (options, sb) {
	sb = report.extend({
		alreadyExists: sb.error,
		invalid: sb.error
	});

	fs.readFile(options.templatePath, 'utf8', function(err, contents) {
		if (err) return sb.error(err);
		return FileHelper(_.merge(options, { contents: contents }), sb);
	});
};<|endoftext|>


<commit_before>var urlParser = require("url");

var $ = require("cheerio");

var request = require("./utils/request");
var error = require("./utils/errors");

/**
 * get favicon path or buffer
 * @param  {[type]}   domain   [description]
 * @param  {Function} callback [description]
 * @return {[type]}            [description]
 */
exports.favicon = function(domain, callback) {
  if(typeof domain !== "string" || typeof callback !== "function") {
    return callback(error.MISSING_PARAMS());
  }
  if(domain.substring(0, 4) !== "http") {
    domain = "http://" + domain;
  }
  followRedirectUrl(domain, function(err, url) {
    url = url.replace(/\/$/, "")
    if(err) { return callback(err); }
    getFaviconPath(url, function(err, path, buffer) {
      if(err) { return callback(err); }

      if(path && buffer) {
        return callback(null, path, buffer);
      }
      getFaviconLink(url, function(err, path, buffer) {
        if(err) { return callback(err); }

        if(path && buffer) {
          return callback(null, path, buffer);
        }
        callback();
      });
    });
  });
};

// 获取Favicon.ico
function getFaviconPath(domain, callback) {
  callback = callback || function() {};
  if(!domain) {
    return callback(error.DOMAIN_CANNOT_NULL());
  }

  domain = domain + "/favicon.ico";
  request({ url: domain, method: "GET", encoding: null },
    function(err, resp, body) {

    if(err) { return callback(error.REQUEST_ERROR()); }

    if(resp && resp.statusCode == 200 && body) {
      return callback(null, domain, body);
    }
    callback();
  });
};

// 获取Link rel=icon的地址
function getFaviconLink(domain, callback) {
  callback = callback || function() {};
  if(!domain) { return callback(error.DOMAIN_CANNOT_NULL()); }

  request.get(domain, function(err, result, body) {
    if(err) { return callback(error.REQUEST_ERROR(err)); }

    var favicon = $(body).find("link[rel*='icon']").attr("href");
    var path = /^http/.test(favicon) ? favicon : (domain + favicon);
    favicon ? request({
      url: path,
      method: "GET",
      encoding: null
    }, function(err, resp, body) {
      if(err) { return callback(error.REQUEST_ERROR()); }

      if(resp && resp.statusCode == 200 && body) {
        return callback(null, path, body);
      }
      callback();
    }) : callback();
  });
};

// 追踪30X的最终地址
function followRedirectUrl(url, callback) {
  if(!url) {
    return callback(error.CANNOT_GET_ICON());
  }
  request.get(url, {
    followRedirect: false
  }, function(err, resp) {
    if(err) {
      return callback(error.REQUEST_ERROR(err));
    }
    if(resp && resp.statusCode > 300 && resp.statusCode < 400
        && resp.headers && resp.headers.location) {
      followRedirectUrl(resp.headers.location, callback);
    }else {
      var urlobj = urlParser.parse(url);
      var path = urlobj.protocol + "//" + urlobj.host + urlobj.pathname;
      callback(null, path);
    }
  });
};<commit_msg>fix bug<commit_after>var urlParser = require("url");

var $ = require("cheerio");

var request = require("./utils/request");
var error = require("./utils/errors");

/**
 * get favicon path or buffer
 * @param  {[type]}   domain   [description]
 * @param  {Function} callback [description]
 * @return {[type]}            [description]
 */
exports.favicon = function(domain, callback) {
  if(typeof domain !== "string" || typeof callback !== "function") {
    return callback(error.MISSING_PARAMS());
  }
  if(domain.substring(0, 4) !== "http") {
    domain = "http://" + domain;
  }
  followRedirectUrl(domain, function(err, url) {
    if(err) { return callback(err); }
    if(url) {
      url = url.replace(/\/$/, "")
    }
    getFaviconPath(url, function(err, path, buffer) {
      if(err) { return callback(err); }

      if(path && buffer) {
        return callback(null, path, buffer);
      }
      getFaviconLink(url, function(err, path, buffer) {
        if(err) { return callback(err); }

        if(path && buffer) {
          return callback(null, path, buffer);
        }
        callback();
      });
    });
  });
};

// 获取Favicon.ico
function getFaviconPath(domain, callback) {
  callback = callback || function() {};
  if(!domain) {
    return callback(error.DOMAIN_CANNOT_NULL());
  }

  domain = domain + "/favicon.ico";
  request({ url: domain, method: "GET", encoding: null },
    function(err, resp, body) {

    if(err) { return callback(error.REQUEST_ERROR()); }

    if(resp && resp.statusCode == 200 && body) {
      return callback(null, domain, body);
    }
    callback();
  });
};

// 获取Link rel=icon的地址
function getFaviconLink(domain, callback) {
  callback = callback || function() {};
  if(!domain) { return callback(error.DOMAIN_CANNOT_NULL()); }

  request.get(domain, function(err, result, body) {
    if(err) { return callback(error.REQUEST_ERROR(err)); }

    var favicon = $(body).find("link[rel*='icon']").attr("href");
    var path = /^http/.test(favicon) ? favicon : (domain + favicon);
    favicon ? request({
      url: path,
      method: "GET",
      encoding: null
    }, function(err, resp, body) {
      if(err) { return callback(error.REQUEST_ERROR()); }

      if(resp && resp.statusCode == 200 && body) {
        return callback(null, path, body);
      }
      callback();
    }) : callback();
  });
};

// 追踪30X的最终地址
function followRedirectUrl(url, callback) {
  if(!url) {
    return callback(error.CANNOT_GET_ICON());
  }
  request.get(url, {
    followRedirect: false
  }, function(err, resp) {
    if(err) {
      return callback(error.REQUEST_ERROR(err));
    }
    if(resp && resp.statusCode > 300 && resp.statusCode < 400
        && resp.headers && resp.headers.location) {
      followRedirectUrl(resp.headers.location, callback);
    }else {
      var urlobj = urlParser.parse(url);
      var path = urlobj.protocol + "//" + urlobj.host + urlobj.pathname;
      callback(null, path);
    }
  });
};<|endoftext|>


<commit_before>var Initializer = require("../initializer");

Initializer.add('startup', 'stex.redis', ['stex.config', 'stex.newrelic'], function(stex) {
  var Promise     = require("bluebird");
  var redis       = Promise.promisifyAll(require("redis"));
  var redisConf = conf.get("redis");
  if(!redisConf) {
    return;
  }

  stex.redis = redis.createClient(redisConf.port || 6379, redisConf.host, {no_ready_check: true});

  if (redisConf.password) {
    stex.redis.auth(redisConf.password, function() {console.log("Connected!");});
  }

  return stex.redis.selectAsync(redisConf.db || 0);
});

Initializer.add('shutdown', 'stex.redis', function(stex) {
  if(stex.redis) {
    stex.redis.quit();
  }
});
<commit_msg>support auth and noauth for redis<commit_after>var Initializer = require("../initializer");

Initializer.add('startup', 'stex.redis', ['stex.config', 'stex.newrelic'], function(stex) {
  var Promise     = require("bluebird");
  var redis       = Promise.promisifyAll(require("redis"));
  var redisConf = conf.get("redis");
  if(!redisConf) {
    return;
  }
  var options = null;
  if (redisConf.password) {
    options = { no_ready_check: true };
  }
  stex.redis = redis.createClient(redisConf.port || 6379, redisConf.host, options);

  if (redisConf.password) {
    stex.redis.auth(redisConf.password, function() {});
  }

  return stex.redis.selectAsync(redisConf.db || 0);
});

Initializer.add('shutdown', 'stex.redis', function(stex) {
  if(stex.redis) {
    stex.redis.quit();
  }
});
<|endoftext|>


<commit_before>(function (factory) {
    module.exports = factory(
        require('./core'),
        require('./object'),
        require('./type'),
        require('./int'),
        require('./list'),
        require('./str'),
        require('./bool'),
        require('./exceptions')
    );
}).call(this, function (core, _object, _type, _int, _list, _str, _bool,
                        _exceptions) {
    'use strict';

    var object, objectproto;
    var type;
    var int, intproto, int_cons;
    var list, listproto, list_cons;
    var str, strproto, str_cons;
    var bool, boolproto, bool_cons, not, eq, True, False;
    var BaseException, Exception, TypeError, AttributeError, ValueError;
    var baseexcproto;

    object = _object.object;
    type = _type.type;
    int = _int.int;
    int_cons = _int.int_cons;
    list = _list.list;
    list_cons = _list.list_cons;
    str = _str.str;
    str_cons = _str.str_cons;
    bool = _bool.bool;
    bool_cons = _bool.bool_cons;
    not = _bool.not;
    eq = _bool.eq;
    True = _bool.True;
    False = _bool.False;
    BaseException = _exceptions.BaseException;
    Exception = _exceptions.Exception;
    TypeError = _exceptions.TypeError;
    AttributeError = _exceptions.AttributeError;
    ValueError = _exceptions.ValueError;

    // object class enrichment
    object.__name__ = str_cons('object');
    object.__class__ = type;
    objectproto = object.prototype;
    objectproto.__doc__ = str_cons('The most base type');

    objectproto.__repr__ = function () {
        return str_cons('<' + this.__class__.__name__.__string__ + ' object>');
    };

    objectproto.__str__ = function () {
        return this.__repr__();
    };

    // int class enrichment
    int.__name__ = str_cons('int');
    intproto = int.prototype;

    intproto.__repr__ = function () {
        return str_cons('' + this.__number__);
    };

    intproto.__bool__ = function () {
        return this.__number__ !== 0 ? True : False;
    };

    intproto.__eq__ = function (b) {
        //TODO: typeerror
        if (b instanceof int) {
            return this.__number__ === b.__number__ ? True : False;
        } else {
            return False;
        }
    };

    // list class enrichment
    list.__name__ = str_cons('list');
    listproto = list.prototype;

    listproto.__len__ = function () {
        return int_cons(this.__array__.length);
    };

    listproto.__repr__ = function () {
        var i, arr, arr_len, list_string = '';
        arr = this.__array__;
        arr_len = arr.length;
        list_string += '[';

        for (i = 0; i < arr_len; ++i) {
            if (i > 0) {
                list_string += ', ';
            }
            list_string += arr[i].__repr__().__string__;
        }

        list_string += ']';
        return str_cons(list_string);
    };

    listproto.__add__ = function (b) {
        return list_cons(this.__array__.concat(b.__array__));
    };

    listproto.__eq__ = function (b) {
        var arr, barr, i;
        if (b instanceof list) {
            arr = this.__array__;
            barr = b.__array__;

            if (arr.length !== barr.length) {
                return False;
            }

            for (i = 0; i < arr.length; i++) {
                if (!eq(arr[i], barr[i]).__boolean__) {
                    return False;
                }
            }

            return True;

        } else {
            return False;
        }
    };

    // str class enrichment
    strproto = str.prototype;

    strproto.__len__ = function () {
        return int_cons(this.__string__.length);
    };

    strproto.__eq__ = function (b) {
        if (b instanceof str) {
            return this.__string__ === b.__string__ ? True : False;
        } else {
            return False;
        }
    };

    // bool class enrichment
    bool.__name__ = str_cons('bool');
    boolproto = bool.prototype;

    boolproto.__repr__ = function () {
        return this.__boolean__ ? str_cons('True') : str_cons('False');
    };

    // exceptions class enrichment
    BaseException.__name__ = str_cons('BaseException');

    baseexcproto = BaseException.prototype;

    baseexcproto.__repr__ = function () {
        var i, arr, arr_len, list_string = '';
        arr = this.args;
        arr_len = arr.length;
        list_string += this.__class__.__name__.__str__().__string__;
        list_string += '(';

        for (i = 0; i < arr_len; ++i) {
            if (i > 0) {
                list_string += ', ';
            }
            list_string += arr[i].__repr__().__string__;
        }

        list_string += ')';
        return str_cons(list_string);
    };

    Exception.__name__ = str_cons('Exception');

    TypeError.__name__ = str_cons('TypeError');

    AttributeError.__name__ = str_cons('AttributeError');

    ValueError.__name__ = str_cons('ValueError');

    return {};
});
<commit_msg>js lib: object __dir__<commit_after>(function (factory) {
    module.exports = factory(
        require('./core'),
        require('./object'),
        require('./type'),
        require('./int'),
        require('./list'),
        require('./str'),
        require('./bool'),
        require('./exceptions')
    );
}).call(this, function (core, _object, _type, _int, _list, _str, _bool,
                        _exceptions) {
    'use strict';

    var object, objectproto;
    var type;
    var int, intproto, int_cons;
    var list, listproto, list_cons;
    var str, strproto, str_cons;
    var bool, boolproto, bool_cons, not, eq, True, False;
    var BaseException, Exception, TypeError, AttributeError, ValueError;
    var baseexcproto;
    var reserved_attributes;

    object = _object.object;
    type = _type.type;
    int = _int.int;
    int_cons = _int.int_cons;
    list = _list.list;
    list_cons = _list.list_cons;
    str = _str.str;
    str_cons = _str.str_cons;
    bool = _bool.bool;
    bool_cons = _bool.bool_cons;
    not = _bool.not;
    eq = _bool.eq;
    True = _bool.True;
    False = _bool.False;
    BaseException = _exceptions.BaseException;
    Exception = _exceptions.Exception;
    TypeError = _exceptions.TypeError;
    AttributeError = _exceptions.AttributeError;
    ValueError = _exceptions.ValueError;

    // object class enrichment
    object.__name__ = str_cons('object');
    object.__class__ = type;
    objectproto = object.prototype;
    objectproto.__doc__ = str_cons('The most base type');

    reserved_attributes = [
        '__string__',
        '__array__',
        '__boolean__',
        '__number__'
    ];

    objectproto.__repr__ = function () {
        return str_cons('<' + this.__class__.__name__.__string__ + ' object>');
    };

    objectproto.__str__ = function () {
        return this.__repr__();
    };

    objectproto.__dir__ = function () {
        var k, arr = [];

        for (k in this) {
            if (reserved_attributes.indexOf(k) === -1) {
                arr.push(str_cons(k));
            }
        }

        return list_cons(arr);
    };

    // int class enrichment
    int.__name__ = str_cons('int');
    intproto = int.prototype;

    intproto.__repr__ = function () {
        return str_cons('' + this.__number__);
    };

    intproto.__bool__ = function () {
        return this.__number__ !== 0 ? True : False;
    };

    intproto.__eq__ = function (b) {
        //TODO: typeerror
        if (b instanceof int) {
            return this.__number__ === b.__number__ ? True : False;
        } else {
            return False;
        }
    };

    // list class enrichment
    list.__name__ = str_cons('list');
    listproto = list.prototype;

    listproto.__len__ = function () {
        return int_cons(this.__array__.length);
    };

    listproto.__repr__ = function () {
        var i, arr, arr_len, list_string = '';
        arr = this.__array__;
        arr_len = arr.length;
        list_string += '[';

        for (i = 0; i < arr_len; ++i) {
            if (i > 0) {
                list_string += ', ';
            }
            list_string += arr[i].__repr__().__string__;
        }

        list_string += ']';
        return str_cons(list_string);
    };

    listproto.__add__ = function (b) {
        return list_cons(this.__array__.concat(b.__array__));
    };

    listproto.__eq__ = function (b) {
        var arr, barr, i;
        if (b instanceof list) {
            arr = this.__array__;
            barr = b.__array__;

            if (arr.length !== barr.length) {
                return False;
            }

            for (i = 0; i < arr.length; i++) {
                if (!eq(arr[i], barr[i]).__boolean__) {
                    return False;
                }
            }

            return True;

        } else {
            return False;
        }
    };

    // str class enrichment
    strproto = str.prototype;

    strproto.__len__ = function () {
        return int_cons(this.__string__.length);
    };

    strproto.__eq__ = function (b) {
        if (b instanceof str) {
            return this.__string__ === b.__string__ ? True : False;
        } else {
            return False;
        }
    };

    // bool class enrichment
    bool.__name__ = str_cons('bool');
    boolproto = bool.prototype;

    boolproto.__repr__ = function () {
        return this.__boolean__ ? str_cons('True') : str_cons('False');
    };

    // exceptions class enrichment
    BaseException.__name__ = str_cons('BaseException');

    baseexcproto = BaseException.prototype;

    baseexcproto.__repr__ = function () {
        var i, arr, arr_len, list_string = '';
        arr = this.args;
        arr_len = arr.length;
        list_string += this.__class__.__name__.__str__().__string__;
        list_string += '(';

        for (i = 0; i < arr_len; ++i) {
            if (i > 0) {
                list_string += ', ';
            }
            list_string += arr[i].__repr__().__string__;
        }

        list_string += ')';
        return str_cons(list_string);
    };

    Exception.__name__ = str_cons('Exception');

    TypeError.__name__ = str_cons('TypeError');

    AttributeError.__name__ = str_cons('AttributeError');

    ValueError.__name__ = str_cons('ValueError');

    return {};
});
<|endoftext|>


<commit_before>"use 6to5";

var language = require('./geck-language');

module.exports = {
  // The basic regular expression string used to find GECK functions
  geckFnRegEx: '\\b[\\w_\\-]+\\b/',

  // The base URL used for documentation reference for GECK functions
  urlBase: 'http://geck.bethsoft.com/index.php?title=',

  // Base functions page
  fnBase: 'http://geck.bethsoft.com/index.php?title=Category:Functions',

  // Language syntax
  syntax: language,

  // Grammars Added
  grammarsAdded: false,

  // Configuration
  config: {
    highlightVegas: {
      type: 'boolean',
      'default': true
    },
    highlightNVSE: {
      "type": "boolean",
      "default": true
    },
    highlightFOSE: {
      "type": "boolean",
      "default": true
    },
    highlightNX: {
      "type": "boolean",
      "default": true
    }
  },

  /**
   * This is the primary required function for an exported module. This
   * function invokes _getSelectedText with a regular expression string
   * used to determine the name of the function in question and then
   * takes that matching text and opens a web browser to that page if
   * Mark Hahn's web-browser package is installed.
   */
  activate: function(state) {
    atom.commands.add(
      'atom-text-editor',
      'language-geck:lookup',
      this.lookupSelected.bind(this)
    );

    atom.commands.add(
      'atom-text-editor',
      'language-geck:toggleFOSE',
      this.toggleConfig.bind(this, 'language-geck.highlightFOSE')
    );

    atom.commands.add(
      'atom-text-editor',
      'language-geck:toggleVegas',
      this.toggleConfig.bind(this, 'language-geck.highlightVegas')
    );

    atom.commands.add(
      'atom-text-editor',
      'language-geck:toggleNVSE',
      this.toggleConfig.bind(this, 'language-geck.highlightNVSE')
    );

    atom.commands.add(
      'atom-text-editor',
      'language-geck:toggleNX',
      this.toggleConfig.bind(this, 'language-geck.highlightNX')
    );

    atom.packages.on('activated', this.updateGrammars.bind(this));
    this.updateGrammars();
  },

  /**
   * Command: language-geck:lookup
   *
   * This function is invoked in a manner of ways (menu, context-menu, and
   * keymap); it's purpose is to either open the selected text, hopefully
   * a function known to GECK, in a web browser or the root functions page
   * if the rest is unavailable.
   */
  lookupSelected: function() {
    console.log("[language-geck] lookup invoked!");
    this._getSelectedText(this.geckFnRegEx, (function(text) {
      var browser;

      browser = atom.packages.getActivePackage('web-browser');
      if (browser) {
        if (text.length) {
          console.log('[language-geck] Selected function -> %o', text);
          atom.workspace.open([this.urlBase, text].join(''));
        }
        else {
          console.log('[language-geck] Opening functions root');
          atom.workspace.open(this.fnBase);
        }
      }
      else {
        console.error("[language-geck] web-browser is a required package.");
      }
    }).bind(this));
  },

  toggleConfig: function(config, event) {
    var value = atom.config.get(config);
    atom.config.set(config, !value);
    this.updateGrammars();
  },

  updateGrammars: function() {
    // Obtain the highlight flags
    var cfg = atom.config.get('language-geck');

    // Supplement grammer
    var grammar = atom.grammars.grammarsByScopeName['source.geck'];

    // Remove dynamic grammars
    for (let a = grammar.rawPatterns, i = 0; i < a.length; i++) {
      if (a[i].___type && a[i].___type === 'dynamic') {
        a.splice(i, 1);
        i--;
      }
    }

    var patterns = [
      [true, 'keyword.geck-keyword', [language.keywords]],
      [true, 'keyword.control.geck.blocktype', [language.blocktypes, true]],
      [true, 'keyword.geck.baseFns', [language.geckFns]],
      [cfg.highlightFOSE, 'keyword.geck.foseFns', [language.foseFns]],
      [cfg.highlightVegas, 'keyword.geck.vegasFns', [language.vegasFns]],
      [cfg.highlightNVSE, 'keyword.geck.nvseFns', [language.nvseFns]],
      [cfg.highlightNX, 'keyword.geck.nxFns', [language.nxFns]]
    ];

    for (let set of patterns) {
      let [condition, name, getSetParams] = set;
      if (condition) {
        this.addPattern(grammar.rawPatterns, name, getSetParams);
      }
    }

    // Update everything
    if (grammar.includedGrammarScopes.indexOf(grammar.scopeName) === -1) {
      grammar.includedGrammarScopes.push(grammar.scopeName);
    }
    grammar.grammarUpdated(grammar.scopeName);
  },

  /**
   * Adds a pattern to make the grammar a bit more dynamic. The patterns
   * added by this function can be determined by the unique triple underscore
   * type property. This makes it easier to find these properties as well
   * as manage them as situations arise.
   *
   * @param patterns a reference to the grammar.rawPatterns array
   * @param name a set of class names that will be applied to the span denoting
   * any matches found by the pattern.
   * @param getSetParams an array of arguments used with the geck-language
   * getSet() function.
   * @return the same array that was passed into the function as patterns
   */
  addPattern: function(patterns, name, getSetParams) {
    patterns[patterns.length] = {
      match: language.getSet(...getSetParams),
      name: name,
      ___type: 'dynamic'
    };

    return patterns;
  },

  /**
   * The purpose of this method is to seek out the selected text,
   * determined by the regex string supplied and invoke the supplied
   * callback, executeOn, for each match. The value of the selected
   * text will be supplied as the only parameter to executeOn.
   *
   * @param regex a regular expression in string format
   * @param executeOn a function receiving a single parameter which
   * denotes the selected text in the editor.
   */
  _getSelectedText: function(regex, executeOn) {
    var body, col, cursor, editor, end, filePattern;
    var line, m, opts, range, selection, start, text, _i, _len, _ref;

    editor = atom.workspace.getActiveEditor();

    filePattern = new RegExp(regex, 'g');

    _ref = editor.getSelections();
    for (_i = 0, _len = _ref.length; _i < _len; _i++) {
      selection = _ref[_i];
      range = selection.getBufferRange();

      if (range.isEmpty()) {
        cursor = selection.cursor;
        line = cursor.getCurrentBufferLine();
        col = cursor.getBufferColumn();
        opts = {
          wordRegex: new RegExp(regex)
        };
        start = cursor.getBeginningOfCurrentWordBufferPosition(opts);
        end = cursor.getEndOfCurrentWordBufferPosition(opts);
        range = new Range(start, end);
      }

      text = editor.getTextInBufferRange(range);
      if (text.match(/\s/)) {
        text = "";
      }

      executeOn(text);
    }
  }
};
<commit_msg>updateGrammars will wait 1s if not ready<commit_after>"use 6to5";

var language = require('./geck-language');

module.exports = {
  // The basic regular expression string used to find GECK functions
  geckFnRegEx: '\\b[\\w_\\-]+\\b/',

  // The base URL used for documentation reference for GECK functions
  urlBase: 'http://geck.bethsoft.com/index.php?title=',

  // Base functions page
  fnBase: 'http://geck.bethsoft.com/index.php?title=Category:Functions',

  // Language syntax
  syntax: language,

  // Grammars Added
  grammarsAdded: false,

  // Configuration
  config: {
    highlightVegas: {
      type: 'boolean',
      'default': true
    },
    highlightNVSE: {
      "type": "boolean",
      "default": true
    },
    highlightFOSE: {
      "type": "boolean",
      "default": true
    },
    highlightNX: {
      "type": "boolean",
      "default": true
    }
  },

  /**
   * This is the primary required function for an exported module. This
   * function invokes _getSelectedText with a regular expression string
   * used to determine the name of the function in question and then
   * takes that matching text and opens a web browser to that page if
   * Mark Hahn's web-browser package is installed.
   */
  activate: function(state) {
    atom.commands.add(
      'atom-text-editor',
      'language-geck:lookup',
      this.lookupSelected.bind(this)
    );

    atom.commands.add(
      'atom-text-editor',
      'language-geck:toggleFOSE',
      this.toggleConfig.bind(this, 'language-geck.highlightFOSE')
    );

    atom.commands.add(
      'atom-text-editor',
      'language-geck:toggleVegas',
      this.toggleConfig.bind(this, 'language-geck.highlightVegas')
    );

    atom.commands.add(
      'atom-text-editor',
      'language-geck:toggleNVSE',
      this.toggleConfig.bind(this, 'language-geck.highlightNVSE')
    );

    atom.commands.add(
      'atom-text-editor',
      'language-geck:toggleNX',
      this.toggleConfig.bind(this, 'language-geck.highlightNX')
    );

    atom.packages.on('activated', this.updateGrammars.bind(this));
    this.updateGrammars();
  },

  /**
   * Command: language-geck:lookup
   *
   * This function is invoked in a manner of ways (menu, context-menu, and
   * keymap); it's purpose is to either open the selected text, hopefully
   * a function known to GECK, in a web browser or the root functions page
   * if the rest is unavailable.
   */
  lookupSelected: function() {
    console.log("[language-geck] lookup invoked!");
    this._getSelectedText(this.geckFnRegEx, (function(text) {
      var browser;

      browser = atom.packages.getActivePackage('web-browser');
      if (browser) {
        if (text.length) {
          console.log('[language-geck] Selected function -> %o', text);
          atom.workspace.open([this.urlBase, text].join(''));
        }
        else {
          console.log('[language-geck] Opening functions root');
          atom.workspace.open(this.fnBase);
        }
      }
      else {
        console.error("[language-geck] web-browser is a required package.");
      }
    }).bind(this));
  },

  toggleConfig: function(config, event) {
    var value = atom.config.get(config);
    atom.config.set(config, !value);
    this.updateGrammars();
  },

  updateGrammars: function() {
    // Obtain the highlight flags
    var cfg = atom.config.get('language-geck');

    // Supplement grammer
    var grammar = atom.grammars.grammarsByScopeName['source.geck'];
    if (!grammar) {
      setTimeout(this.updateGrammars.bind(this), 1000);
      console.log('Grammar not yet available, trying again in 1s');
      return;
    }

    // Remove dynamic grammars
    for (let a = grammar.rawPatterns, i = 0; i < a.length; i++) {
      if (a[i].___type && a[i].___type === 'dynamic') {
        a.splice(i, 1);
        i--;
      }
    }

    var patterns = [
      [true, 'keyword.geck-keyword', [language.keywords]],
      [true, 'keyword.control.geck.blocktype', [language.blocktypes, true]],
      [true, 'keyword.geck.baseFns', [language.geckFns]],
      [cfg.highlightFOSE, 'keyword.geck.foseFns', [language.foseFns]],
      [cfg.highlightVegas, 'keyword.geck.vegasFns', [language.vegasFns]],
      [cfg.highlightNVSE, 'keyword.geck.nvseFns', [language.nvseFns]],
      [cfg.highlightNX, 'keyword.geck.nxFns', [language.nxFns]]
    ];

    for (let set of patterns) {
      let [condition, name, getSetParams] = set;
      if (condition) {
        this.addPattern(grammar.rawPatterns, name, getSetParams);
      }
    }

    // Update everything
    if (grammar.includedGrammarScopes.indexOf(grammar.scopeName) === -1) {
      grammar.includedGrammarScopes.push(grammar.scopeName);
    }
    grammar.grammarUpdated(grammar.scopeName);
  },

  /**
   * Adds a pattern to make the grammar a bit more dynamic. The patterns
   * added by this function can be determined by the unique triple underscore
   * type property. This makes it easier to find these properties as well
   * as manage them as situations arise.
   *
   * @param patterns a reference to the grammar.rawPatterns array
   * @param name a set of class names that will be applied to the span denoting
   * any matches found by the pattern.
   * @param getSetParams an array of arguments used with the geck-language
   * getSet() function.
   * @return the same array that was passed into the function as patterns
   */
  addPattern: function(patterns, name, getSetParams) {
    patterns[patterns.length] = {
      match: language.getSet(...getSetParams),
      name: name,
      ___type: 'dynamic'
    };

    return patterns;
  },

  /**
   * The purpose of this method is to seek out the selected text,
   * determined by the regex string supplied and invoke the supplied
   * callback, executeOn, for each match. The value of the selected
   * text will be supplied as the only parameter to executeOn.
   *
   * @param regex a regular expression in string format
   * @param executeOn a function receiving a single parameter which
   * denotes the selected text in the editor.
   */
  _getSelectedText: function(regex, executeOn) {
    var body, col, cursor, editor, end, filePattern;
    var line, m, opts, range, selection, start, text, _i, _len, _ref;

    editor = atom.workspace.getActiveEditor();

    filePattern = new RegExp(regex, 'g');

    _ref = editor.getSelections();
    for (_i = 0, _len = _ref.length; _i < _len; _i++) {
      selection = _ref[_i];
      range = selection.getBufferRange();

      if (range.isEmpty()) {
        cursor = selection.cursor;
        line = cursor.getCurrentBufferLine();
        col = cursor.getBufferColumn();
        opts = {
          wordRegex: new RegExp(regex)
        };
        start = cursor.getBeginningOfCurrentWordBufferPosition(opts);
        end = cursor.getEndOfCurrentWordBufferPosition(opts);
        range = new Range(start, end);
      }

      text = editor.getTextInBufferRange(range);
      if (text.match(/\s/)) {
        text = "";
      }

      executeOn(text);
    }
  }
};
<|endoftext|>


<commit_before>var _ = require('lodash')
    curtain = require('./curtain')
    hackyMarineCadastreLayerConversion = require('./hacky_marine_cadastre_layer_conversion')
    scrollSpy = require('./scroll_spy')
    ol3MapEngine = require('./ol3_map_engine')
    oceanStoryMap = require('./map')
    polyfills = require('./polyfills');

function mount(mapElement, story, animate) {

  var map;
  var mapEngine = ol3MapEngine(mapElement[0], animate);

  function bindScrollAnimationToLinks(selector) {
    if (animate) {
      // copied with modification from
      // http://www.paulund.co.uk/smooth-scroll-to-internal-links-with-jquery
      $(document).ready(function(){
        // only animate intra-page links inside .content
        $(selector).on('click',function (e) {
          e.preventDefault();

          var target = this.hash;
          $target = $(target);

          $('html, body').stop().animate({
            'scrollTop': $target.offset().top
          }, 900, 'swing', function () {
            window.location.hash = target;
          });
        });
      });
    }
  }

  bindScrollAnimationToLinks('a[href^="#"].animate');

  // returns a setter that calls the passed function whenever the value changes
  // this could be useful as part of a utility library
  function callIfChanged(f) {
    var state;
    return function(newState) {
      if (typeof(state) == "undefined" || newState !== state) {
        state = newState;
        f(state);
      }
    }
  }

  curtain($('.curtain'), callIfChanged(function(collapsed){
    console.info('set collapse: '+collapsed)
    mapElement.toggleClass('half', collapsed);
    mapElement.toggleClass('full', !collapsed);
    mapEngine.updateSize();
  }));

  $.getJSON("/data_manager/api/layers", function(data) {

    var dataLayers = _.indexBy(data, 'id');
    _.each(dataLayers, function(d) {
      if (d.layer_type == 'ArcRest') {
        hackyMarineCadastreLayerConversion(d);
      }
    })
    map = oceanStoryMap(mapEngine, story, dataLayers);
    scrollSpy('.content', 'a.anchor[id^=\'section-\']', function(sectionIndex){
      return map.goToSection(sectionIndex);
    })
  });
}

module.exports = mount;
window.oceanStory = module.exports;
<commit_msg>add a slash, avoid a 301 redirect<commit_after>var _ = require('lodash')
    curtain = require('./curtain')
    hackyMarineCadastreLayerConversion = require('./hacky_marine_cadastre_layer_conversion')
    scrollSpy = require('./scroll_spy')
    ol3MapEngine = require('./ol3_map_engine')
    oceanStoryMap = require('./map')
    polyfills = require('./polyfills');

function mount(mapElement, story, animate) {

  var map;
  var mapEngine = ol3MapEngine(mapElement[0], animate);

  function bindScrollAnimationToLinks(selector) {
    if (animate) {
      // copied with modification from
      // http://www.paulund.co.uk/smooth-scroll-to-internal-links-with-jquery
      $(document).ready(function(){
        // only animate intra-page links inside .content
        $(selector).on('click',function (e) {
          e.preventDefault();

          var target = this.hash;
          $target = $(target);

          $('html, body').stop().animate({
            'scrollTop': $target.offset().top
          }, 900, 'swing', function () {
            window.location.hash = target;
          });
        });
      });
    }
  }

  bindScrollAnimationToLinks('a[href^="#"].animate');

  // returns a setter that calls the passed function whenever the value changes
  // this could be useful as part of a utility library
  function callIfChanged(f) {
    var state;
    return function(newState) {
      if (typeof(state) == "undefined" || newState !== state) {
        state = newState;
        f(state);
      }
    }
  }

  curtain($('.curtain'), callIfChanged(function(collapsed){
    console.info('set collapse: '+collapsed)
    mapElement.toggleClass('half', collapsed);
    mapElement.toggleClass('full', !collapsed);
    mapEngine.updateSize();
  }));

  $.getJSON("/data_manager/api/layers/", function(data) {

    var dataLayers = _.indexBy(data, 'id');
    _.each(dataLayers, function(d) {
      if (d.layer_type == 'ArcRest') {
        hackyMarineCadastreLayerConversion(d);
      }
    })
    map = oceanStoryMap(mapEngine, story, dataLayers);
    scrollSpy('.content', 'a.anchor[id^=\'section-\']', function(sectionIndex){
      return map.goToSection(sectionIndex);
    })
  });
}

module.exports = mount;
window.oceanStory = module.exports;
<|endoftext|>


<commit_before>function initializeTextEditors() {
    console.log("initializeTextEditors");

    jQuery("input[type='text'], textarea").each(function() {
        if (jQuery(this).hasClass('rteInitialized') || jQuery(this).parent().parent().attr('class') == "login_popup_box") {
            return;
        }

        var tmp = this;
        var thiz = jQuery(this);

        var limitCharactersMax = thiz.parent().find(".limit_charactersMax");
        var limitCharacterCount = thiz.parent().find(".limit_characterCount");

        if (limitCharactersMax.length > 0) {
            thiz.attr({maxCharacters: limitCharactersMax.text(), validateLength: true});
            this.limitCharacterCounter = limitCharacterCount;
            updateCharacterCounter(thiz);
        } else {
            thiz.attr({validateLength: false});
        }

        if (thiz.hasClass("ckeditor_placeholder")) {

            var editor = CKEDITOR.replace(thiz.attr("id"));

            thiz.get(0)["ckeditor"] = editor;
            editor.updatedCharCount = false;

            function updateEditorCharCount() {
                try{
                    if (editor == null) return;

                    if (editor &&  editor.document && editor.document['$'] && (editor.checkDirty() || editor.updatedCharCount)) {
                        markEditorDirty(thiz);
                        updateCharacterCounter(thiz, editor);
                        editor.updatedCharCount = true;
                        editor.resetDirty();
                    }

                    setTimeout(updateEditorCharCount, 1000);
                } catch (e) {
                    if (typeof(console) != 'undefined' && typeof(console.log) != 'undefined') {
                        console.log(e);
                    }
                }
            }
            if (! jQuery.browser.ie || jQuery.browser.version.number >= 9) {
                updateEditorCharCount();
            }

            editor.on("blur", function() {
                updateCharacterCounter(thiz, editor);
            });

            // initiate char counters
            setTimeout(function() { updateCharacterCounter(thiz, editor); }, 2000);
        }
        else {
            eventsToBind = {
                keypress: function(event) {
                    if (thiz.attr('validateLength') && tmp.limitCharacterCounter) {
                        updateCharacterCounter(thiz);
                    }
                },
                keyup: function(event) {
                    if (thiz.attr('validateLength') && tmp.limitCharacterCounter) {
                        updateCharacterCounter(thiz);
                    }
                },
                change: function(event) {
                    console.log("asdfasdfasdfasdfasdfasfd");
                    markEditorDirty(thiz);
                }
            };
            thiz.bind(eventsToBind);
        }
        jQuery(this).addClass('rteInitialized');
    });
}

function initializeDropDowns() {
    jQuery("select").each(function() {
        eventsToBind = {
            change: function(event) {
                markEditorDirty(jQuery(jQuery("input[type='text'], textarea")[0]));
            }
        };
        jQuery(this).bind(eventsToBind);
    });
}

function markEditorDirty(editor) {
    editor.addClass('editorDirty');
}

function enableDirtyCheck() {
    window.oldOnBeforeUnload = window.onbeforeunload;
    window.onbeforeunload = function() {
        if (jQuery(".editorDirty").length > 0) {
            return 'You have modified this page but have not saved your changes.';
        }
        return null;
    };
}

function disableDirtyCheck() {
    if ('oldOnBeforeUnload' in window) {
        window.onbeforeunload = window.oldOnBeforeUnload;
    }
    delete window.onbeforeunload;
}<commit_msg>Removed orphaned log message<commit_after>function initializeTextEditors() {
    console.log("initializeTextEditors");

    jQuery("input[type='text'], textarea").each(function() {
        if (jQuery(this).hasClass('rteInitialized') || jQuery(this).parent().parent().attr('class') == "login_popup_box") {
            return;
        }

        var tmp = this;
        var thiz = jQuery(this);

        var limitCharactersMax = thiz.parent().find(".limit_charactersMax");
        var limitCharacterCount = thiz.parent().find(".limit_characterCount");

        if (limitCharactersMax.length > 0) {
            thiz.attr({maxCharacters: limitCharactersMax.text(), validateLength: true});
            this.limitCharacterCounter = limitCharacterCount;
            updateCharacterCounter(thiz);
        } else {
            thiz.attr({validateLength: false});
        }

        if (thiz.hasClass("ckeditor_placeholder")) {

            var editor = CKEDITOR.replace(thiz.attr("id"));

            thiz.get(0)["ckeditor"] = editor;
            editor.updatedCharCount = false;

            function updateEditorCharCount() {
                try{
                    if (editor == null) return;

                    if (editor &&  editor.document && editor.document['$'] && (editor.checkDirty() || editor.updatedCharCount)) {
                        markEditorDirty(thiz);
                        updateCharacterCounter(thiz, editor);
                        editor.updatedCharCount = true;
                        editor.resetDirty();
                    }

                    setTimeout(updateEditorCharCount, 1000);
                } catch (e) {
                    if (typeof(console) != 'undefined' && typeof(console.log) != 'undefined') {
                        console.log(e);
                    }
                }
            }
            if (! jQuery.browser.ie || jQuery.browser.version.number >= 9) {
                updateEditorCharCount();
            }

            editor.on("blur", function() {
                updateCharacterCounter(thiz, editor);
            });

            // initiate char counters
            setTimeout(function() { updateCharacterCounter(thiz, editor); }, 2000);
        }
        else {
            eventsToBind = {
                keypress: function(event) {
                    if (thiz.attr('validateLength') && tmp.limitCharacterCounter) {
                        updateCharacterCounter(thiz);
                    }
                },
                keyup: function(event) {
                    if (thiz.attr('validateLength') && tmp.limitCharacterCounter) {
                        updateCharacterCounter(thiz);
                    }
                },
                change: function(event) {
                    markEditorDirty(thiz);
                }
            };
            thiz.bind(eventsToBind);
        }
        jQuery(this).addClass('rteInitialized');
    });
}

function initializeDropDowns() {
    jQuery("select").each(function() {
        eventsToBind = {
            change: function(event) {
                markEditorDirty(jQuery(jQuery("input[type='text'], textarea")[0]));
            }
        };
        jQuery(this).bind(eventsToBind);
    });
}

function markEditorDirty(editor) {
    editor.addClass('editorDirty');
}

function enableDirtyCheck() {
    window.oldOnBeforeUnload = window.onbeforeunload;
    window.onbeforeunload = function() {
        if (jQuery(".editorDirty").length > 0) {
            return 'You have modified this page but have not saved your changes.';
        }
        return null;
    };
}

function disableDirtyCheck() {
    if ('oldOnBeforeUnload' in window) {
        window.onbeforeunload = window.oldOnBeforeUnload;
    }
    delete window.onbeforeunload;
}<|endoftext|>