// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

'use strict';

// const inspect = require('util').inspect;

var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };

var inspect = function inspect(obj) {
	return obj;
};

function assertPath(path) {
	if (typeof path !== 'string') {
		throw new TypeError('Path must be a string. Received ' + inspect(path));
	}
}

// Resolves . and .. elements in a path with directory names
function normalizeStringWin32(path, allowAboveRoot) {
	var res = '';
	var lastSlash = -1;
	var dots = 0;
	var code;
	for (var i = 0; i <= path.length; ++i) {
		if (i < path.length) code = path.charCodeAt(i);else if (code === 47 /*/*/ || code === 92 /*\*/) break;else code = 47 /*/*/;
		if (code === 47 /*/*/ || code === 92 /*\*/) {
				if (lastSlash === i - 1 || dots === 1) {
					// NOOP
				} else if (lastSlash !== i - 1 && dots === 2) {
						if (res.length < 2 || res.charCodeAt(res.length - 1) !== 46 /*.*/ || res.charCodeAt(res.length - 2) !== 46 /*.*/) {
								if (res.length > 2) {
									var start = res.length - 1;
									var j = start;
									for (; j >= 0; --j) {
										if (res.charCodeAt(j) === 92 /*\*/) break;
									}
									if (j !== start) {
										if (j === -1) res = '';else res = res.slice(0, j);
										lastSlash = i;
										dots = 0;
										continue;
									}
								} else if (res.length === 2 || res.length === 1) {
									res = '';
									lastSlash = i;
									dots = 0;
									continue;
								}
							}
						if (allowAboveRoot) {
							if (res.length > 0) res += '\\..';else res = '..';
						}
					} else {
						if (res.length > 0) res += '\\' + path.slice(lastSlash + 1, i);else res = path.slice(lastSlash + 1, i);
					}
				lastSlash = i;
				dots = 0;
			} else if (code === 46 /*.*/ && dots !== -1) {
			++dots;
		} else {
			dots = -1;
		}
	}
	return res;
}

// Resolves . and .. elements in a path with directory names
function normalizeStringPosix(path, allowAboveRoot) {
	var res = '';
	var lastSlash = -1;
	var dots = 0;
	var code;
	for (var i = 0; i <= path.length; ++i) {
		if (i < path.length) code = path.charCodeAt(i);else if (code === 47 /*/*/) break;else code = 47 /*/*/;
		if (code === 47 /*/*/) {
				if (lastSlash === i - 1 || dots === 1) {
					// NOOP
				} else if (lastSlash !== i - 1 && dots === 2) {
						if (res.length < 2 || res.charCodeAt(res.length - 1) !== 46 /*.*/ || res.charCodeAt(res.length - 2) !== 46 /*.*/) {
								if (res.length > 2) {
									var start = res.length - 1;
									var j = start;
									for (; j >= 0; --j) {
										if (res.charCodeAt(j) === 47 /*/*/) break;
									}
									if (j !== start) {
										if (j === -1) res = '';else res = res.slice(0, j);
										lastSlash = i;
										dots = 0;
										continue;
									}
								} else if (res.length === 2 || res.length === 1) {
									res = '';
									lastSlash = i;
									dots = 0;
									continue;
								}
							}
						if (allowAboveRoot) {
							if (res.length > 0) res += '/..';else res = '..';
						}
					} else {
						if (res.length > 0) res += '/' + path.slice(lastSlash + 1, i);else res = path.slice(lastSlash + 1, i);
					}
				lastSlash = i;
				dots = 0;
			} else if (code === 46 /*.*/ && dots !== -1) {
			++dots;
		} else {
			dots = -1;
		}
	}
	return res;
}

function _format(sep, pathObject) {
	var dir = pathObject.dir || pathObject.root;
	var base = pathObject.base || (pathObject.name || '') + (pathObject.ext || '');
	if (!dir) {
		return base;
	}
	if (dir === pathObject.root) {
		return dir + base;
	}
	return dir + sep + base;
}

var win32 = {
	// path.resolve([from ...], to)
	resolve: function resolve() {
		var resolvedDevice = '';
		var resolvedTail = '';
		var resolvedAbsolute = false;

		for (var i = arguments.length - 1; i >= -1; i--) {
			var path;
			if (i >= 0) {
				path = arguments[i];
			} else if (!resolvedDevice) {
				path = process.cwd();
			} else {
				// Windows has the concept of drive-specific current working
				// directories. If we've resolved a drive letter but not yet an
				// absolute path, get cwd for that drive. We're sure the device is not
				// a UNC path at this points, because UNC paths are always absolute.
				path = process.env['=' + resolvedDevice];
				// Verify that a drive-local cwd was found and that it actually points
				// to our drive. If not, default to the drive's root.
				if (path === undefined || path.slice(0, 3).toLowerCase() !== resolvedDevice.toLowerCase() + '\\') {
					path = resolvedDevice + '\\';
				}
			}

			assertPath(path);

			// Skip empty entries
			if (path.length === 0) {
				continue;
			}

			var len = path.length;
			var rootEnd = 0;
			var code = path.charCodeAt(0);
			var device = '';
			var isAbsolute = false;

			// Try to match a root
			if (len > 1) {
				if (code === 47 /*/*/ || code === 92 /*\*/) {
						// Possible UNC root

						// If we started with a separator, we know we at least have an
						// absolute path of some kind (UNC or otherwise)
						isAbsolute = true;

						code = path.charCodeAt(1);
						if (code === 47 /*/*/ || code === 92 /*\*/) {
								// Matched double path separator at beginning
								var j = 2;
								var last = j;
								// Match 1 or more non-path separators
								for (; j < len; ++j) {
									code = path.charCodeAt(j);
									if (code === 47 /*/*/ || code === 92 /*\*/) break;
								}
								if (j < len && j !== last) {
									var firstPart = path.slice(last, j);
									// Matched!
									last = j;
									// Match 1 or more path separators
									for (; j < len; ++j) {
										code = path.charCodeAt(j);
										if (code !== 47 /*/*/ && code !== 92 /*\*/) break;
									}
									if (j < len && j !== last) {
										// Matched!
										last = j;
										// Match 1 or more non-path separators
										for (; j < len; ++j) {
											code = path.charCodeAt(j);
											if (code === 47 /*/*/ || code === 92 /*\*/) break;
										}
										if (j === len) {
											// We matched a UNC root only

											device = '\\\\' + firstPart + '\\' + path.slice(last);
											rootEnd = j;
										} else if (j !== last) {
											// We matched a UNC root with leftovers

											device = '\\\\' + firstPart + '\\' + path.slice(last, j);
											rootEnd = j;
										}
									}
								}
							} else {
							rootEnd = 1;
						}
					} else if (code >= 65 /*A*/ && code <= 90 /*Z*/ || code >= 97 /*a*/ && code <= 122 /*z*/) {
						// Possible device root

						code = path.charCodeAt(1);
						if (path.charCodeAt(1) === 58 /*:*/) {
								device = path.slice(0, 2);
								rootEnd = 2;
								if (len > 2) {
									code = path.charCodeAt(2);
									if (code === 47 /*/*/ || code === 92 /*\*/) {
											// Treat separator following drive name as an absolute path
											// indicator
											isAbsolute = true;
											rootEnd = 3;
										}
								}
							}
					}
			} else if (code === 47 /*/*/ || code === 92 /*\*/) {
					// `path` contains just a path separator
					rootEnd = 1;
					isAbsolute = true;
				}

			if (device.length > 0 && resolvedDevice.length > 0 && device.toLowerCase() !== resolvedDevice.toLowerCase()) {
				// This path points to another device so it is not applicable
				continue;
			}

			if (resolvedDevice.length === 0 && device.length > 0) {
				resolvedDevice = device;
			}
			if (!resolvedAbsolute) {
				resolvedTail = path.slice(rootEnd) + '\\' + resolvedTail;
				resolvedAbsolute = isAbsolute;
			}

			if (resolvedDevice.length > 0 && resolvedAbsolute) {
				break;
			}
		}

		// At this point the path should be resolved to a full absolute path,
		// but handle relative paths to be safe (might happen when process.cwd()
		// fails)

		// Normalize the tail path
		resolvedTail = normalizeStringWin32(resolvedTail, !resolvedAbsolute);

		return resolvedDevice + (resolvedAbsolute ? '\\' : '') + resolvedTail || '.';
	},

	normalize: function normalize(path) {
		assertPath(path);
		var len = path.length;
		if (len === 0) return '.';
		var rootEnd = 0;
		var code = path.charCodeAt(0);
		var device;
		var isAbsolute = false;

		// Try to match a root
		if (len > 1) {
			if (code === 47 /*/*/ || code === 92 /*\*/) {
					// Possible UNC root

					// If we started with a separator, we know we at least have an absolute
					// path of some kind (UNC or otherwise)
					isAbsolute = true;

					code = path.charCodeAt(1);
					if (code === 47 /*/*/ || code === 92 /*\*/) {
							// Matched double path separator at beginning
							var j = 2;
							var last = j;
							// Match 1 or more non-path separators
							for (; j < len; ++j) {
								code = path.charCodeAt(j);
								if (code === 47 /*/*/ || code === 92 /*\*/) break;
							}
							if (j < len && j !== last) {
								var firstPart = path.slice(last, j);
								// Matched!
								last = j;
								// Match 1 or more path separators
								for (; j < len; ++j) {
									code = path.charCodeAt(j);
									if (code !== 47 /*/*/ && code !== 92 /*\*/) break;
								}
								if (j < len && j !== last) {
									// Matched!
									last = j;
									// Match 1 or more non-path separators
									for (; j < len; ++j) {
										code = path.charCodeAt(j);
										if (code === 47 /*/*/ || code === 92 /*\*/) break;
									}
									if (j === len) {
										// We matched a UNC root only
										// Return the normalized version of the UNC root since there
										// is nothing left to process

										return '\\\\' + firstPart + '\\' + path.slice(last) + '\\';
									} else if (j !== last) {
										// We matched a UNC root with leftovers

										device = '\\\\' + firstPart + '\\' + path.slice(last, j);
										rootEnd = j;
									}
								}
							}
						} else {
						rootEnd = 1;
					}
				} else if (code >= 65 /*A*/ && code <= 90 /*Z*/ || code >= 97 /*a*/ && code <= 122 /*z*/) {
					// Possible device root

					code = path.charCodeAt(1);
					if (path.charCodeAt(1) === 58 /*:*/) {
							device = path.slice(0, 2);
							rootEnd = 2;
							if (len > 2) {
								code = path.charCodeAt(2);
								if (code === 47 /*/*/ || code === 92 /*\*/) {
										// Treat separator following drive name as an absolute path
										// indicator
										isAbsolute = true;
										rootEnd = 3;
									}
							}
						}
				}
		} else if (code === 47 /*/*/ || code === 92 /*\*/) {
				// `path` contains just a path separator, exit early to avoid unnecessary
				// work
				return '\\';
			}

		code = path.charCodeAt(len - 1);
		var trailingSeparator = code === 47 /*/*/ || code === 92 /*\*/;
		var tail;
		if (rootEnd < len) tail = normalizeStringWin32(path.slice(rootEnd), !isAbsolute);else tail = '';
		if (tail.length === 0 && !isAbsolute) tail = '.';
		if (tail.length > 0 && trailingSeparator) tail += '\\';
		if (device === undefined) {
			if (isAbsolute) {
				if (tail.length > 0) return '\\' + tail;else return '\\';
			} else if (tail.length > 0) {
				return tail;
			} else {
				return '';
			}
		} else {
			if (isAbsolute) {
				if (tail.length > 0) return device + '\\' + tail;else return device + '\\';
			} else if (tail.length > 0) {
				return device + tail;
			} else {
				return device;
			}
		}
	},

	isAbsolute: function isAbsolute(path) {
		assertPath(path);
		var len = path.length;
		if (len === 0) return false;
		var code = path.charCodeAt(0);
		if (code === 47 /*/*/ || code === 92 /*\*/) {
				return true;
			} else if (code >= 65 /*A*/ && code <= 90 /*Z*/ || code >= 97 /*a*/ && code <= 122 /*z*/) {
				// Possible device root

				if (len > 2 && path.charCodeAt(1) === 58 /*:*/) {
						code = path.charCodeAt(2);
						if (code === 47 /*/*/ || code === 92 /*\*/) return true;
					}
			}
		return false;
	},

	join: function join() {
		if (arguments.length === 0) return '.';

		var joined;
		var firstPart;
		for (var i = 0; i < arguments.length; ++i) {
			var arg = arguments[i];
			assertPath(arg);
			if (arg.length > 0) {
				if (joined === undefined) joined = firstPart = arg;else joined += '\\' + arg;
			}
		}

		if (joined === undefined) return '.';

		// Make sure that the joined path doesn't start with two slashes, because
		// normalize() will mistake it for an UNC path then.
		//
		// This step is skipped when it is very clear that the user actually
		// intended to point at an UNC path. This is assumed when the first
		// non-empty string arguments starts with exactly two slashes followed by
		// at least one more non-slash character.
		//
		// Note that for normalize() to treat a path as an UNC path it needs to
		// have at least 2 components, so we don't filter for that here.
		// This means that the user can use join to construct UNC paths from
		// a server name and a share name; for example:
		//   path.join('//server', 'share') -> '\\\\server\\share\\')
		//var firstPart = paths[0];
		var needsReplace = true;
		var slashCount = 0;
		var code = firstPart.charCodeAt(0);
		if (code === 47 /*/*/ || code === 92 /*\*/) {
				++slashCount;
				var firstLen = firstPart.length;
				if (firstLen > 1) {
					code = firstPart.charCodeAt(1);
					if (code === 47 /*/*/ || code === 92 /*\*/) {
							++slashCount;
							if (firstLen > 2) {
								code = firstPart.charCodeAt(2);
								if (code === 47 /*/*/ || code === 92 /*\*/) ++slashCount;else {
									// We matched a UNC path in the first part
									needsReplace = false;
								}
							}
						}
				}
			}
		if (needsReplace) {
			// Find any more consecutive slashes we need to replace
			for (; slashCount < joined.length; ++slashCount) {
				code = joined.charCodeAt(slashCount);
				if (code !== 47 /*/*/ && code !== 92 /*\*/) break;
			}

			// Replace the slashes if needed
			if (slashCount >= 2) joined = '\\' + joined.slice(slashCount);
		}

		return win32.normalize(joined);
	},

	// It will solve the relative path from `from` to `to`, for instance:
	//  from = 'C:\\orandea\\test\\aaa'
	//  to = 'C:\\orandea\\impl\\bbb'
	// The output of the function should be: '..\\..\\impl\\bbb'
	relative: function relative(from, to) {
		assertPath(from);
		assertPath(to);

		if (from === to) return '';

		var fromOrig = win32.resolve(from);
		var toOrig = win32.resolve(to);

		if (fromOrig === toOrig) return '';

		from = fromOrig.toLowerCase();
		to = toOrig.toLowerCase();

		if (from === to) return '';

		// Trim any leading backslashes
		var fromStart = 0;
		for (; fromStart < from.length; ++fromStart) {
			if (from.charCodeAt(fromStart) !== 92 /*\*/) break;
		}
		// Trim trailing backslashes (applicable to UNC paths only)
		var fromEnd = from.length;
		for (; fromEnd - 1 > fromStart; --fromEnd) {
			if (from.charCodeAt(fromEnd - 1) !== 92 /*\*/) break;
		}
		var fromLen = fromEnd - fromStart;

		// Trim any leading backslashes
		var toStart = 0;
		for (; toStart < to.length; ++toStart) {
			if (to.charCodeAt(toStart) !== 92 /*\*/) break;
		}
		// Trim trailing backslashes (applicable to UNC paths only)
		var toEnd = to.length;
		for (; toEnd - 1 > toStart; --toEnd) {
			if (to.charCodeAt(toEnd - 1) !== 92 /*\*/) break;
		}
		var toLen = toEnd - toStart;

		// Compare paths to find the longest common path from root
		var length = fromLen < toLen ? fromLen : toLen;
		var lastCommonSep = -1;
		var i = 0;
		for (; i <= length; ++i) {
			if (i === length) {
				if (toLen > length) {
					if (to.charCodeAt(toStart + i) === 92 /*\*/) {
							// We get here if `from` is the exact base path for `to`.
							// For example: from='C:\\foo\\bar'; to='C:\\foo\\bar\\baz'
							return toOrig.slice(toStart + i + 1);
						} else if (i === 2) {
						// We get here if `from` is the device root.
						// For example: from='C:\\'; to='C:\\foo'
						return toOrig.slice(toStart + i);
					}
				}
				if (fromLen > length) {
					if (from.charCodeAt(fromStart + i) === 92 /*\*/) {
							// We get here if `to` is the exact base path for `from`.
							// For example: from='C:\\foo\\bar'; to='C:\\foo'
							lastCommonSep = i;
						} else if (i === 2) {
						// We get here if `to` is the device root.
						// For example: from='C:\\foo\\bar'; to='C:\\'
						lastCommonSep = 3;
					}
				}
				break;
			}
			var fromCode = from.charCodeAt(fromStart + i);
			var toCode = to.charCodeAt(toStart + i);
			if (fromCode !== toCode) break;else if (fromCode === 92 /*\*/) lastCommonSep = i;
		}

		// We found a mismatch before the first common path separator was seen, so
		// return the original `to`.
		// TODO: do this just for device roots (and not UNC paths)?
		if (i !== length && lastCommonSep === -1) {
			if (toStart > 0) return toOrig.slice(toStart);else return toOrig;
		}

		var out = '';
		if (lastCommonSep === -1) lastCommonSep = 0;
		// Generate the relative path based on the path difference between `to` and
		// `from`
		for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) {
			if (i === fromEnd || from.charCodeAt(i) === 92 /*\*/) {
					if (out.length === 0) out += '..';else out += '\\..';
				}
		}

		// Lastly, append the rest of the destination (`to`) path that comes after
		// the common path parts
		if (out.length > 0) return out + toOrig.slice(toStart + lastCommonSep, toEnd);else {
			toStart += lastCommonSep;
			if (toOrig.charCodeAt(toStart) === 92 /*\*/) ++toStart;
			return toOrig.slice(toStart, toEnd);
		}
	},

	_makeLong: function _makeLong(path) {
		// Note: this will *probably* throw somewhere.
		if (typeof path !== 'string') return path;

		if (path.length === 0) {
			return '';
		}

		var resolvedPath = win32.resolve(path);

		if (resolvedPath.length >= 3) {
			var code = resolvedPath.charCodeAt(0);
			if (code === 92 /*\*/) {
					// Possible UNC root

					if (resolvedPath.charCodeAt(1) === 92 /*\*/) {
							code = resolvedPath.charCodeAt(2);
							if (code !== 63 /*?*/ && code !== 46 /*.*/) {
									// Matched non-long UNC root, convert the path to a long UNC path
									return '\\\\?\\UNC\\' + resolvedPath.slice(2);
								}
						}
				} else if (code >= 65 /*A*/ && code <= 90 /*Z*/ || code >= 97 /*a*/ && code <= 122 /*z*/) {
					// Possible device root

					if (resolvedPath.charCodeAt(1) === 58 /*:*/ && resolvedPath.charCodeAt(2) === 92 /*\*/) {
							// Matched device root, convert the path to a long UNC path
							return '\\\\?\\' + resolvedPath;
						}
				}
		}

		return path;
	},

	dirname: function dirname(path) {
		assertPath(path);
		var len = path.length;
		if (len === 0) return '.';
		var rootEnd = -1;
		var end = -1;
		var matchedSlash = true;
		var offset = 0;
		var code = path.charCodeAt(0);

		// Try to match a root
		if (len > 1) {
			if (code === 47 /*/*/ || code === 92 /*\*/) {
					// Possible UNC root

					rootEnd = offset = 1;

					code = path.charCodeAt(1);
					if (code === 47 /*/*/ || code === 92 /*\*/) {
							// Matched double path separator at beginning
							var j = 2;
							var last = j;
							// Match 1 or more non-path separators
							for (; j < len; ++j) {
								code = path.charCodeAt(j);
								if (code === 47 /*/*/ || code === 92 /*\*/) break;
							}
							if (j < len && j !== last) {
								// Matched!
								last = j;
								// Match 1 or more path separators
								for (; j < len; ++j) {
									code = path.charCodeAt(j);
									if (code !== 47 /*/*/ && code !== 92 /*\*/) break;
								}
								if (j < len && j !== last) {
									// Matched!
									last = j;
									// Match 1 or more non-path separators
									for (; j < len; ++j) {
										code = path.charCodeAt(j);
										if (code === 47 /*/*/ || code === 92 /*\*/) break;
									}
									if (j === len) {
										// We matched a UNC root only
										return path;
									}
									if (j !== last) {
										// We matched a UNC root with leftovers

										// Offset by 1 to include the separator after the UNC root to
										// treat it as a "normal root" on top of a (UNC) root
										rootEnd = offset = j + 1;
									}
								}
							}
						}
				} else if (code >= 65 /*A*/ && code <= 90 /*Z*/ || code >= 97 /*a*/ && code <= 122 /*z*/) {
					// Possible device root

					code = path.charCodeAt(1);
					if (path.charCodeAt(1) === 58 /*:*/) {
							rootEnd = offset = 2;
							if (len > 2) {
								code = path.charCodeAt(2);
								if (code === 47 /*/*/ || code === 92 /*\*/) rootEnd = offset = 3;
							}
						}
				}
		} else if (code === 47 /*/*/ || code === 92 /*\*/) {
				return path[0];
			}

		for (var i = len - 1; i >= offset; --i) {
			code = path.charCodeAt(i);
			if (code === 47 /*/*/ || code === 92 /*\*/) {
					if (!matchedSlash) {
						end = i;
						break;
					}
				} else {
				// We saw the first non-path separator
				matchedSlash = false;
			}
		}

		if (end === -1) {
			if (rootEnd === -1) return '.';else end = rootEnd;
		}
		return path.slice(0, end);
	},

	basename: function basename(path, ext) {
		if (ext !== undefined && typeof ext !== 'string') throw new TypeError('"ext" argument must be a string');
		assertPath(path);
		var start = 0;
		var end = -1;
		var matchedSlash = true;
		var i;

		// Check for a drive letter prefix so as not to mistake the following
		// path separator as an extra separator at the end of the path that can be
		// disregarded
		if (path.length >= 2) {
			var drive = path.charCodeAt(0);
			if (drive >= 65 /*A*/ && drive <= 90 /*Z*/ || drive >= 97 /*a*/ && drive <= 122 /*z*/) {
					if (path.charCodeAt(1) === 58 /*:*/) start = 2;
				}
		}

		if (ext !== undefined && ext.length > 0 && ext.length <= path.length) {
			if (ext.length === path.length && ext === path) return '';
			var extIdx = ext.length - 1;
			var firstNonSlashEnd = -1;
			for (i = path.length - 1; i >= start; --i) {
				var code = path.charCodeAt(i);
				if (code === 47 /*/*/ || code === 92 /*\*/) {
						// If we reached a path separator that was not part of a set of path
						// separators at the end of the string, stop now
						if (!matchedSlash) {
							start = i + 1;
							break;
						}
					} else {
					if (firstNonSlashEnd === -1) {
						// We saw the first non-path separator, remember this index in case
						// we need it if the extension ends up not matching
						matchedSlash = false;
						firstNonSlashEnd = i + 1;
					}
					if (extIdx >= 0) {
						// Try to match the explicit extension
						if (code === ext.charCodeAt(extIdx)) {
							if (--extIdx === -1) {
								// We matched the extension, so mark this as the end of our path
								// component
								end = i;
							}
						} else {
							// Extension does not match, so our result is the entire path
							// component
							extIdx = -1;
							end = firstNonSlashEnd;
						}
					}
				}
			}

			if (start === end) end = firstNonSlashEnd;else if (end === -1) end = path.length;
			return path.slice(start, end);
		} else {
			for (i = path.length - 1; i >= start; --i) {
				var _code = path.charCodeAt(i);
				if (_code === 47 /*/*/ || _code === 92 /*\*/) {
						// If we reached a path separator that was not part of a set of path
						// separators at the end of the string, stop now
						if (!matchedSlash) {
							start = i + 1;
							break;
						}
					} else if (end === -1) {
					// We saw the first non-path separator, mark this as the end of our
					// path component
					matchedSlash = false;
					end = i + 1;
				}
			}

			if (end === -1) return '';
			return path.slice(start, end);
		}
	},

	extname: function extname(path) {
		assertPath(path);
		var startDot = -1;
		var startPart = 0;
		var end = -1;
		var matchedSlash = true;
		// Track the state of characters (if any) we see before our first dot and
		// after any path separator we find
		var preDotState = 0;
		for (var i = path.length - 1; i >= 0; --i) {
			var code = path.charCodeAt(i);
			if (code === 47 /*/*/ || code === 92 /*\*/) {
					// If we reached a path separator that was not part of a set of path
					// separators at the end of the string, stop now
					if (!matchedSlash) {
						startPart = i + 1;
						break;
					}
					continue;
				}
			if (end === -1) {
				// We saw the first non-path separator, mark this as the end of our
				// extension
				matchedSlash = false;
				end = i + 1;
			}
			if (code === 46 /*.*/) {
					// If this is our first dot, mark it as the start of our extension
					if (startDot === -1) startDot = i;else if (preDotState !== 1) preDotState = 1;
				} else if (startDot !== -1) {
				// We saw a non-dot and non-path separator before our dot, so we should
				// have a good chance at having a non-empty extension
				preDotState = -1;
			}
		}

		if (startDot === -1 || end === -1 ||
		// We saw a non-dot character immediately before the dot
		preDotState === 0 ||
		// The (right-most) trimmed path component is exactly '..'
		preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) {
			return '';
		}
		return path.slice(startDot, end);
	},

	format: function format(pathObject) {
		if (pathObject === null || (typeof pathObject === 'undefined' ? 'undefined' : _typeof(pathObject)) !== 'object') {
			throw new TypeError('Parameter "pathObject" must be an object, not ' + (typeof pathObject === 'undefined' ? 'undefined' : _typeof(pathObject)));
		}
		return _format('\\', pathObject);
	},

	parse: function parse(path) {
		assertPath(path);

		var ret = { root: '', dir: '', base: '', ext: '', name: '' };
		if (path.length === 0) return ret;

		var len = path.length;
		var rootEnd = 0;
		var code = path.charCodeAt(0);
		var isAbsolute = false;

		// Try to match a root
		if (len > 1) {
			if (code === 47 /*/*/ || code === 92 /*\*/) {
					// Possible UNC root

					isAbsolute = true;

					code = path.charCodeAt(1);
					rootEnd = 1;
					if (code === 47 /*/*/ || code === 92 /*\*/) {
							// Matched double path separator at beginning
							var j = 2;
							var last = j;
							// Match 1 or more non-path separators
							for (; j < len; ++j) {
								code = path.charCodeAt(j);
								if (code === 47 /*/*/ || code === 92 /*\*/) break;
							}
							if (j < len && j !== last) {
								// Matched!
								last = j;
								// Match 1 or more path separators
								for (; j < len; ++j) {
									code = path.charCodeAt(j);
									if (code !== 47 /*/*/ && code !== 92 /*\*/) break;
								}
								if (j < len && j !== last) {
									// Matched!
									last = j;
									// Match 1 or more non-path separators
									for (; j < len; ++j) {
										code = path.charCodeAt(j);
										if (code === 47 /*/*/ || code === 92 /*\*/) break;
									}
									if (j === len) {
										// We matched a UNC root only

										rootEnd = j;
									} else if (j !== last) {
										// We matched a UNC root with leftovers

										rootEnd = j + 1;
									}
								}
							}
						}
				} else if (code >= 65 /*A*/ && code <= 90 /*Z*/ || code >= 97 /*a*/ && code <= 122 /*z*/) {
					// Possible device root

					code = path.charCodeAt(1);
					if (path.charCodeAt(1) === 58 /*:*/) {
							rootEnd = 2;
							if (len > 2) {
								code = path.charCodeAt(2);
								if (code === 47 /*/*/ || code === 92 /*\*/) {
										if (len === 3) {
											// `path` contains just a drive root, exit early to avoid
											// unnecessary work
											ret.root = ret.dir = path.slice(0, 3);
											return ret;
										}
										isAbsolute = true;
										rootEnd = 3;
									}
							} else {
								// `path` contains just a drive root, exit early to avoid
								// unnecessary work
								ret.root = ret.dir = path.slice(0, 2);
								return ret;
							}
						}
				}
		} else if (code === 47 /*/*/ || code === 92 /*\*/) {
				// `path` contains just a path separator, exit early to avoid
				// unnecessary work
				ret.root = ret.dir = path[0];
				return ret;
			}

		if (rootEnd > 0) ret.root = path.slice(0, rootEnd);

		var startDot = -1;
		var startPart = 0;
		var end = -1;
		var matchedSlash = true;
		var i = path.length - 1;

		// Track the state of characters (if any) we see before our first dot and
		// after any path separator we find
		var preDotState = 0;

		// Get non-dir info
		for (; i >= rootEnd; --i) {
			code = path.charCodeAt(i);
			if (code === 47 /*/*/ || code === 92 /*\*/) {
					// If we reached a path separator that was not part of a set of path
					// separators at the end of the string, stop now
					if (!matchedSlash) {
						startPart = i + 1;
						break;
					}
					continue;
				}
			if (end === -1) {
				// We saw the first non-path separator, mark this as the end of our
				// extension
				matchedSlash = false;
				end = i + 1;
			}
			if (code === 46 /*.*/) {
					// If this is our first dot, mark it as the start of our extension
					if (startDot === -1) startDot = i;else if (preDotState !== 1) preDotState = 1;
				} else if (startDot !== -1) {
				// We saw a non-dot and non-path separator before our dot, so we should
				// have a good chance at having a non-empty extension
				preDotState = -1;
			}
		}

		if (startDot === -1 || end === -1 ||
		// We saw a non-dot character immediately before the dot
		preDotState === 0 ||
		// The (right-most) trimmed path component is exactly '..'
		preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) {
			if (end !== -1) {
				if (startPart === 0 && isAbsolute) ret.base = ret.name = path.slice(rootEnd, end);else ret.base = ret.name = path.slice(startPart, end);
			}
		} else {
			if (startPart === 0 && isAbsolute) {
				ret.name = path.slice(rootEnd, startDot);
				ret.base = path.slice(rootEnd, end);
			} else {
				ret.name = path.slice(startPart, startDot);
				ret.base = path.slice(startPart, end);
			}
			ret.ext = path.slice(startDot, end);
		}

		if (startPart > 0) ret.dir = path.slice(0, startPart - 1);else if (isAbsolute) ret.dir = path.slice(0, rootEnd);

		return ret;
	},

	sep: '\\',
	delimiter: ';',
	win32: null,
	posix: null
};

var posix = {
	// path.resolve([from ...], to)
	resolve: function resolve() {
		var resolvedPath = '';
		var resolvedAbsolute = false;
		var cwd;

		for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
			var path;
			if (i >= 0) path = arguments[i];else {
				if (cwd === undefined) cwd = process.cwd();
				path = cwd;
			}

			assertPath(path);

			// Skip empty entries
			if (path.length === 0) {
				continue;
			}

			resolvedPath = path + '/' + resolvedPath;
			resolvedAbsolute = path.charCodeAt(0) === 47 /*/*/;
		}

		// At this point the path should be resolved to a full absolute path, but
		// handle relative paths to be safe (might happen when process.cwd() fails)

		// Normalize the path
		resolvedPath = normalizeStringPosix(resolvedPath, !resolvedAbsolute);

		if (resolvedAbsolute) {
			if (resolvedPath.length > 0) return '/' + resolvedPath;else return '/';
		} else if (resolvedPath.length > 0) {
			return resolvedPath;
		} else {
			return '.';
		}
	},

	normalize: function normalize(path) {
		assertPath(path);

		if (path.length === 0) return '.';

		var isAbsolute = path.charCodeAt(0) === 47 /*/*/;
		var trailingSeparator = path.charCodeAt(path.length - 1) === 47 /*/*/;

		// Normalize the path
		path = normalizeStringPosix(path, !isAbsolute);

		if (path.length === 0 && !isAbsolute) path = '.';
		if (path.length > 0 && trailingSeparator) path += '/';

		if (isAbsolute) return '/' + path;
		return path;
	},

	isAbsolute: function isAbsolute(path) {
		assertPath(path);
		return path.length > 0 && path.charCodeAt(0) === 47 /*/*/;
	},

	join: function join() {
		if (arguments.length === 0) return '.';
		var joined;
		for (var i = 0; i < arguments.length; ++i) {
			var arg = arguments[i];
			assertPath(arg);
			if (arg.length > 0) {
				if (joined === undefined) joined = arg;else joined += '/' + arg;
			}
		}
		if (joined === undefined) return '.';
		return posix.normalize(joined);
	},

	relative: function relative(from, to) {
		assertPath(from);
		assertPath(to);

		if (from === to) return '';

		from = posix.resolve(from);
		to = posix.resolve(to);

		if (from === to) return '';

		// Trim any leading backslashes
		var fromStart = 1;
		for (; fromStart < from.length; ++fromStart) {
			if (from.charCodeAt(fromStart) !== 47 /*/*/) break;
		}
		var fromEnd = from.length;
		var fromLen = fromEnd - fromStart;

		// Trim any leading backslashes
		var toStart = 1;
		for (; toStart < to.length; ++toStart) {
			if (to.charCodeAt(toStart) !== 47 /*/*/) break;
		}
		var toEnd = to.length;
		var toLen = toEnd - toStart;

		// Compare paths to find the longest common path from root
		var length = fromLen < toLen ? fromLen : toLen;
		var lastCommonSep = -1;
		var i = 0;
		for (; i <= length; ++i) {
			if (i === length) {
				if (toLen > length) {
					if (to.charCodeAt(toStart + i) === 47 /*/*/) {
							// We get here if `from` is the exact base path for `to`.
							// For example: from='/foo/bar'; to='/foo/bar/baz'
							return to.slice(toStart + i + 1);
						} else if (i === 0) {
						// We get here if `from` is the root
						// For example: from='/'; to='/foo'
						return to.slice(toStart + i);
					}
				} else if (fromLen > length) {
					if (from.charCodeAt(fromStart + i) === 47 /*/*/) {
							// We get here if `to` is the exact base path for `from`.
							// For example: from='/foo/bar/baz'; to='/foo/bar'
							lastCommonSep = i;
						} else if (i === 0) {
						// We get here if `to` is the root.
						// For example: from='/foo'; to='/'
						lastCommonSep = 0;
					}
				}
				break;
			}
			var fromCode = from.charCodeAt(fromStart + i);
			var toCode = to.charCodeAt(toStart + i);
			if (fromCode !== toCode) break;else if (fromCode === 47 /*/*/) lastCommonSep = i;
		}

		var out = '';
		// Generate the relative path based on the path difference between `to`
		// and `from`
		for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) {
			if (i === fromEnd || from.charCodeAt(i) === 47 /*/*/) {
					if (out.length === 0) out += '..';else out += '/..';
				}
		}

		// Lastly, append the rest of the destination (`to`) path that comes after
		// the common path parts
		if (out.length > 0) return out + to.slice(toStart + lastCommonSep);else {
			toStart += lastCommonSep;
			if (to.charCodeAt(toStart) === 47 /*/*/) ++toStart;
			return to.slice(toStart);
		}
	},

	_makeLong: function _makeLong(path) {
		return path;
	},

	dirname: function dirname(path) {
		assertPath(path);
		if (path.length === 0) return '.';
		var code = path.charCodeAt(0);
		var hasRoot = code === 47 /*/*/;
		var end = -1;
		var matchedSlash = true;
		for (var i = path.length - 1; i >= 1; --i) {
			code = path.charCodeAt(i);
			if (code === 47 /*/*/) {
					if (!matchedSlash) {
						end = i;
						break;
					}
				} else {
				// We saw the first non-path separator
				matchedSlash = false;
			}
		}

		if (end === -1) return hasRoot ? '/' : '.';
		if (hasRoot && end === 1) return '//';
		return path.slice(0, end);
	},

	basename: function basename(path, ext) {
		if (ext !== undefined && typeof ext !== 'string') throw new TypeError('"ext" argument must be a string');
		assertPath(path);

		var start = 0;
		var end = -1;
		var matchedSlash = true;
		var i;

		if (ext !== undefined && ext.length > 0 && ext.length <= path.length) {
			if (ext.length === path.length && ext === path) return '';
			var extIdx = ext.length - 1;
			var firstNonSlashEnd = -1;
			for (i = path.length - 1; i >= 0; --i) {
				var code = path.charCodeAt(i);
				if (code === 47 /*/*/) {
						// If we reached a path separator that was not part of a set of path
						// separators at the end of the string, stop now
						if (!matchedSlash) {
							start = i + 1;
							break;
						}
					} else {
					if (firstNonSlashEnd === -1) {
						// We saw the first non-path separator, remember this index in case
						// we need it if the extension ends up not matching
						matchedSlash = false;
						firstNonSlashEnd = i + 1;
					}
					if (extIdx >= 0) {
						// Try to match the explicit extension
						if (code === ext.charCodeAt(extIdx)) {
							if (--extIdx === -1) {
								// We matched the extension, so mark this as the end of our path
								// component
								end = i;
							}
						} else {
							// Extension does not match, so our result is the entire path
							// component
							extIdx = -1;
							end = firstNonSlashEnd;
						}
					}
				}
			}

			if (start === end) end = firstNonSlashEnd;else if (end === -1) end = path.length;
			return path.slice(start, end);
		} else {
			for (i = path.length - 1; i >= 0; --i) {
				if (path.charCodeAt(i) === 47 /*/*/) {
						// If we reached a path separator that was not part of a set of path
						// separators at the end of the string, stop now
						if (!matchedSlash) {
							start = i + 1;
							break;
						}
					} else if (end === -1) {
					// We saw the first non-path separator, mark this as the end of our
					// path component
					matchedSlash = false;
					end = i + 1;
				}
			}

			if (end === -1) return '';
			return path.slice(start, end);
		}
	},

	extname: function extname(path) {
		assertPath(path);
		var startDot = -1;
		var startPart = 0;
		var end = -1;
		var matchedSlash = true;
		// Track the state of characters (if any) we see before our first dot and
		// after any path separator we find
		var preDotState = 0;
		for (var i = path.length - 1; i >= 0; --i) {
			var code = path.charCodeAt(i);
			if (code === 47 /*/*/) {
					// If we reached a path separator that was not part of a set of path
					// separators at the end of the string, stop now
					if (!matchedSlash) {
						startPart = i + 1;
						break;
					}
					continue;
				}
			if (end === -1) {
				// We saw the first non-path separator, mark this as the end of our
				// extension
				matchedSlash = false;
				end = i + 1;
			}
			if (code === 46 /*.*/) {
					// If this is our first dot, mark it as the start of our extension
					if (startDot === -1) startDot = i;else if (preDotState !== 1) preDotState = 1;
				} else if (startDot !== -1) {
				// We saw a non-dot and non-path separator before our dot, so we should
				// have a good chance at having a non-empty extension
				preDotState = -1;
			}
		}

		if (startDot === -1 || end === -1 ||
		// We saw a non-dot character immediately before the dot
		preDotState === 0 ||
		// The (right-most) trimmed path component is exactly '..'
		preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) {
			return '';
		}
		return path.slice(startDot, end);
	},

	format: function format(pathObject) {
		if (pathObject === null || (typeof pathObject === 'undefined' ? 'undefined' : _typeof(pathObject)) !== 'object') {
			throw new TypeError('Parameter "pathObject" must be an object, not ' + (typeof pathObject === 'undefined' ? 'undefined' : _typeof(pathObject)));
		}
		return _format('/', pathObject);
	},

	parse: function parse(path) {
		assertPath(path);

		var ret = { root: '', dir: '', base: '', ext: '', name: '' };
		if (path.length === 0) return ret;
		var code = path.charCodeAt(0);
		var isAbsolute = code === 47 /*/*/;
		var start;
		if (isAbsolute) {
			ret.root = '/';
			start = 1;
		} else {
			start = 0;
		}
		var startDot = -1;
		var startPart = 0;
		var end = -1;
		var matchedSlash = true;
		var i = path.length - 1;

		// Track the state of characters (if any) we see before our first dot and
		// after any path separator we find
		var preDotState = 0;

		// Get non-dir info
		for (; i >= start; --i) {
			code = path.charCodeAt(i);
			if (code === 47 /*/*/) {
					// If we reached a path separator that was not part of a set of path
					// separators at the end of the string, stop now
					if (!matchedSlash) {
						startPart = i + 1;
						break;
					}
					continue;
				}
			if (end === -1) {
				// We saw the first non-path separator, mark this as the end of our
				// extension
				matchedSlash = false;
				end = i + 1;
			}
			if (code === 46 /*.*/) {
					// If this is our first dot, mark it as the start of our extension
					if (startDot === -1) startDot = i;else if (preDotState !== 1) preDotState = 1;
				} else if (startDot !== -1) {
				// We saw a non-dot and non-path separator before our dot, so we should
				// have a good chance at having a non-empty extension
				preDotState = -1;
			}
		}

		if (startDot === -1 || end === -1 ||
		// We saw a non-dot character immediately before the dot
		preDotState === 0 ||
		// The (right-most) trimmed path component is exactly '..'
		preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) {
			if (end !== -1) {
				if (startPart === 0 && isAbsolute) ret.base = ret.name = path.slice(1, end);else ret.base = ret.name = path.slice(startPart, end);
			}
		} else {
			if (startPart === 0 && isAbsolute) {
				ret.name = path.slice(1, startDot);
				ret.base = path.slice(1, end);
			} else {
				ret.name = path.slice(startPart, startDot);
				ret.base = path.slice(startPart, end);
			}
			ret.ext = path.slice(startDot, end);
		}

		if (startPart > 0) ret.dir = path.slice(0, startPart - 1);else if (isAbsolute) ret.dir = '/';

		return ret;
	},

	sep: '/',
	delimiter: ':',
	win32: null,
	posix: null
};

posix.win32 = win32.win32 = win32;
posix.posix = win32.posix = posix;

if (process.platform === 'win32') module.exports = win32;else module.exports = posix;


'use strict';

var R = require('ramda');
var nr = require('needle-retry');
var nodeSchedule = require('node-schedule');
var util = require('util');
var events = require('events');

/*
 * Gets default options and merges with user options if any.
 * @param options
 * @returns {*}
 */
var getDefaults = function(options) {
  var defaults = {
    'method': 'get',
    'data': null,
    'needleRetry': null,
    'rule': { 'second': 1 }
  };

  if (!options) {
    return defaults;
  }

  return R.merge(defaults, options);
};

var Schedule = function(targets, userOptions) {
  var self = this;
  self.jobs = [];
  self.running = 0;
  self.targets = targets;
  self.options = getDefaults(userOptions);

  events.EventEmitter.call(this);
  return self;
};

util.inherits(Schedule, events.EventEmitter);

/*
 * Start the scheduler
 */
Schedule.prototype.start = function() {
  var self = this;

  self.emit('start');

  R.forEach(function(target) {
    var options = R.merge(self.options, target);

    var job = nodeSchedule.scheduleJob(options.rule, function() {
      var timestamps = {
        'start': Date.now()
      };

      self.running++;
      self.emit('running', options, timestamps);

      nr.request(
        options.method,
        options.url,
        options.data,
        options.needleRetry,
        function(error, response, body) {
          self.running--;
          timestamps.end = Date.now();

          if (error) {
            self.emit('error', error, options, timestamps);
            return;
          }

          self.emit('response', response, body, options, timestamps);
        });
    });

    self.jobs.push(job);
  }, self.targets);
};

/*
 * stop the scheduler
 */
Schedule.prototype.stop = function() {
  var self = this;
  R.forEach(function(job) {
    job.cancel();
  }, self.jobs);

  self.emit('stop');
};

module.exports = function(targets, userOptions) {
  return new Schedule(targets, userOptions);
};


"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
/*====================================================
	- HTML Table Filter Generator v1.0
	- By Max Guglielmi
	- mguglielmi.free.fr
  - http://www.javascriptsource.com/repository/javascripts/2006/05/835271/TableFilter_EN.htm
  - modified by @noahedwardhall
  - thank me later
=====================================================*/

var TblId = [];
var StartRow = [];
var SearchFlt = [];

/*====================================================
- adds a filter (input) for each column (td)
- adds button on last column
=====================================================*/
function AddRow(id, n) {
  var t = document.getElementById(id);
  var fltrow = t.insertRow(0);
  var inpclass = "flt";
  for (var i = 0; i < n; i++) {
    var fltcell = fltrow.insertCell(i);
    var inp = document.createElement("input");
    inp.setAttribute("id", "flt" + i + "_" + id);
    inp.setAttribute("type", "text");
    inp.setAttribute("class", i == n - 1 ? "flt_s" : "flt");
    inp.setAttribute('placeholder', 'Filter');
    inp.addEventListener('keyup', Filter);
    fltcell.appendChild(inp);
  }
}

/*====================================================
- returns text + text of child nodes of a cell
=====================================================*/
function getCellText(n) {
  var s = "";
  var enfants = n.childNodes;
  for (var i = 0; i < enfants.length; i++) {
    var child = enfants[i];
    if (child.nodeType == 3) s += child.data;else s += getCellText(child);
  }
  return s.toLowerCase();
}

/*====================================================
- returns starting row for Filter fn for a
given table id
=====================================================*/
function getStartRow(id) {
  var r = void 0;
  for (var j in TblId) {
    if (TblId[j] === id) r = StartRow[j];
  }
  return r;
}

/*====================================================
- checks passed node is a ELEMENT_NODE nodeType=1
- removes TEXT_NODE nodeType=3
=====================================================*/
function getChildElms(n) {
  if (n.nodeType == 1) {
    var enfants = n.childNodes;
    for (var i = 0; i < enfants.length; i++) {
      var child = enfants[i];
      if (child.nodeType == 3) n.removeChild(child);
    }
    return n;
  }
}

/*====================================================
- filter (input) ids are stored in this.SearchFlt
array
=====================================================*/
function getFilters(id) {
  SearchFlt = [];
  var t = document.getElementById(id);
  var tr = t.getElementsByTagName("tr")[0];
  var inp = tr.getElementsByTagName("input");

  for (var i = 0; i < inp.length; i++) {
    SearchFlt.push(inp[i].getAttribute("id"));
  }return SearchFlt;
}

/*====================================================
- returns number of cells in a row
- if nrow param is passed returns number of cells
of that specific row
=====================================================*/
function getCellsNb(id, nrow) {
  var t = document.getElementById(id);
  var tr = void 0;
  if (nrow == undefined) tr = t.getElementsByTagName("tr")[0];else tr = t.getElementsByTagName("tr")[nrow];
  var n = getChildElms(tr);
  return n.childNodes.length;
}

var filterTable = {
  /*====================================================
  - Checks if id exists and is a table
  - Calls fn that adds inputs and button
  =====================================================*/
  setFilterGrid: function setFilterGrid(id, ref_row) {
    if (typeof window === 'undefined' || typeof document === 'undefined') return;

    var tbl = document.getElementById(id);
    if (tbl && tbl.nodeName.toLowerCase() === "table") {
      TblId.push(id);
      ref_row = ref_row === undefined ? StartRow.push(2) : StartRow.push(ref_row + 2);
      //let ncells = getCellsNb(id, ref_row);

      // AddRow(id, ncells);
    }
  },

  /*====================================================
  - gets search strings from this.SearchFlt array
  - retrieves data from each td in every single tr
  and compares to search string for current
  column
  - tr is hidden if all search strings are not
  found
  =====================================================*/
  Filter: function Filter(e) {
    if (typeof document === 'undefined') return;
    var id = e.target.getAttribute("id").split("_")[1];
    var SearchFlt = getFilters(id);
    var t = document.getElementById(id);
    var SearchArgs = [];
    var ncells = getCellsNb(id);

    for (var i in SearchFlt) {
      SearchArgs.push(document.getElementById(SearchFlt[i]).value.toLowerCase());
    }var start_row = getStartRow(id);
    var row = t.getElementsByTagName("tr");

    for (var k = start_row; k < row.length; k++) {
      /*** if table already filtered some rows are not visible ***/
      if (row[k].style.display === "none") row[k].style.display = "";

      var cell = getChildElms(row[k]).childNodes;
      var nchilds = cell.length;
      var isRowValid = true;

      if (nchilds === ncells) {
        // checks if row has exact cell #
        var cell_value = [];
        var occurence = [];

        for (var j = 0; j < nchilds; j++) // this loop retrieves cell data
        {
          var cell_data = getCellText(cell[j]);
          cell_value.push(cell_data);

          if (SearchArgs[j] !== "") {
            occurence[j] = cell_data.split(SearchArgs[j]).length;
          }
        } //for j

        for (var _t = 0; _t < ncells; _t++) {
          if (SearchArgs[_t] !== "" && occurence[_t] < 2) {
            isRowValid = false;
          }
        } //for t
      } //if

      if (isRowValid === false) row[k].style.display = "none";else row[k].style.display = "";
    } // for k
  }
};

exports.default = filterTable;


'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = setConstants;

var _lodash = require('lodash');

var _lodash2 = _interopRequireDefault(_lodash);

var _seamlessImmutable = require('seamless-immutable');

var _seamlessImmutable2 = _interopRequireDefault(_seamlessImmutable);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

/**
 * Universal Constants made available to entire application
 * @see https://www.hacksparrow.com/global-variables-in-node-js.html
 * @author @noahehall
 * @type {Object}
 */
var appConsts = {
  isProd: process.env.NODE_ENV === 'production'
};

/**
 * Set global variables on worker & main threads, else node
 * @type {[type]}
*/
var setAppConsts = function setAppConsts() {
  var mergedConstants = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : (0, _seamlessImmutable2.default)(appConsts);

  // set node app consts
  if (typeof self === 'undefined' && typeof global !== 'undefined') {
    global.appConsts = global.appConsts ? _seamlessImmutable2.default.merge(global.appConsts, mergedConstants) : mergedConstants;

    return global.appConsts;
  } else if (typeof self !== 'undefined') {
    // set main & worker threads
    self.appConsts = self.appConsts ? _seamlessImmutable2.default.merge(self.appConsts, mergedConstants) : mergedConstants;

    return self.appConsts;
  }

  return {};
};

function setConstants(_ref) {
  var _ref$constants = _ref.constants,
      constants = _ref$constants === undefined ? {} : _ref$constants;

  return setAppConsts((0, _seamlessImmutable2.default)(_lodash2.default.merge(appConsts, constants || {})));
}


'use strict';

/*!
 * route-mapper - utils
 * Copyright(c) 2015 Fangdun Cai
 * MIT Licensed
 */

Object.defineProperty(exports, "__esModule", {
  value: true
});

var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();

var _lodash = require('lodash');

var _lodash2 = _interopRequireDefault(_lodash);

var _path = require('path');

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

/**
 * Split a string to an array.
 *
 * @example
 *  splitTo('controller#action')
 *  // => [ 'controller', 'action' ]
 *
 * @param {String} to
 * @return {Array} [ controller, action ]
 */
function splitTo() {
  let to = arguments.length <= 0 || arguments[0] === undefined ? '' : arguments[0];

  if (/#/.test(to)) {
    return to.split('#');
  }
  return [];
}

/**
 * Normalize Path
 *
 * @param {String} path
 * @return {String}
 */
function normalizePath(path) {
  path = '/' + path;
  path = (0, _path.resolve)((0, _path.normalize)(path));
  path = path.replace(/(%[a-f0-9]{2})/g, $1 => $1.toUpperCase());
  if (path === '') path = '/';
  return path;
}

/**
 * Parse the arguments and return an special array.
 *
 * @example
 *  parseArgs(path)
 *  // => [[path], {}, undefined]
 *  parseArgs(path, cb)
 *  // => [[path], {}, cb]
 *  parseArgs(path, options)
 *  // => [[path], options, undefined]
 *  parseArgs(options)
 *  // => [[], options, undefined]
 *
 * @param {Array|ArrayLike} args
 * @return {Array} [ [path, path], {}, function ]
 */
function parseArgs() {
  for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
    args[_key] = arguments[_key];
  }

  const l = args.length;
  const last = args[l - 1];
  let cb, opts, paths;
  if (_lodash2.default.isFunction(last)) {
    cb = last;
    args.pop(); // don't remove this semicolon

    var _parseArgs = parseArgs(...args);

    var _parseArgs2 = _slicedToArray(_parseArgs, 2);

    paths = _parseArgs2[0];
    opts = _parseArgs2[1];
  } else if (_lodash2.default.isObject(last) && !Array.isArray(last)) {
    opts = last;
    args.pop();
    paths = args;
  } else if (!last && l > 0) {
    args.pop();
    return parseArgs(...args);
  } else {
    paths = args;
  }
  return [_lodash2.default.compact(_lodash2.default.flatten(paths, true)), opts || {}, cb];
}

const mergeScope = {

  // parent/child
  path(parent, child) {
    return parent ? normalizePath(`${ parent }/${ child }`) : child;
  },

  // parent_child
  as(parent, child) {
    return parent ? `${ parent }_${ child }` : child;
  },

  // parent/child
  module(parent, child) {
    return parent ? normalizePath(`${ parent }/${ child }`) : child;
  },

  controller(parent, child) {
    return child;
  },

  action(parent, child) {
    return child;
  },

  pathNames(parent, child) {
    return this.options(parent, child);
  },

  options(parent, child) {
    const excepts = this.overrideKeys(child);
    return Object.assign(_lodash2.default.omit(parent, excepts), child);
  },

  overrideKeys(child) {
    return child.only || child.except ? ['only', 'except'] : [];
  }

};

exports.default = {
  splitTo,
  parseArgs,
  mergeScope,
  normalizePath
};


/*
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

'use strict';

var path = require('path');
var _ = require('lodash');
var fse = require('fs-extra');
var git = require('./gitutil');
var blank = {};
var SYSREPO = '_sys';

/**
 * maintains system repository conaining system meta information
 * maintains system commit log and history using nodegit
 * uses master branch only
 * need to be able to create a new repo on demand - for new system definition
 */
module.exports = function(options) {

  var _systems;
  var sysRepoPath = path.join(options.systemsRoot, SYSREPO);
  var systemsJsonPath = path.join(sysRepoPath, 'systems.json');

  /**
   * ensures that the system repository is in place, creates it if doesn't exist
   */
  var boot = function(cb) {
    fse.readFile(systemsJsonPath, 'utf8', function(err, data) {
      if (err) {
        if (err.code !== 'ENOENT') { return cb(err); }

        fse.mkdirpSync(sysRepoPath);
        fse.writeFileSync(systemsJsonPath, JSON.stringify(blank, null, 2), 'utf8');
        return git.createRepository(sysRepoPath, 'system', 'system@nfd.com', function(err_) {
          _systems = blank;
          cb(err_);
        });
      }

      _systems = JSON.parse(data);
      cb();
    });
  };

  /**
   * register a system
   */
  var register = function(user, namespace, name, repoName, repoPath, systemId, cb) {
    if (!_systems[systemId]) {
      _systems[systemId] = { name: name, namespace: namespace, repoName: repoName, repoPath: repoPath };
      fse.writeFileSync(systemsJsonPath, JSON.stringify(_systems, null, 2), 'utf8');
      git.commit(sysRepoPath, 'registered system: ' + repoPath, user.name, user.email, cb);
    }
    else {
      cb(null);
    }
  };

  /**
   * unregister a system
   */
  var unregister = function(user, systemId, cb) {
    if (!_systems[systemId]) { return cb(); }
    var newSystems = _.clone(_systems);
    delete newSystems[systemId];
    fse.writeFileSync(systemsJsonPath, JSON.stringify(newSystems, null, 2), 'utf8');
    _systems = newSystems;
    git.commit(sysRepoPath, 'unregistered system: ' + systemId, user.name, user.email, cb);
  };

  /**
   * returns a repository path from a system id
   */
  var repoPath = function(systemId) {
    return _systems[systemId].repoPath;
  };

  var repoId = function(repoName) {
    var systemId = _.find(_.keys(_systems), function(systemId) { return _systems[systemId].repoName === repoName; });
    return systemId;
  };

  var listSystems = function() {
    var result = [];
    _.each(_.keys(_systems), function(system) {
      result.push({name: _systems[system].name, id: system});
    });
    return result;
  };

  /**
   * convert identifier into full system guid using:
   * 1) exact match on key
   * 2) partial match on key
   * 3) partial match on name
   */
  var findSystem = function(identifier) {
    identifier = identifier.replace(/[.+]/g, function(match) {
      return '\\' + match;
    });

    var re = new RegExp('^' + identifier + '.*', ['i']);
    var systemId;

    systemId = _.find(_.keys(_systems), function(system) { return system === identifier; });

    if (!systemId) {
      systemId = _.find(_.keys(_systems), function(system) { return re.test(system); });
    }

    if (!systemId) {
      systemId = _.find(_.keys(_systems), function(system) { return re.test(_systems[system].name); });
    }

    return systemId;
  };

  var systemExists = function(namespace, name) {
    var system = _.find(_systems, function(system) { return system.namespace === namespace && system.name === name; });
    return fse.existsSync(system.repoPath + '/system.json');
  };

  return {
    boot: boot,
    register: register,
    unregister: unregister,
    repoPath: repoPath,
    repoId: repoId,
    listSystems: listSystems,
    findSystem: findSystem,
    systemExists: systemExists
  };
};


var Context = require("./di"),
    Collection = require("./collection"),
    Object = require("./object"),
    utils = require("./utils");

/**
 * Creates a simple component tree-like architecture for the view layer. Used with DI
 * @alias Component
 */
var Component = Object.extend({

    $meta: {
        domProcessors: [utils.domProcessors.createComponents, utils.domProcessors.injectElement]
    },

    tag: "",

    html: "",

    root: {
        get: function() {
            return this._root;
        },
        set: function(value) {
            this._root = value;
            this.processRoot();
        }
    },

    parent: null,

    children: {
        get: function() {
            return this._children;
        }
    },

    /**
     * Init the object, construct and process DOM
     */
    $create: function() {
        var domWrapper;

        this._children = [];
        this._createRootHtml();

        domWrapper = utils.html.parseHTML(this.html);
        if (domWrapper.childNodes.length > 1) {
            throw new Error("Component should have only one root element");
        }
        this.root = domWrapper.firstChild;

        this.processInstance();
    },

    /**
     * Process DOM using defined DOM processors
     */
    processRoot: function() {
        var i, elements, element, value;
        if (this._root) {
            (this.$meta.domProcessors || []).forEach(function(processor) {
                elements =  this._root.querySelectorAll("[" + processor.attribute + "]");
                for (i = 0; i < elements.length; i++) {
                    element = elements[i];
                    value = element.getAttribute(processor.attribute);
                    processor.process(this, element, value);
                }
            }, this);
        }
    },

    /**
     * Process instance applying shortcuts defined in metadata
     */
    processInstance: function() {
        utils.meta(this, "renderWith", function(property) {
            this[property] = Collection.create(this[property] || []);
        }.bind(this));
    },

    processBinding: {
        injectInit: true,
        value: function() {
            var properties;

            utils.meta(this, "bindWith", function(property, meta) {
                properties = utils.isPrimitive(meta) ? [meta] : meta;
                properties.forEach(function(propertyToBind) {
                    utils.bind(this, propertyToBind, this[property]);
                }, this);
            }.bind(this));

            utils.meta(this, "renderWith", function(property, meta) {
                utils.renderList(this, property, meta);
            }.bind(this));
        }
    },

    /**
     * @type {Function}
     */
    __fastinject__: {
        get: function() {return this.___fastinject___;},
        set: function(value) {
            if (!this.___fastinject___) {
                this.___fastinject___ = value;
                // fastinject all the children
                this._children.forEach(this.__fastinject__, this);

                if (this.$meta.presenter) {
                    this.__presenter__ = this.$meta.presenter.create();
                }

            }
        }
    },

    __presenter__: {
        get: function() {
            return this.___presenter___;
        },
        set: function(presenter) {
            this.___presenter___ = presenter;
            presenter.view = this;
            this.___fastinject___(presenter);
        }
    },

    /**
     * Template method, used to create DOM of the component
     */
    init: {
        injectInit: true,
        value: function() {}
    },

    /**
     * Destroy the component and all child components
     */
    destroy: {
        injectDestroy: false,
        value: function() {
            if (this.__presenter__ && this.__presenter__.destroy) {
                this.__presenter__.destroy();
            }
            this.removeAll();
        }
    },

    /**
     * Add a child component
     * @param {Component} child
     */
    add: function(child) {
        this._validateChild(child);
        if (child.parent) {
            child.parent.remove(child);
        }
        child.parent = this;
        this._children.push(child);
        this.root.appendChild(child.root);
        if (this.__fastinject__) {
            this.__fastinject__(child);
        } // otherwise it will be injected when __fastinject__ is set
    },

    /**
     * Validates if child is correctly defined
     * @param {Component} child
     * @private
     */
    _validateChild: function(child) {
        if (!child) {
            throw new Error("Child component cannot be null");
        }
        if (!child.root) {
            throw new Error("Child component should have root property");
        }
    },

    /**
     * Create root html (if not defined) based on "tag" property (defaulting to "div")
     * @private
     */
    _createRootHtml: function() {
        if (!this.tag && !this.html) {
            this.tag = "div";
        }

        if (this.tag && !this.html) {
            this.html = "<" + this.tag + "></" + this.tag + ">";
        }
    },

    /**
     * Remove child component
     * @param {Component} child
     */
    remove: function(child) {
        var index = this._children.indexOf(child);
        if (index !== -1) {
            this._children.splice(index, 1);
            child.root.parentNode.removeChild(child.root);
            child.destroy();
        }
    },

    /**
     * Remove all children component
     */
    removeAll: function() {
        this._children.concat().forEach(function(child) {
            this.remove(child);
        }, this);
    },

    /**
     * Attaches a component by replacing the provided element. Element must be an element inside the parent component.
     * @param {Component} child
     * @param {Element} element
     * @param {HTMLElement} root if different than child.root
     */
    attach: function(child, element, root) {
        this._children.push(child);
        (root || this.root).insertBefore(child.root, element);
        (root || this.root).removeChild(element);
    },

    /**
     * Attaches the component to a root created on a provided element
     * @param element
     * @param context
     */
    attachTo: function(element, context) {
        var parent = Component.Root(element, context);
        parent.add(this);
    }
});

/**
 *
 * @param {HTMLElement} element
 * @param {Context} [context]
 * @returns {Component}
 * @constructor
 */
Component.Root = function(element, context) {
    var component = Component.create();
    context = context || Context.create();
    component.root = element;
    context.register(component);
    return component;
};

Component.Mount = function(tag, Component, context) {
    var elements, element, component;

    elements = document.getElementsByTagName(tag);

    if (!context) {
        context = Context.create();
        context.build();
    }

    for (var i=0; i < elements.length; i++) {
        element = elements[i];
        component = Component.create();

        element.parentNode.insertBefore(component.root, element);
        element.parentNode.removeChild(element);

        context.register(component);
        context.process(component);
    }

    return component;
};

module.exports = Component;


/*
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

'use strict';

var path = require('path');
var async = require('async');
var _ = require('lodash');
var fse = require('fs-extra');
var fs = require('fs');
var uuid = require('uuid');
var git = require('./gitutil');
var ngit = require('nodegit');
var srMeta = require('./sysrevMeta');
var generify = require('generify');
var path = require('path');
var split2 = require('split2');
var callback = require('callback-stream');
var baseTag = 'refs/tags/deployed-';
var editsTag = 'refs/tags/edits-';
var blank = {'name': '',
             'namespace': '',
             'id': '',
             'containerDefinitions': [],
             'topology': {'containers': {}}};
var EDITS = 'edits';

/**
 * maintains system commit log and history using nodegit
 * uses master branch only
 * need to be able to create a new repo on demand - for new system definition
 */
module.exports = function(options, logger) {

  var _meta;

  /**
   * ensures that system has all required files
   */
  var initNscaleFiles = function(repoPath, doc, done) {
    generify(path.join(__dirname, 'template'), repoPath, {
      name: doc.name,
      namespace: doc.namespace,
      id: doc.id
    }, done);
  };

  /**
   * checks if a directory is a system (has all the required files and correct
   * system.json and system.js
   */
  var validateSystem = function(repoPath) {
    var sys;

    if (fse.existsSync(path.join(repoPath, 'system.js'))) {
      // TODO extract in its own module
      sys = require(repoPath + '/system.js');
      delete require.cache[repoPath + '/system.js'];
    }

    if (!sys) {
      return new Error('missing system.js, is this an nscale repository?');
    }
    if (!sys.name) {
      return new Error('missing name in system.js, correct and try again');
    }
    if (!sys.namespace) {
      return new Error('missing namespace in system.js, correct and try again');
    }
    if (!sys.id) {
      return new Error('missing id in system.js, correct and try again');
    }
  };

  /**
   * timeline format
   * [{user: user, ts: new Date(), type: entryType, details: details },...
   * custom values can be provided through the details object
   */
  // TODO change the format to include all the details in the main object
  var writeTimeline = function(user, systemId, entryType, details, cb) {
    var file = path.join(options.timelinesRoot, findSystem(systemId));
    if (typeof details === 'function') {
      cb = details;
      details = {};
    } else if (!details) {
      details = {};
    }

    var entry = {v: 0, user: user, ts: new Date(), type: entryType, details: details};
    fs.writeFile(file, JSON.stringify(entry) + '\n', { flag: 'a' }, function() {
      // error is swallowed, as this file does not really matter
      cb();
    });
  };

  var getTimeline = function(systemId, cb) {
    var file = path.join(options.timelinesRoot, findSystem(systemId));

    fs.createReadStream(file)
      .once('error', cb)
      .pipe(split2(function(line) {
        try {
          return JSON.parse(line);
        } catch(err) {
          // swallow bad lines
          return undefined;
        }
      }))
      .pipe(callback({ objectMode: true }, function(err, timeline) {
        if (err) { return cb(err); }
        cb(null, timeline.reverse());
      }));
  };

  /**
   * make a commit to local git repository
   * TODO: implement seperate push functionality
   * TODO: replace with git hub id
   */
  var commit = function(user, systemId, message, cb) {
    logger.info('committing revision: ' + systemId + ', ' + message);
    var repoPath = _meta.repoPath(systemId);
    git.commit(repoPath, message, user.name, user.email, cb);
  };

  /**
   * create a new system repository
   */
  var createSystem = function(user, namespace, name, cwd, cb) {
    var repoName = name;
    var doc = _.extend({}, blank);
    var repoPath = path.join(cwd, repoName);

    doc.name = name;
    doc.namespace = namespace;
    doc.id = uuid.v4();

    if (!fse.existsSync(repoPath)) {
      fse.mkdirpSync(repoPath);
      initNscaleFiles(repoPath, doc, function() {
        git.createRepository(repoPath, user.name, user.email, function(err) {
          if (err) { return cb(err); }
          _meta.register(user, namespace, name, repoName, cwd + '/' + repoName, doc.id, function(err) {
            writeTimeline(user, doc.id, 'create', 'system created', function() {
              // swallow any errors here
              cb(err, {id: doc.id, err: err});
            });
          });
        });
      });
    }
    else {
      cb(null, { id: _meta.repoId(repoName), err: null});
    }
  };

  /**
   * create a new system by linking from local file system
   */
  var linkSystem = function(user, path_, cwd, cb) {
    var repoPath = path.resolve(cwd, path_);
    var sys;

    var validationError = validateSystem(repoPath);
    if (validationError) { return cb(validationError); }
    sys = require(repoPath + '/system.js');
    delete require.cache[repoPath + '/system.js'];

    _meta.register(user, sys.namespace, sys.name, path.basename(repoPath), repoPath, sys.id, function(err) {
      writeTimeline(user, sys.id, 'link', 'system linked', function() {
        cb(err, {id: sys.id, err: err});
      });
    });
  };

  /**
   * unlink system from the daemon
   */
  var unlinkSystem = function(user, systemId, cb) {
    writeTimeline(user, systemId, 'system unlinked', function() {
      // swallow any errors here
      _meta.unregister(user, systemId, function(err) {
        cb(err);
      });
    });
  };

  var systemExists = function(namespace, name) {
    return _meta.systemExists(namespace, name);
  };

  /**
   * commit a new version of the system, the head of the commit log
   * may be ahead of the actual deployed version of the system
   */
  var commitRevision = function(user, systemId, description, cb) {
    commit(user, systemId, description, cb);
  };

  /**
   * commit a new version of the system, the head of the commit log
   * may be ahead of the actual deployed version of the system
   */
  var writeFile = function(systemId, fileName, contents, cb) {
    var repoPath = _meta.repoPath(systemId);
    fse.writeFile(path.join(repoPath, fileName), contents, 'utf8', cb);
  };

  /**
   * get the head revision for a system
   */
  var getHead = function(systemId, target, cb) {
    listRevisions(systemId, function(err, revs) {
      if (err) { return cb(err); }
      getRevision(systemId, revs[0].id, target, cb);
    });
  };

  /**
   * get the head revision id for a system
   */
  var getHeadRevisionId = function(systemId, cb) {
    listRevisions(systemId, function(err, revs) {
      cb(err, revs && revs[0] && revs[0].id);
    });
  };

  /**
   * get the head revision id for a system
   */
  var getComittedHeadRevisionId = function(systemId, cb) {
    listRevisions(systemId, function(err, revs) {
      if (revs[0].id === EDITS) {
        cb(err, revs && revs[1] && revs[1].id);
      }
      else {
        cb(err, revs && revs[0] && revs[0].id);
      }
    });
  };

  /**
   * get a revision from the history, with a specific version number
   */
  var _getRevision = function(systemId, revisionId, target, cb) {
    var repoPath = _meta.repoPath(systemId);
    git.getFileRevision(repoPath, revisionId, target + '.json', function(err, rev) {
      if (err) { return cb(err); }

      var s;
      try {
        s = JSON.parse(rev);
      }
      catch (e) {
        return cb(new Error('invalid system definition: ' + e.message), null);
      }
      cb(err, s);
    });
  };

  var _getOnDiskVersion = function(systemId, revisionId, target, cb) {
    var repoPath = _meta.repoPath(systemId);
    fs.readFile(repoPath + '/' + target + '.json', 'utf8', function(err, rev) {
      if (err) { return cb(err); }

      var s;
      try {
        s = JSON.parse(rev);
      }
      catch (e) {
        return cb(new Error('invalid system definition: ' + e.message), null);
      }
      cb(err, s);
    });
  };

  /**
   * get a revision from the history, with abbreviation support
   */
  var getRevision = function(systemId, revisionId, target, cb) {
    if (revisionId === EDITS) {
      _getOnDiskVersion(systemId, revisionId, target, cb);
    }
    else {
      findRevision(systemId, revisionId, function(err, rev) {
        if (err) { return cb(err); }
        if (rev === EDITS) {
          _getOnDiskVersion(systemId, revisionId, target, cb);
        }
        else {
          _getRevision(systemId, rev, target, cb);
        }
      });
    }
  };

  /*
tesnt this to fuck and PR and release
  move onto proxy - must be testing it tomorrow night
  app dynamics only - load to AJ
  */

  /**
   * set the currently deployed revision, there will only ever be one deployed revision
   * clear the currently deployed flag and set the deployed flag against the specified revision
   */
  var markDeployedRevision = function(user, systemId, revisionId, env, cb) {
    var repoPath = _meta.repoPath(systemId);
    var removeTag;
    var addTag;
    var revId;

    getComittedHeadRevisionId(systemId, function(err, comittedHeadId) {
      if (revisionId === EDITS) {
        removeTag = baseTag + env;
        addTag = editsTag + env;
        revId = comittedHeadId;
      }
      else {
        addTag = baseTag + env;
        removeTag = editsTag + env;
        revId = revisionId;
      }

      ngit.Repository.open(repoPath, function(err, repo) {
        if (err) { return cb(err); }
        ngit.Reference.remove(repo, removeTag);
        repo.getCommit(revId, function(err, commit) {
          if (err) { return cb(err); }
          var now = Math.round(Date.now() / 1000);
          var author = ngit.Signature.create(user.name, user.email, now, 0);
          ngit.Reference.create(repo, addTag, commit, 1, author, 'Tagged ' + addTag)
            .then(function() {
              writeTimeline(user, systemId, 'deployed revision', revisionId, function() {
                cb();
              });
            })
            .catch(cb);
        });
      });
    });
  };

  /**
   * get the currently deployed revision
   */
  var getDeployedRevisionId = function(systemId, env, cb) {
    var repoPath = _meta.repoPath(systemId);
    var tagName = baseTag + env;
    var editsTagName = editsTag + env;

    ngit.Repository.open(repoPath, function(err, repo) {
      if (err) { return cb(err); }

      ngit.Reference.nameToId(repo, tagName, function(err, head) {
        if (err && (!err.message || err.message.indexOf('not found') === -1)) { return cb(err); }
        if (head) {
          cb(null, head.toString());
        }
        else {
          ngit.Reference.nameToId(repo, editsTagName, function(err) {
            if (err) { return cb(err); }
            cb(null, EDITS);
          });
        }
      });
    });
  };

  var getDeployedTargets = function(systemId, cb) {
    var repoPath = _meta.repoPath(systemId);

    ngit.Repository.open(repoPath, function(err, repo) {
      if (err) { return cb(err); }
      ngit.Reference.list(repo, function(err, refNames) {
        if (err) { return cb(err); }

        var deployed = refNames.filter(function(ref) {
          return ref.indexOf(baseTag) === 0 || ref.indexOf(editsTag) === 0;
        });

        async.map(deployed, function(ref, cb) {
          var env = ref.replace(baseTag, '');
          env = env.replace(editsTag, '');
          ngit.Reference.nameToId(repo, ref, function(err, commit) {
            if (err) { return cb(err); }
            if (ref.indexOf(baseTag) >= 0) {
              cb(null, {env: env, commit: commit.toString()});
            }
            else {
              cb(null, {env: env, commit: EDITS});
            }
          });
        }, cb);
      });
    });
  };

  /**
   * get the currently deployed revision
   */
  var getDeployedRevision = function(systemId, target, cb) {
    getDeployedRevisionId(systemId, target, function(err, revisionId) {
      if (err) { return cb(err); }
      if (revisionId === EDITS) {
        _getOnDiskVersion(systemId, revisionId, target, cb);
      }
      else {
        _getRevision(systemId, revisionId, target, cb);
      }
    });
  };

  /**
   * list all of the available revisions in the system
   */
  var listRevisions = function(systemId, cb) {
    var repoPath = _meta.repoPath(systemId);
    getDeployedTargets(systemId, function(err, targets) {
      if (err) { return cb(err); }
      git.listRevisions(repoPath, function(err, revisions) {
        revisions.forEach(function(revision) {
          var deployedTo = _.find(targets, function(target) { return target.commit === revision.id; });
          if (deployedTo) {
            revision.deployedTo = deployedTo.env;
          }
        });
        cb(err, revisions);
      });
    });
  };

  /**
   * find revision id by parital or full identifier
   */
  var findRevision = function(systemId, identifier, cb) {
    var re = new RegExp('^' + identifier + '.*', ['i']);
    var revision;

    if (identifier !== 'head' && identifier !== 'latest') {
      listRevisions(systemId, function(err, revisions) {
        revision = _.find(revisions, function(revision) { return re.test(revision.id); });
        if (revision) {
          cb(err, revision.id);
        }
        else {
          cb(new Error('revision not found'));
        }
      });
    }
    else {
      getHeadRevisionId(systemId, cb);
    }
  };

  var boot = function(cb) {
    _meta = srMeta(options);
    _meta.boot(cb);
  };

  var listSystems = function() {
    return _meta.listSystems();
  };

  var findSystem = function(identifier) {
    return _meta.findSystem(identifier);
  };

  var findContainer = function(systemId, revision, identifier, target, cb) {
    var containerId;
    var containerDef;

    getRevision(systemId, revision, target, function(err, data) {
      if (err) { return cb(err); }
      if (data.containerDefinitions.length > 0) {
        _.each(data.containerDefinitions, function(cdef) {
          if (cdef.id === identifier) {
            containerId = cdef.id;
            containerDef = cdef;
          }
          else if (cdef.id.indexOf(identifier) !== -1) {
            containerId = cdef.id;
            containerDef = cdef;
          }
          else if (cdef.name === identifier) {
            containerId = cdef.id;
            containerDef = cdef;
          }
        });
        cb(null, containerId, containerDef);
      }
      else {
        cb(new Error('getHead returned 0 data'));
      }
    });
  };

  var repoPath = function(systemId) {
    return _meta.repoPath(systemId);
  };

  return {
    boot: boot,
    createSystem: createSystem,
    linkSystem: linkSystem,
    unlinkSystem: unlinkSystem,
    systemExists: systemExists,
    commitRevision: commitRevision,
    writeFile: writeFile,
    markDeployedRevision: markDeployedRevision,
    getDeployedRevision: getDeployedRevision,
    getDeployedRevisionId: getDeployedRevisionId,
    listRevisions: listRevisions,
    getHead: getHead,
    getHeadRevisionId: getHeadRevisionId,
    getRevision: getRevision,
    listSystems: listSystems,
    findSystem: findSystem,
    findContainer: findContainer,
    findRevision: findRevision,
    getTimeline: getTimeline,
    writeTimeline: writeTimeline,
    repoPath: repoPath,
    getDeployedTargets: getDeployedTargets
  };
};


/* jshint node: true */
'use strict';

var path = require('path');

var _emojiConfig = {};
var _defaultEmojiConfig = {
  mode: 'sprites',
  tag_type: 'span',
  img_dir: 'images/emoji',
  ignore_emoticons: false,
  blacklist: {
    elements: ['script', 'textarea', 'a', 'pre', 'code'],
    classes: ['no-emojify']
  }
};

module.exports = {
  name: 'ember-cli-emoji',

  /**
   * Import javascript depending on the *mode*. We currently support
   * `sprite` and `data-uri` modes (NO basic image mode).
   */
  included: function(app, parentAddon) {
    this._super.included(app);

    var target = (parentAddon || app);

    target.import(target.bowerDirectory + '/emojify/dist/js/emojify.js');

    if (_emojiConfig.mode === 'sprites') {
      var destSpriteDir = 'images/sprites';
      var spritePath    = '/emojify/dist/images/sprites/';

      target.import(target.bowerDirectory + spritePath + 'emojify.png', {
        destDir: destSpriteDir
      });
      target.import(target.bowerDirectory + spritePath + 'emojify@2x.png', {
        destDir: destSpriteDir
      });
    }

  },

  /**
   * Allows custom configuration from `environment`
   */
  config: function (environment, baseConfig) {
    if ('emoji' in baseConfig) {
      if (!baseConfig.emoji) {
        _emojiConfig = false;
      } else {
        Object.keys(_defaultEmojiConfig).forEach(function (key) {
          _emojiConfig[key] = baseConfig.emoji.hasOwnProperty(key) ? baseConfig.emoji[key] : _defaultEmojiConfig[key];
        });
      }
    } else {
      _emojiConfig = _defaultEmojiConfig;
    }

    if (environment === 'development') {
      return {
        emoji: _emojiConfig,
        contentSecurityPolicy: {
          'script-src': "'self' 'unsafe-eval' 'unsafe-inline'"
        }
      };
    }

    return {
      emoji: _emojiConfig
    };
  },

  /**
   * Import style depending on the *mode*. We currently support
   * `sprite` and `data-uri` modes (NO basic image mode).
   */
  treeForStyles: function () {
    var emojiDataURIPath = path.join(this.app.bowerDirectory,
          'emojify/dist/css/data-uri/emojify.css'),
        emojiSpritesPath = path.join(this.app.bowerDirectory,
          'emojify/dist/css/sprites/emojify.css');

    if (_emojiConfig.mode === 'data-uri') {
      this.app.import(emojiDataURIPath);
    } else {
      this.app.import(emojiSpritesPath);
    }
  },

  /**
   * Setup `emojify` configuration inline
   */
  contentFor: function (name) {
    if (name === 'body-footer') {
      return '<script type="text/javascript">emojify.setConfig(' + JSON.stringify(_emojiConfig) +')</script>';
    }
  }

};


/*
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

'use strict';

var _ = require('lodash');
var pxy = require('nscale-proxy')();
var async = require('async');

module.exports = function(loadConfig, _containers) {

  /**
   * Determine the target containers - machine containers that have a proxy on them.
   */
  var determineTargets = function(analyzed) {
    var containers = analyzed.topology.containers;
    var targets = [];

    _.each(containers, function(c) {
      if (c.containerDefinitionId.indexOf('__proxy') === 0) {
        var cdef = _.find(analyzed.containerDefinitions, function(cdef) { return cdef.id === c.containerDefinitionId; });
        targets.push({containerDef: cdef, container: c});
      }
    });
    return targets;
  };

  /**
   * generate a new proxy configuration, distribute to all containers and hup all
   */
  var hupAllProxies = function hupAll(mode, target, system, analyzed, out, cb) {
    var targetProxies;
    var host = 'unspecified';

    loadConfig(system, function(err, cfg) {
      if (err) { return cb(err); }
      if (cfg.enableProxy && _.find(cfg.enableProxy, function(p) { return p === target; })) {
        pxy.generate(system, analyzed, function(err, haConfig) {
          if (err) { return cb(err); }

          targetProxies = determineTargets(analyzed);
          async.eachSeries(targetProxies, function(targetProxy, next) {
            _containers.getHandler(system, targetProxy.containerDef.type, function(err, impl) {
              if (err) { return cb(err); }
              if (!impl) { return cb(new Error(err)); }
              if (!impl.hup) { return cb(new Error('container mismatch - no hup command')); }

              if (mode === 'preview') {
                if (analyzed.topology.containers[targetProxy.containedBy]) {
                  host = analyzed.topology.containers[targetProxy.containedBy];
                }
                out.preview({cmd: 'HUP: ' + targetProxy.containerDef.name, host: host});
              }

              if (analyzed.topology.containers[targetProxy.container.containedBy] && analyzed.topology.containers[targetProxy.container.containedBy].specific) {
                impl.hup(mode, analyzed.topology.containers[targetProxy.container.containedBy].specific, system, targetProxy.containerDef, targetProxy.container, haConfig, out, function(err) {
                  if (err) { return next(err); }
                  next();
                });
              }
              else {
                cb(new Error('no specific block available for hup'));
              }
            });
          }, function(err) {
            cb(err);
          });
        });
      }
      else {
        cb();
      }
    });
  };

  return {
    hupAllProxies: hupAllProxies
  };
};


"use strict";

var Origin = require('origin');

exports.Storable = Origin.Responder.extend({

  initializer : function() {
    this.parent(Origin.Responder).constructor();

    // If a collection was specified for this class, add this instance
    // to that collection now.
    var cls = this.cls();
    while(cls) {
      if (cls.collection) {
        cls.collection.add(this);
        break;
      }
      cls = cls.superclass ? cls.superclass() : false;
    }
  },

  properties : {

    id : undefined,

    destroy: function() {
      if (!this.isDestroyed()) {
        this._destroyed = true;
        this.unbindFromAll();
        this.trigger("destroy");
      }
    },

    isDestroyed: function() {
      return this._destroyed;
    }

  },

  classProperties: {

    collection : false,

    /*
       Function: getCollection
       Looks for a collection object attached to the current class. If one is not
       found, it traverses the ancestor tree looking for the closest class that
       has a collection object associated with it, and returns that collection.

       Parameters:
          cls - (Optional) A class in the ancestor hierarchy to start the serach with.
          If none is provided, the search will start with the current class.

       Returns:
          A collection object if one is found, or false.
    */
    getCollection: function(cls) {

      if (this.collection) {
        return this.collection;
      }

      cls = (cls) ? this.superclass(cls) : this;

      while(cls) {
        if (cls.collection) {
          this.collection = cls.collection;
          return cls.collection;
        }
      }

      return false;
    }
  }
});