<commit_before>'use strict';

var bind = require('./helpers/bind');
var isBuffer = require('is-buffer');

/*global toString:true*/

// utils is a library of generic helper functions non-specific to axios

var toString = Object.prototype.toString;

/**
 * Determine if a value is an Array
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is an Array, otherwise false
 */
function isArray(val) {
  return toString.call(val) === '[object Array]';
}

/**
 * Determine if a value is an ArrayBuffer
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is an ArrayBuffer, otherwise false
 */
function isArrayBuffer(val) {
  return toString.call(val) === '[object ArrayBuffer]';
}

/**
 * Determine if a value is a FormData
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is an FormData, otherwise false
 */
function isFormData(val) {
  return (typeof FormData !== 'undefined') && (val instanceof FormData);
}

/**
 * Determine if a value is a view on an ArrayBuffer
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a view on an ArrayBuffer, otherwise false
 */
function isArrayBufferView(val) {
  var result;
  if ((typeof ArrayBuffer !== 'undefined') && (ArrayBuffer.isView)) {
    result = ArrayBuffer.isView(val);
  } else {
    result = (val) && (val.buffer) && (val.buffer instanceof ArrayBuffer);
  }
  return result;
}

/**
 * Determine if a value is a String
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a String, otherwise false
 */
function isString(val) {
  return typeof val === 'string';
}

/**
 * Determine if a value is a Number
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a Number, otherwise false
 */
function isNumber(val) {
  return typeof val === 'number';
}

/**
 * Determine if a value is undefined
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if the value is undefined, otherwise false
 */
function isUndefined(val) {
  return typeof val === 'undefined';
}

/**
 * Determine if a value is an Object
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is an Object, otherwise false
 */
function isObject(val) {
  return val !== null && typeof val === 'object';
}

/**
 * Determine if a value is a Date
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a Date, otherwise false
 */
function isDate(val) {
  return toString.call(val) === '[object Date]';
}

/**
 * Determine if a value is a File
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a File, otherwise false
 */
function isFile(val) {
  return toString.call(val) === '[object File]';
}

/**
 * Determine if a value is a Blob
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a Blob, otherwise false
 */
function isBlob(val) {
  return toString.call(val) === '[object Blob]';
}

/**
 * Determine if a value is a Function
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a Function, otherwise false
 */
function isFunction(val) {
  return toString.call(val) === '[object Function]';
}

/**
 * Determine if a value is a Stream
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a Stream, otherwise false
 */
function isStream(val) {
  return isObject(val) && isFunction(val.pipe);
}

/**
 * Determine if a value is a URLSearchParams object
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a URLSearchParams object, otherwise false
 */
function isURLSearchParams(val) {
  return typeof URLSearchParams !== 'undefined' && val instanceof URLSearchParams;
}

/**
 * Trim excess whitespace off the beginning and end of a string
 *
 * @param {String} str The String to trim
 * @returns {String} The String freed of excess whitespace
 */
function trim(str) {
  return str.replace(/^\s*/, '').replace(/\s*$/, '');
}

/**
 * Determine if we're running in a standard browser environment
 *
 * This allows axios to run in a web worker, and react-native.
 * Both environments support XMLHttpRequest, but not fully standard globals.
 *
 * web workers:
 *  typeof window -> undefined
 *  typeof document -> undefined
 *
 * react-native:
 *  navigator.product -> 'ReactNative'
 */
function isStandardBrowserEnv() {
  if (typeof navigator !== 'undefined' && navigator.product === 'ReactNative') {
    return false;
  }
  return (
    typeof window !== 'undefined' &&
    typeof document !== 'undefined'
  );
}

/**
 * Iterate over an Array or an Object invoking a function for each item.
 *
 * If `obj` is an Array callback will be called passing
 * the value, index, and complete array for each item.
 *
 * If 'obj' is an Object callback will be called passing
 * the value, key, and complete object for each property.
 *
 * @param {Object|Array} obj The object to iterate
 * @param {Function} fn The callback to invoke for each item
 */
function forEach(obj, fn) {
  // Don't bother if no value provided
  if (obj === null || typeof obj === 'undefined') {
    return;
  }

  // Force an array if not already something iterable
  if (typeof obj !== 'object') {
    /*eslint no-param-reassign:0*/
    obj = [obj];
  }

  if (isArray(obj)) {
    // Iterate over array values
    for (var i = 0, l = obj.length; i < l; i++) {
      fn.call(null, obj[i], i, obj);
    }
  } else {
    // Iterate over object keys
    for (var key in obj) {
      if (Object.prototype.hasOwnProperty.call(obj, key)) {
        fn.call(null, obj[key], key, obj);
      }
    }
  }
}

/**
 * Accepts varargs expecting each argument to be an object, then
 * immutably merges the properties of each object and returns result.
 *
 * When multiple objects contain the same key the later object in
 * the arguments list will take precedence.
 *
 * Example:
 *
 * ```js
 * var result = merge({foo: 123}, {foo: 456});
 * console.log(result.foo); // outputs 456
 * ```
 *
 * @param {Object} obj1 Object to merge
 * @returns {Object} Result of all merge properties
 */
function merge(/* obj1, obj2, obj3, ... */) {
  var result = {};
  function assignValue(val, key) {
    if (typeof result[key] === 'object' && typeof val === 'object') {
      result[key] = merge(result[key], val);
    } else {
      result[key] = val;
    }
  }

  for (var i = 0, l = arguments.length; i < l; i++) {
    forEach(arguments[i], assignValue);
  }
  return result;
}

/**
 * Function equal to merge with the difference being that no reference
 * to original objects is kept.
 *
 * @see merge
 * @param {Object} obj1 Object to merge
 * @returns {Object} Result of all merge properties
 */
function deepMerge(/* obj1, obj2, obj3, ... */) {
  var result = {};
  function assignValue(val, key) {
    if (typeof result[key] === 'object' && typeof val === 'object') {
      result[key] = deepMerge(result[key], val);
    } else if (typeof val === 'object') {
      result[key] = deepMerge({}, val);
    } else {
      result[key] = val;
    }
  }

  for (var i = 0, l = arguments.length; i < l; i++) {
    forEach(arguments[i], assignValue);
  }
  return result;
}

/**
 * Extends object a by mutably adding to it the properties of object b.
 *
 * @param {Object} a The object to be extended
 * @param {Object} b The object to copy properties from
 * @param {Object} thisArg The object to bind function to
 * @return {Object} The resulting value of object a
 */
function extend(a, b, thisArg) {
  forEach(b, function assignValue(val, key) {
    if (thisArg && typeof val === 'function') {
      a[key] = bind(val, thisArg);
    } else {
      a[key] = val;
    }
  });
  return a;
}

module.exports = {
  isArray: isArray,
  isArrayBuffer: isArrayBuffer,
  isBuffer: isBuffer,
  isFormData: isFormData,
  isArrayBufferView: isArrayBufferView,
  isString: isString,
  isNumber: isNumber,
  isObject: isObject,
  isUndefined: isUndefined,
  isDate: isDate,
  isFile: isFile,
  isBlob: isBlob,
  isFunction: isFunction,
  isStream: isStream,
  isURLSearchParams: isURLSearchParams,
  isStandardBrowserEnv: isStandardBrowserEnv,
  forEach: forEach,
  merge: merge,
  deepMerge: deepMerge,
  extend: extend,
  trim: trim
};
<commit_msg>[NS]: Send `false` flag isStandardBrowserEnv for Nativescript<commit_after>'use strict';

var bind = require('./helpers/bind');
var isBuffer = require('is-buffer');

/*global toString:true*/

// utils is a library of generic helper functions non-specific to axios

var toString = Object.prototype.toString;

/**
 * Determine if a value is an Array
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is an Array, otherwise false
 */
function isArray(val) {
  return toString.call(val) === '[object Array]';
}

/**
 * Determine if a value is an ArrayBuffer
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is an ArrayBuffer, otherwise false
 */
function isArrayBuffer(val) {
  return toString.call(val) === '[object ArrayBuffer]';
}

/**
 * Determine if a value is a FormData
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is an FormData, otherwise false
 */
function isFormData(val) {
  return (typeof FormData !== 'undefined') && (val instanceof FormData);
}

/**
 * Determine if a value is a view on an ArrayBuffer
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a view on an ArrayBuffer, otherwise false
 */
function isArrayBufferView(val) {
  var result;
  if ((typeof ArrayBuffer !== 'undefined') && (ArrayBuffer.isView)) {
    result = ArrayBuffer.isView(val);
  } else {
    result = (val) && (val.buffer) && (val.buffer instanceof ArrayBuffer);
  }
  return result;
}

/**
 * Determine if a value is a String
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a String, otherwise false
 */
function isString(val) {
  return typeof val === 'string';
}

/**
 * Determine if a value is a Number
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a Number, otherwise false
 */
function isNumber(val) {
  return typeof val === 'number';
}

/**
 * Determine if a value is undefined
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if the value is undefined, otherwise false
 */
function isUndefined(val) {
  return typeof val === 'undefined';
}

/**
 * Determine if a value is an Object
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is an Object, otherwise false
 */
function isObject(val) {
  return val !== null && typeof val === 'object';
}

/**
 * Determine if a value is a Date
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a Date, otherwise false
 */
function isDate(val) {
  return toString.call(val) === '[object Date]';
}

/**
 * Determine if a value is a File
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a File, otherwise false
 */
function isFile(val) {
  return toString.call(val) === '[object File]';
}

/**
 * Determine if a value is a Blob
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a Blob, otherwise false
 */
function isBlob(val) {
  return toString.call(val) === '[object Blob]';
}

/**
 * Determine if a value is a Function
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a Function, otherwise false
 */
function isFunction(val) {
  return toString.call(val) === '[object Function]';
}

/**
 * Determine if a value is a Stream
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a Stream, otherwise false
 */
function isStream(val) {
  return isObject(val) && isFunction(val.pipe);
}

/**
 * Determine if a value is a URLSearchParams object
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a URLSearchParams object, otherwise false
 */
function isURLSearchParams(val) {
  return typeof URLSearchParams !== 'undefined' && val instanceof URLSearchParams;
}

/**
 * Trim excess whitespace off the beginning and end of a string
 *
 * @param {String} str The String to trim
 * @returns {String} The String freed of excess whitespace
 */
function trim(str) {
  return str.replace(/^\s*/, '').replace(/\s*$/, '');
}

/**
 * Determine if we're running in a standard browser environment
 *
 * This allows axios to run in a web worker, and react-native.
 * Both environments support XMLHttpRequest, but not fully standard globals.
 *
 * web workers:
 *  typeof window -> undefined
 *  typeof document -> undefined
 *
 * react-native:
 *  navigator.product -> 'ReactNative'
 * nativescript
 *  navigator.product -> 'NativeScript' or 'NS'
 */
function isStandardBrowserEnv() {
  if (typeof navigator !== 'undefined' && (navigator.product === 'ReactNative' ||
                                          navigator.product === 'NativeScript' ||
                                          navigator.product === 'NS') {
    return false;
  }
  return (
    typeof window !== 'undefined' &&
    typeof document !== 'undefined'
  );
}

/**
 * Iterate over an Array or an Object invoking a function for each item.
 *
 * If `obj` is an Array callback will be called passing
 * the value, index, and complete array for each item.
 *
 * If 'obj' is an Object callback will be called passing
 * the value, key, and complete object for each property.
 *
 * @param {Object|Array} obj The object to iterate
 * @param {Function} fn The callback to invoke for each item
 */
function forEach(obj, fn) {
  // Don't bother if no value provided
  if (obj === null || typeof obj === 'undefined') {
    return;
  }

  // Force an array if not already something iterable
  if (typeof obj !== 'object') {
    /*eslint no-param-reassign:0*/
    obj = [obj];
  }

  if (isArray(obj)) {
    // Iterate over array values
    for (var i = 0, l = obj.length; i < l; i++) {
      fn.call(null, obj[i], i, obj);
    }
  } else {
    // Iterate over object keys
    for (var key in obj) {
      if (Object.prototype.hasOwnProperty.call(obj, key)) {
        fn.call(null, obj[key], key, obj);
      }
    }
  }
}

/**
 * Accepts varargs expecting each argument to be an object, then
 * immutably merges the properties of each object and returns result.
 *
 * When multiple objects contain the same key the later object in
 * the arguments list will take precedence.
 *
 * Example:
 *
 * ```js
 * var result = merge({foo: 123}, {foo: 456});
 * console.log(result.foo); // outputs 456
 * ```
 *
 * @param {Object} obj1 Object to merge
 * @returns {Object} Result of all merge properties
 */
function merge(/* obj1, obj2, obj3, ... */) {
  var result = {};
  function assignValue(val, key) {
    if (typeof result[key] === 'object' && typeof val === 'object') {
      result[key] = merge(result[key], val);
    } else {
      result[key] = val;
    }
  }

  for (var i = 0, l = arguments.length; i < l; i++) {
    forEach(arguments[i], assignValue);
  }
  return result;
}

/**
 * Function equal to merge with the difference being that no reference
 * to original objects is kept.
 *
 * @see merge
 * @param {Object} obj1 Object to merge
 * @returns {Object} Result of all merge properties
 */
function deepMerge(/* obj1, obj2, obj3, ... */) {
  var result = {};
  function assignValue(val, key) {
    if (typeof result[key] === 'object' && typeof val === 'object') {
      result[key] = deepMerge(result[key], val);
    } else if (typeof val === 'object') {
      result[key] = deepMerge({}, val);
    } else {
      result[key] = val;
    }
  }

  for (var i = 0, l = arguments.length; i < l; i++) {
    forEach(arguments[i], assignValue);
  }
  return result;
}

/**
 * Extends object a by mutably adding to it the properties of object b.
 *
 * @param {Object} a The object to be extended
 * @param {Object} b The object to copy properties from
 * @param {Object} thisArg The object to bind function to
 * @return {Object} The resulting value of object a
 */
function extend(a, b, thisArg) {
  forEach(b, function assignValue(val, key) {
    if (thisArg && typeof val === 'function') {
      a[key] = bind(val, thisArg);
    } else {
      a[key] = val;
    }
  });
  return a;
}

module.exports = {
  isArray: isArray,
  isArrayBuffer: isArrayBuffer,
  isBuffer: isBuffer,
  isFormData: isFormData,
  isArrayBufferView: isArrayBufferView,
  isString: isString,
  isNumber: isNumber,
  isObject: isObject,
  isUndefined: isUndefined,
  isDate: isDate,
  isFile: isFile,
  isBlob: isBlob,
  isFunction: isFunction,
  isStream: isStream,
  isURLSearchParams: isURLSearchParams,
  isStandardBrowserEnv: isStandardBrowserEnv,
  forEach: forEach,
  merge: merge,
  deepMerge: deepMerge,
  extend: extend,
  trim: trim
};
<|endoftext|>


<commit_before>const _ = require('lodash');

/**
 * Uses lodash isEqual to perform non-strict object comparison.
 *
 * @see https://stackoverflow.com/a/4587130/167987
 * @param {object} obj - The object to search for.
 * @param {Array} list - The array of objects to search.
 */
const containsObject = (obj, list) => {
	for (const element of list) {
		if (_.isEqual(element, obj)) {
			return true;
		}
	}

	return false;
};

/**
 * @param {string} line - The file line to check for an XML file prolog.
 */
const checkIsXMLFile = (line) => {
	const XMLSearch = line.match(/(<\?xml|type="text\/xml)/);
	let isXMLFile = false;
	if (XMLSearch !== null) {
		isXMLFile = true;
	}

	return isXMLFile;
};

/**
 * @param {string} str - The string to match.
 * @param {RegExp} regex - The RegExp to use.
 */
const matchAll = (str, regex) => {
	const res = [];
	let m;
	if (regex.global) {
		while ((m = regex.exec(str))) {
			res.push(m);
		}
	} else if ((m = regex.exec(str))) {
		res.push(m);
	}

	return res;
};

module.exports = {
	checkIsXMLFile,
	containsObject,
	matchAll,
};
<commit_msg>Refactor checkIsXMLFile()<commit_after>const _ = require('lodash');

/**
 * Uses lodash isEqual to perform non-strict object comparison.
 *
 * @see https://stackoverflow.com/a/4587130/167987
 * @param {object} obj - The object to search for.
 * @param {Array} list - The array of objects to search.
 */
const containsObject = (obj, list) => {
	for (const element of list) {
		if (_.isEqual(element, obj)) {
			return true;
		}
	}

	return false;
};

/**
 * @param {string} line - The file line to check for an XML file prolog.
 */
const checkIsXMLFile = (line) => {
	const regexp = /<\?xml|type="text\/xml/;
	const xmlSearch = line.match(regexp);

	if (xmlSearch === null) {
		return false;
	}

	return true;
};

/**
 * @param {string} str - The string to match.
 * @param {RegExp} regex - The RegExp to use.
 */
const matchAll = (str, regex) => {
	const res = [];
	let m;
	if (regex.global) {
		while ((m = regex.exec(str))) {
			res.push(m);
		}
	} else if ((m = regex.exec(str))) {
		res.push(m);
	}

	return res;
};

module.exports = {
	checkIsXMLFile,
	containsObject,
	matchAll,
};
<|endoftext|>


<commit_before>var controllerDir;
var appName;

function getAppName() {
    var parts = __dirname.replace(/\\/g, '/').split('/');
    return parts[parts.length - 2].split('.')[0];
}

// Get js-controller directory to load libs
function getControllerDir(isInstall) {
    var fs = require('fs');
    // Find the js-controller location
    var controllerDir = __dirname.replace(/\\/g, '/');
    controllerDir = controllerDir.split('/');
    if (controllerDir[controllerDir.length - 3] === 'adapter') {
        controllerDir.splice(controllerDir.length - 3, 3);
        controllerDir = controllerDir.join('/');
    } else if (controllerDir[controllerDir.length - 3] === 'node_modules') {
        controllerDir.splice(controllerDir.length - 3, 3);
        controllerDir = controllerDir.join('/');
        if (fs.existsSync(controllerDir + '/node_modules/' + appName + '.js-controller')) {
            controllerDir += '/node_modules/' + appName + '.js-controller';
        } else if (fs.existsSync(controllerDir + '/node_modules/' + appName.toLowerCase() + '.js-controller')) {
            controllerDir += '/node_modules/' + appName.toLowerCase() + '.js-controller';
        } else if (!fs.existsSync(controllerDir + '/controller.js')) {
            if (!isInstall) {
                console.log('Cannot find js-controller');
                process.exit(10);
            } else {
                process.exit();
            }
        }
    } else if (fs.existsSync(__dirname + '/../../node_modules/' + appName.toLowerCase() + '.js-controller')) {
        controllerDir.splice(controllerDir.length - 2, 2);
        return controllerDir.join('/') + '/node_modules/' + appName.toLowerCase() + '.js-controller';
    } else {
        if (!isInstall) {
            console.log('Cannot find js-controller');
            process.exit(10);
        } else {
            process.exit();
        }
    }
    return controllerDir;
}

// Read controller configuration file
function getConfig() {
    var fs = require('fs');
    if (fs.existsSync(controllerDir + '/conf/' + appName + '.json')) {
        return JSON.parse(fs.readFileSync(controllerDir + '/conf/' + appName + '.json'));
    } else if (fs.existsSync(controllerDir + '/conf/' + appName.toLowerCase() + '.json')) {
        return JSON.parse(fs.readFileSync(controllerDir + '/conf/' + appName.toLowerCase() + '.json'));
    } else {
        throw new Error('Cannot find ' + controllerDir + '/conf/' + appName + '.json');
    }
}
appName       = getAppName();
controllerDir = getControllerDir(typeof process !== 'undefined' && process.argv && process.argv.indexOf('--install') !== -1);

exports.controllerDir = controllerDir;
exports.getConfig =     getConfig;
exports.Adapter =       require(controllerDir + '/lib/adapter.js');
exports.appName =       appName;
<commit_msg>update utils.js<commit_after>'use strict';

const fs = require('fs');
const path = require('path');

let controllerDir;
let appName;

/**
 * returns application name
 *
 * The name of the application can be different and this function finds it out.
 *
 * @returns {string}
 */
 function getAppName() {
    const parts = __dirname.replace(/\\/g, '/').split('/');
    return parts[parts.length - 2].split('.')[0];
}

/**
 * looks for js-controller home folder
 *
 * @param {boolean} isInstall
 * @returns {string}
 */
function getControllerDir(isInstall) {
    // Find the js-controller location
    const possibilities = [
        'iobroker.js-controller',
        'ioBroker.js-controller',
    ];
    /** @type {string} */
    let controllerPath;
    for (const pkg of possibilities) {
        try {
            const possiblePath = require.resolve(pkg);
            if (fs.existsSync(possiblePath)) {
                controllerPath = possiblePath;
                break;
            }
        } catch (e) { /* not found */ }
    }
    if (controllerPath == null) {
        if (!isInstall) {
            console.log('Cannot find js-controller');
            process.exit(10);
        } else {
            process.exit();
        }
    }
    // we found the controller
    return path.dirname(controllerPath);
}

/**
 * reads controller base settings
 *
 * @alias getConfig
 * @returns {object}
 */
 function getConfig() {
    let configPath;
    if (fs.existsSync(
        configPath = path.join(controllerDir, 'conf', appName + '.json')
    )) {
        return JSON.parse(fs.readFileSync(configPath, 'utf8'));
    } else if (fs.existsSync(
        configPath = path.join(controllerDir, 'conf', + appName.toLowerCase() + '.json')
    )) {
        return JSON.parse(fs.readFileSync(configPath, 'utf8'));
    } else {
        throw new Error('Cannot find ' + controllerDir + '/conf/' + appName + '.json');
    }
}
appName       = getAppName();
controllerDir = getControllerDir(typeof process !== 'undefined' && process.argv && process.argv.indexOf('--install') !== -1);
const adapter = require(path.join(controllerDir, 'lib/adapter.js'));

exports.controllerDir = controllerDir;
exports.getConfig =     getConfig;
exports.Adapter =       adapter;
exports.appName =       appName;
<|endoftext|>


<commit_before>
/*!
 * Connect - utils
 * Copyright(c) 2010 Sencha Inc.
 * Copyright(c) 2011 TJ Holowaychuk
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var crypto = require('crypto')
  , Path = require('path')
  , fs = require('fs');

/**
 * Flatten the given `arr`.
 *
 * @param {Array} arr
 * @return {Array}
 * @api private
 */

exports.flatten = function(arr, ret){
  var ret = ret || []
    , len = arr.length;
  for (var i = 0; i < len; ++i) {
    if (Array.isArray(arr[i])) {
      exports.flatten(arr[i], ret);
    } else {
      ret.push(arr[i]);
    }
  }
  return ret;
};

/**
 * Return md5 hash of the given string and optional encoding,
 * defaulting to hex.
 *
 *     utils.md5('wahoo');
 *     // => "e493298061761236c96b02ea6aa8a2ad"
 *
 * @param {String} str
 * @param {String} encoding
 * @return {String}
 * @api public
 */

exports.md5 = function(str, encoding){
  return crypto
    .createHash('md5')
    .update(str)
    .digest(encoding || 'hex');
};

/**
 * Merge object b with object a.
 *
 *     var a = { foo: 'bar' }
 *       , b = { bar: 'baz' };
 *
 *     utils.merge(a, b);
 *     // => { foo: 'bar', bar: 'baz' }
 *
 * @param {Object} a
 * @param {Object} b
 * @return {Object}
 * @api public
 */

exports.merge = function(a, b){
  if (a && b) {
    for (var key in b) {
      a[key] = b[key];
    }
  }
  return a;
};

/**
 * Escape the given string of `html`.
 *
 * @param {String} html
 * @return {String}
 * @api public
 */

exports.escape = function(html){
  return String(html)
    .replace(/&(?!\w+;)/g, '&')
    .replace(/</g, '<')
    .replace(/>/g, '>')
    .replace(/"/g, '"');
};

/**
 * Return a unique identifier with the given `len`.
 *
 *     utils.uid(10);
 *     // => "FDaS435D2z"
 *
 * @param {Number} len
 * @return {String}
 * @api public
 */

exports.uid = function(len) {
  var buf = []
    , chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
    , charlen = chars.length;

  for (var i = 0; i < len; ++i) {
    buf.push(chars[Math.random() * charlen | 0]);
  }

  return buf.join('');
};

/**
 * Sign and base64-encode the given `val` with `secret`.
 *
 * @param {String} val
 * @param {String} secret
 * @return {String}
 * @api public
 */

exports.sign = function(val, secret){
  val = new Buffer(val).toString('base64').replace(/=+$/, '');
  return val + '.' + crypto
    .createHmac('sha1', secret)
    .update(val)
    .digest('base64')
    .replace(/=+$/, '');
};

/**
 * Unsign and decode the given `val` with `secret`,
 * returning `false` if the signature is invalid.
 *
 * @param {String} val
 * @param {String} secret
 * @return {String|Boolean}
 * @api public
 */

exports.unsign = function(val, secret){
  var parts = val.split('.')
    , str = new Buffer(parts[0], 'base64').toString();
  return exports.sign(str, secret) == val
    ? str
    : false;
};

/**
 * Parse signed cookies, returning an object
 * containing the decoded key/value pairs,
 * while removing the signed key from `obj`.
 *
 * @param {Object} obj
 * @return {Object}
 * @api public
 */

exports.parseSignedCookies = function(obj, secret){
  var ret = {};
  Object.keys(obj).forEach(function(key){
    var val = obj[key]
      , signed = exports.unsign(val, secret);

    if (signed) {
      ret[key] = signed;
      delete obj[key];
    }
  });
  return ret;
};

/**
 * Parse JSON cookies.
 *
 * @param {Object} obj
 * @return {Object}
 * @api public
 */

exports.parseJSONCookies = function(obj){
  Object.keys(obj).forEach(function(key){
    var val = obj[key];
    if (0 == val.indexOf('j:')) {
      try {
        obj[key] = JSON.parse(val.slice(2));
      } catch (err) {
        // nothing
      }
    }
  });
  return obj;
};

/**
 * Parse the given cookie string into an object.
 *
 * @param {String} str
 * @return {Object}
 * @api public
 */

exports.parseCookie = function(str){
  var obj = {}
    , pairs = str.split(/[;,] */);
  for (var i = 0, len = pairs.length; i < len; ++i) {
    var pair = pairs[i]
      , eqlIndex = pair.indexOf('=')
      , key = pair.substr(0, eqlIndex).trim().toLowerCase()
      , val = pair.substr(++eqlIndex, pair.length).trim();

    // quoted values
    if ('"' == val[0]) val = val.slice(1, -1);

    // only assign once
    if (undefined == obj[key]) {
      val = val.replace(/\+/g, ' ');
      try {
        obj[key] = decodeURIComponent(val);
      } catch (err) {
        if (err instanceof URIError) {
          obj[key] = val;
        } else {
          throw err;
        }
      }
    }
  }
  return obj;
};

/**
 * Serialize the given object into a cookie string.
 *
 *      utils.serializeCookie('name', 'tj', { httpOnly: true })
 *      // => "name=tj; httpOnly"
 *
 * @param {String} name
 * @param {String} val
 * @param {Object} obj
 * @return {String}
 * @api public
 */

exports.serializeCookie = function(name, val, obj){
  var pairs = [name + '=' + encodeURIComponent(val)]
    , obj = obj || {};

  if (obj.domain) pairs.push('domain=' + obj.domain);
  if (obj.path) pairs.push('path=' + obj.path);
  if (obj.expires) pairs.push('expires=' + obj.expires.toUTCString());
  if (obj.httpOnly) pairs.push('httpOnly');
  if (obj.secure) pairs.push('secure');

  return pairs.join('; ');
};

/**
 * Pause `data` and `end` events on the given `obj`.
 * Middleware performing async tasks _should_ utilize
 * this utility (or similar), to re-emit data once
 * the async operation has completed, otherwise these
 * events may be lost.
 *
 *      var pause = utils.pause(req);
 *      fs.readFile(path, function(){
 *         next();
 *         pause.resume();
 *      });
 *
 * @param {Object} obj
 * @return {Object}
 * @api public
 */

exports.pause = function(obj){
  var onData
    , onEnd
    , events = [];

  // buffer data
  obj.on('data', onData = function(data, encoding){
    events.push(['data', data, encoding]);
  });

  // buffer end
  obj.on('end', onEnd = function(data, encoding){
    events.push(['end', data, encoding]);
  });

  return {
    end: function(){
      obj.removeListener('data', onData);
      obj.removeListener('end', onEnd);
    },
    resume: function(){
      this.end();
      for (var i = 0, len = events.length; i < len; ++i) {
        obj.emit.apply(obj, events[i]);
      }
    }
  };
};

/**
 * Check `req` and `res` to see if it has been modified.
 *
 * @param {IncomingMessage} req
 * @param {ServerResponse} res
 * @return {Boolean}
 * @api public
 */

exports.modified = function(req, res, headers) {
  var headers = headers || res._headers || {}
    , modifiedSince = req.headers['if-modified-since']
    , lastModified = headers['last-modified']
    , noneMatch = req.headers['if-none-match']
    , etag = headers['etag'];

  if (noneMatch) noneMatch = noneMatch.split(/ *, */);

  // check If-None-Match
  if (noneMatch && etag && ~noneMatch.indexOf(etag)) {
    return false;
  }

  // check If-Modified-Since
  if (modifiedSince && lastModified) {
    modifiedSince = new Date(modifiedSince);
    lastModified = new Date(lastModified);
    // Ignore invalid dates
    if (!isNaN(modifiedSince.getTime())) {
      if (lastModified <= modifiedSince) return false;
    }
  }

  return true;
};

/**
 * Strip `Content-*` headers from `res`.
 *
 * @param {ServerResponse} res
 * @api public
 */

exports.removeContentHeaders = function(res){
  Object.keys(res._headers).forEach(function(field){
    if (0 == field.indexOf('content')) {
      res.removeHeader(field);
    }
  });
};

/**
 * Check if `req` is a conditional GET request.
 *
 * @param {IncomingMessage} req
 * @return {Boolean}
 * @api public
 */

exports.conditionalGET = function(req) {
  return req.headers['if-modified-since']
    || req.headers['if-none-match'];
};

/**
 * Respond with 403 "Forbidden".
 *
 * @param {ServerResponse} res
 * @api public
 */

exports.forbidden = function(res) {
  var body = 'Forbidden';
  res.setHeader('Content-Type', 'text/plain');
  res.setHeader('Content-Length', body.length);
  res.statusCode = 403;
  res.end(body);
};

/**
 * Respond with 401 "Unauthorized".
 *
 * @param {ServerResponse} res
 * @param {String} realm
 * @api public
 */

exports.unauthorized = function(res, realm) {
  res.statusCode = 401;
  res.setHeader('WWW-Authenticate', 'Basic realm="' + realm + '"');
  res.end('Unauthorized');
};

/**
 * Respond with 400 "Bad Request".
 *
 * @param {ServerResponse} res
 * @api public
 */

exports.badRequest = function(res) {
  res.statusCode = 400;
  res.end('Bad Request');
};

/**
 * Respond with 304 "Not Modified".
 *
 * @param {ServerResponse} res
 * @param {Object} headers
 * @api public
 */

exports.notModified = function(res) {
  exports.removeContentHeaders(res);
  res.statusCode = 304;
  res.end();
};

/**
 * Return an ETag in the form of `"<size>-<mtime>"`
 * from the given `stat`.
 *
 * @param {Object} stat
 * @return {String}
 * @api public
 */

exports.etag = function(stat) {
  return '"' + stat.size + '-' + Number(stat.mtime) + '"';
};

/**
 * Parse "Range" header `str` relative to the given file `size`.
 *
 * @param {Number} size
 * @param {String} str
 * @return {Array}
 * @api public
 */

exports.parseRange = function(size, str){
  var valid = true;
  var arr = str.substr(6).split(',').map(function(range){
    var range = range.split('-')
      , start = parseInt(range[0], 10)
      , end = parseInt(range[1], 10);

    // -500
    if (isNaN(start)) {
      start = size - end;
      end = size - 1;
    // 500-
    } else if (isNaN(end)) {
      end = size - 1;
    }

    // Invalid
    if (isNaN(start) || isNaN(end) || start > end) valid = false;

    return { start: start, end: end };
  });
  return valid ? arr : undefined;
};

/**
 * Parse the given Cache-Control `str`.
 *
 * @param {String} str
 * @return {Object}
 * @api public
 */

exports.parseCacheControl = function(str){
  var directives = str.split(',')
    , obj = {};

  for(var i = 0, len = directives.length; i < len; i++) {
    var parts = directives[i].split('=')
      , key = parts.shift().trim()
      , val = parseInt(parts.shift(), 10);

    obj[key] = isNaN(val) ? true : val;
  }

  return obj;
};

/**
 * Convert array-like object to an `Array`.
 *
 * node-bench measured "16.5 times faster than Array.prototype.slice.call()"
 *
 * @param {Object} obj
 * @return {Array}
 * @api public
 */

var toArray = exports.toArray = function(obj){
  var len = obj.length
    , arr = new Array(len);
  for (var i = 0; i < len; ++i) {
    arr[i] = obj[i];
  }
  return arr;
};
<commit_msg>prevent unsign() from breaking on json cookie<commit_after>
/*!
 * Connect - utils
 * Copyright(c) 2010 Sencha Inc.
 * Copyright(c) 2011 TJ Holowaychuk
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var crypto = require('crypto')
  , Path = require('path')
  , fs = require('fs');

/**
 * Flatten the given `arr`.
 *
 * @param {Array} arr
 * @return {Array}
 * @api private
 */

exports.flatten = function(arr, ret){
  var ret = ret || []
    , len = arr.length;
  for (var i = 0; i < len; ++i) {
    if (Array.isArray(arr[i])) {
      exports.flatten(arr[i], ret);
    } else {
      ret.push(arr[i]);
    }
  }
  return ret;
};

/**
 * Return md5 hash of the given string and optional encoding,
 * defaulting to hex.
 *
 *     utils.md5('wahoo');
 *     // => "e493298061761236c96b02ea6aa8a2ad"
 *
 * @param {String} str
 * @param {String} encoding
 * @return {String}
 * @api public
 */

exports.md5 = function(str, encoding){
  return crypto
    .createHash('md5')
    .update(str)
    .digest(encoding || 'hex');
};

/**
 * Merge object b with object a.
 *
 *     var a = { foo: 'bar' }
 *       , b = { bar: 'baz' };
 *
 *     utils.merge(a, b);
 *     // => { foo: 'bar', bar: 'baz' }
 *
 * @param {Object} a
 * @param {Object} b
 * @return {Object}
 * @api public
 */

exports.merge = function(a, b){
  if (a && b) {
    for (var key in b) {
      a[key] = b[key];
    }
  }
  return a;
};

/**
 * Escape the given string of `html`.
 *
 * @param {String} html
 * @return {String}
 * @api public
 */

exports.escape = function(html){
  return String(html)
    .replace(/&(?!\w+;)/g, '&')
    .replace(/</g, '<')
    .replace(/>/g, '>')
    .replace(/"/g, '"');
};

/**
 * Return a unique identifier with the given `len`.
 *
 *     utils.uid(10);
 *     // => "FDaS435D2z"
 *
 * @param {Number} len
 * @return {String}
 * @api public
 */

exports.uid = function(len) {
  var buf = []
    , chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
    , charlen = chars.length;

  for (var i = 0; i < len; ++i) {
    buf.push(chars[Math.random() * charlen | 0]);
  }

  return buf.join('');
};

/**
 * Sign and base64-encode the given `val` with `secret`.
 *
 * @param {String} val
 * @param {String} secret
 * @return {String}
 * @api public
 */

exports.sign = function(val, secret){
  val = new Buffer(val).toString('base64').replace(/=+$/, '');
  return val + '.' + crypto
    .createHmac('sha1', secret)
    .update(val)
    .digest('base64')
    .replace(/=+$/, '');
};

/**
 * Unsign and decode the given `val` with `secret`,
 * returning `false` if the signature is invalid.
 *
 * @param {String} val
 * @param {String} secret
 * @return {String|Boolean}
 * @api public
 */

exports.unsign = function(val, secret){
  if ('string' != typeof val) return false;
  var parts = val.split('.')
    , str = new Buffer(parts[0], 'base64').toString();
  return exports.sign(str, secret) == val
    ? str
    : false;
};

/**
 * Parse signed cookies, returning an object
 * containing the decoded key/value pairs,
 * while removing the signed key from `obj`.
 *
 * @param {Object} obj
 * @return {Object}
 * @api public
 */

exports.parseSignedCookies = function(obj, secret){
  var ret = {};
  Object.keys(obj).forEach(function(key){
    var val = obj[key]
      , signed = exports.unsign(val, secret);

    if (signed) {
      ret[key] = signed;
      delete obj[key];
    }
  });
  return ret;
};

/**
 * Parse JSON cookies.
 *
 * @param {Object} obj
 * @return {Object}
 * @api public
 */

exports.parseJSONCookies = function(obj){
  Object.keys(obj).forEach(function(key){
    var val = obj[key];
    if (0 == val.indexOf('j:')) {
      try {
        obj[key] = JSON.parse(val.slice(2));
      } catch (err) {
        // nothing
      }
    }
  });
  return obj;
};

/**
 * Parse the given cookie string into an object.
 *
 * @param {String} str
 * @return {Object}
 * @api public
 */

exports.parseCookie = function(str){
  var obj = {}
    , pairs = str.split(/[;,] */);
  for (var i = 0, len = pairs.length; i < len; ++i) {
    var pair = pairs[i]
      , eqlIndex = pair.indexOf('=')
      , key = pair.substr(0, eqlIndex).trim().toLowerCase()
      , val = pair.substr(++eqlIndex, pair.length).trim();

    // quoted values
    if ('"' == val[0]) val = val.slice(1, -1);

    // only assign once
    if (undefined == obj[key]) {
      val = val.replace(/\+/g, ' ');
      try {
        obj[key] = decodeURIComponent(val);
      } catch (err) {
        if (err instanceof URIError) {
          obj[key] = val;
        } else {
          throw err;
        }
      }
    }
  }
  return obj;
};

/**
 * Serialize the given object into a cookie string.
 *
 *      utils.serializeCookie('name', 'tj', { httpOnly: true })
 *      // => "name=tj; httpOnly"
 *
 * @param {String} name
 * @param {String} val
 * @param {Object} obj
 * @return {String}
 * @api public
 */

exports.serializeCookie = function(name, val, obj){
  var pairs = [name + '=' + encodeURIComponent(val)]
    , obj = obj || {};

  if (obj.domain) pairs.push('domain=' + obj.domain);
  if (obj.path) pairs.push('path=' + obj.path);
  if (obj.expires) pairs.push('expires=' + obj.expires.toUTCString());
  if (obj.httpOnly) pairs.push('httpOnly');
  if (obj.secure) pairs.push('secure');

  return pairs.join('; ');
};

/**
 * Pause `data` and `end` events on the given `obj`.
 * Middleware performing async tasks _should_ utilize
 * this utility (or similar), to re-emit data once
 * the async operation has completed, otherwise these
 * events may be lost.
 *
 *      var pause = utils.pause(req);
 *      fs.readFile(path, function(){
 *         next();
 *         pause.resume();
 *      });
 *
 * @param {Object} obj
 * @return {Object}
 * @api public
 */

exports.pause = function(obj){
  var onData
    , onEnd
    , events = [];

  // buffer data
  obj.on('data', onData = function(data, encoding){
    events.push(['data', data, encoding]);
  });

  // buffer end
  obj.on('end', onEnd = function(data, encoding){
    events.push(['end', data, encoding]);
  });

  return {
    end: function(){
      obj.removeListener('data', onData);
      obj.removeListener('end', onEnd);
    },
    resume: function(){
      this.end();
      for (var i = 0, len = events.length; i < len; ++i) {
        obj.emit.apply(obj, events[i]);
      }
    }
  };
};

/**
 * Check `req` and `res` to see if it has been modified.
 *
 * @param {IncomingMessage} req
 * @param {ServerResponse} res
 * @return {Boolean}
 * @api public
 */

exports.modified = function(req, res, headers) {
  var headers = headers || res._headers || {}
    , modifiedSince = req.headers['if-modified-since']
    , lastModified = headers['last-modified']
    , noneMatch = req.headers['if-none-match']
    , etag = headers['etag'];

  if (noneMatch) noneMatch = noneMatch.split(/ *, */);

  // check If-None-Match
  if (noneMatch && etag && ~noneMatch.indexOf(etag)) {
    return false;
  }

  // check If-Modified-Since
  if (modifiedSince && lastModified) {
    modifiedSince = new Date(modifiedSince);
    lastModified = new Date(lastModified);
    // Ignore invalid dates
    if (!isNaN(modifiedSince.getTime())) {
      if (lastModified <= modifiedSince) return false;
    }
  }

  return true;
};

/**
 * Strip `Content-*` headers from `res`.
 *
 * @param {ServerResponse} res
 * @api public
 */

exports.removeContentHeaders = function(res){
  Object.keys(res._headers).forEach(function(field){
    if (0 == field.indexOf('content')) {
      res.removeHeader(field);
    }
  });
};

/**
 * Check if `req` is a conditional GET request.
 *
 * @param {IncomingMessage} req
 * @return {Boolean}
 * @api public
 */

exports.conditionalGET = function(req) {
  return req.headers['if-modified-since']
    || req.headers['if-none-match'];
};

/**
 * Respond with 403 "Forbidden".
 *
 * @param {ServerResponse} res
 * @api public
 */

exports.forbidden = function(res) {
  var body = 'Forbidden';
  res.setHeader('Content-Type', 'text/plain');
  res.setHeader('Content-Length', body.length);
  res.statusCode = 403;
  res.end(body);
};

/**
 * Respond with 401 "Unauthorized".
 *
 * @param {ServerResponse} res
 * @param {String} realm
 * @api public
 */

exports.unauthorized = function(res, realm) {
  res.statusCode = 401;
  res.setHeader('WWW-Authenticate', 'Basic realm="' + realm + '"');
  res.end('Unauthorized');
};

/**
 * Respond with 400 "Bad Request".
 *
 * @param {ServerResponse} res
 * @api public
 */

exports.badRequest = function(res) {
  res.statusCode = 400;
  res.end('Bad Request');
};

/**
 * Respond with 304 "Not Modified".
 *
 * @param {ServerResponse} res
 * @param {Object} headers
 * @api public
 */

exports.notModified = function(res) {
  exports.removeContentHeaders(res);
  res.statusCode = 304;
  res.end();
};

/**
 * Return an ETag in the form of `"<size>-<mtime>"`
 * from the given `stat`.
 *
 * @param {Object} stat
 * @return {String}
 * @api public
 */

exports.etag = function(stat) {
  return '"' + stat.size + '-' + Number(stat.mtime) + '"';
};

/**
 * Parse "Range" header `str` relative to the given file `size`.
 *
 * @param {Number} size
 * @param {String} str
 * @return {Array}
 * @api public
 */

exports.parseRange = function(size, str){
  var valid = true;
  var arr = str.substr(6).split(',').map(function(range){
    var range = range.split('-')
      , start = parseInt(range[0], 10)
      , end = parseInt(range[1], 10);

    // -500
    if (isNaN(start)) {
      start = size - end;
      end = size - 1;
    // 500-
    } else if (isNaN(end)) {
      end = size - 1;
    }

    // Invalid
    if (isNaN(start) || isNaN(end) || start > end) valid = false;

    return { start: start, end: end };
  });
  return valid ? arr : undefined;
};

/**
 * Parse the given Cache-Control `str`.
 *
 * @param {String} str
 * @return {Object}
 * @api public
 */

exports.parseCacheControl = function(str){
  var directives = str.split(',')
    , obj = {};

  for(var i = 0, len = directives.length; i < len; i++) {
    var parts = directives[i].split('=')
      , key = parts.shift().trim()
      , val = parseInt(parts.shift(), 10);

    obj[key] = isNaN(val) ? true : val;
  }

  return obj;
};

/**
 * Convert array-like object to an `Array`.
 *
 * node-bench measured "16.5 times faster than Array.prototype.slice.call()"
 *
 * @param {Object} obj
 * @return {Array}
 * @api public
 */

var toArray = exports.toArray = function(obj){
  var len = obj.length
    , arr = new Array(len);
  for (var i = 0; i < len; ++i) {
    arr[i] = obj[i];
  }
  return arr;
};
<|endoftext|>


<commit_before>'use strict';

/**
 * Module dependencies
 */

var diacritics = require('diacritics-map');
var utils = require('lazy-cache')(require);
var fn = require;
const os = require('os');
require = utils;

/**
 * Lazily required module dependencies
 */

require('concat-stream', 'concat');
require('gray-matter', 'matter');
require('list-item', 'li');
require('markdown-link', 'mdlink');
require('minimist');
require('mixin-deep', 'merge');
require('object.pick', 'pick');
require('remarkable', 'Remarkable');
require('repeat-string', 'repeat');
require('strip-color');
require = fn;

/**
 * Get the "title" from a markdown link
 */

utils.getTitle = function(str) {
  if (/^\[[^\]]+\]\(/.test(str)) {
    var m = /^\[([^\]]+)\]/.exec(str);
    if (m) return m[1];
  }
  return str;
};

/**
 * Slugify the url part of a markdown link.
 *
 * @name  options.slugify
 * @param  {String} `str` The string to slugify
 * @param  {Object} `options` Pass a custom slugify function on `options.slugify`
 * @return {String}
 * @api public
 */

utils.slugify = function(str, options) {
  options = options || {};
  if (options.slugify === false) return str;
  if (typeof options.slugify === 'function') {
    return options.slugify(str, options);
  }

  str = utils.getTitle(str);
  str = utils.stripColor(str);
  str = str.toLowerCase();

  // `.split()` is often (but not always) faster than `.replace()`
  // str = str.slice(0, -2);
  str = str.split(' ').join('-');
  str = str.split(/\t/).join('--');
  if (options.stripHeadingTags !== false) {
    str = str.split(/<\/?[^>]+>/).join('');
  }
  // str = str.split(/[|$&`~=\\\/@+*!?({[\]})<>=.,;:'"^]/).join('');
  // quick fix: delete . from regex to get file ending in resulting link
  str = str.split(/[|$&`~=\\\/@+*!?({[\]})<>=,;:'"^]/).join('');
  str = str.split(/[。？！，、；：“”【】（）〔〕［］﹃﹄“ ”‘’﹁﹂—…－～《》〈〉「」]/).join('');
  str = replaceDiacritics(str);
  if (options.num) {
    str += '-' + options.num;
  }
  return str;
};

/**
 * Convert a non-heading string to a h1 heading
 * @param {String} `str` The string to headify
 * @returns {string}
 */
utils.headify = function h(str) {
  // line ending doesn't really matter because the headings are tokenized later on.
  return `# ${str.trim() + os.EOL}`;
};

function replaceDiacritics(str) {
  return str.replace(/[À-ž]/g, function(ch) {
    return diacritics[ch] || ch;
  });
}

utils.determineNewline = function (file) {
  let newline;
  if (file.indexOf('\n\r') > -1) {
    newline = '\n\r';
  } else if (file.indexOf('\r\n') > -1) {
    newline = '\r\n';
  } else if (file.indexOf('\r') > -1) {
    newline = '\r';
  } else {
    newline = '\n';
  }
  return newline;
};

/**
 * Expose `utils` modules
 */

module.exports = utils;
<commit_msg>Fix variable name<commit_after>'use strict';

/**
 * Module dependencies
 */

var diacritics = require('diacritics-map');
var utils = require('lazy-cache')(require);
var fn = require;
const os = require('os');
require = utils;

/**
 * Lazily required module dependencies
 */

require('concat-stream', 'concat');
require('gray-matter', 'matter');
require('list-item', 'li');
require('markdown-link', 'mdlink');
require('minimist');
require('mixin-deep', 'merge');
require('object.pick', 'pick');
require('remarkable', 'Remarkable');
require('repeat-string', 'repeat');
require('strip-color');
require = fn;

/**
 * Get the "title" from a markdown link
 */

utils.getTitle = function(str) {
  if (/^\[[^\]]+\]\(/.test(str)) {
    var m = /^\[([^\]]+)\]/.exec(str);
    if (m) return m[1];
  }
  return str;
};

/**
 * Slugify the url part of a markdown link.
 *
 * @name  options.slugify
 * @param  {String} `str` The string to slugify
 * @param  {Object} `options` Pass a custom slugify function on `options.slugify`
 * @return {String}
 * @api public
 */

utils.slugify = function(str, options) {
  options = options || {};
  if (options.slugify === false) return str;
  if (typeof options.slugify === 'function') {
    return options.slugify(str, options);
  }

  str = utils.getTitle(str);
  str = utils.stripColor(str);
  str = str.toLowerCase();

  // `.split()` is often (but not always) faster than `.replace()`
  // str = str.slice(0, -2);
  str = str.split(' ').join('-');
  str = str.split(/\t/).join('--');
  if (options.stripHeadingTags !== false) {
    str = str.split(/<\/?[^>]+>/).join('');
  }
  // str = str.split(/[|$&`~=\\\/@+*!?({[\]})<>=.,;:'"^]/).join('');
  // quick fix: delete . from regex to get file ending in resulting link
  str = str.split(/[|$&`~=\\\/@+*!?({[\]})<>=,;:'"^]/).join('');
  str = str.split(/[。？！，、；：“”【】（）〔〕［］﹃﹄“ ”‘’﹁﹂—…－～《》〈〉「」]/).join('');
  str = replaceDiacritics(str);
  if (options.num) {
    str += '-' + options.num;
  }
  return str;
};

/**
 * Convert a non-heading string to a h1 heading
 * @param {String} `str` The string to headify
 * @returns {string}
 */
utils.headify = function h(str) {
  // line ending doesn't really matter because the headings are tokenized later on.
  return `# ${str.trim() + os.EOL}`;
};

function replaceDiacritics(str) {
  return str.replace(/[À-ž]/g, function(ch) {
    return diacritics[ch] || ch;
  });
}

utils.determineNewline = function (content) {
  let newline;
  if (content.indexOf('\n\r') > -1) {
    newline = '\n\r';
  } else if (content.indexOf('\r\n') > -1) {
    newline = '\r\n';
  } else if (content.indexOf('\r') > -1) {
    newline = '\r';
  } else {
    newline = '\n';
  }
  return newline;
};

/**
 * Expose `utils` modules
 */

module.exports = utils;
<|endoftext|>


<commit_before>/**
 * Created by mwmaleks on 22.12.13.
 */

var   winston = require('winston')
    , config = {
        levels: {
            silly: 0,
            verbose: 1,
            info: 2,
            data: 3,
            warn: 4,
            debug: 5,
            error: 6
        },
        colors: {
            silly: 'magenta',
            verbose: 'cyan',
            info: 'green',
            data: 'grey',
            warn: 'yellow',
            debug: 'blue',
            error: 'red'
        }
    }
    , log = new ( winston.Logger ) ({

    transports: [
        new ( winston.transports.Console ) ({
            colorize: true
        })
    ],
    levels : config.levels,
    colors : config.colors
});

exports.log = log;
<commit_msg>removed unused file<commit_after><|endoftext|>


<commit_before>import { List, Map as $Map } from 'immutable';
import { RECEIVE_ARCHIVE, REVIVE_TOGGLE } from './archive-actions';

function getInitState () {
    return new $Map({ list: new List() });
}

const archiveStore = (state = getInitState(), action) => {
    switch (action.type) {
        case REVIVE_TOGGLE:
            return state.update('list', (list) => list.remove(list.indexOf(action.value)));
        case RECEIVE_ARCHIVE:
            return state.set('list', new List(action.value));
        default:
            return state;
    }
};

export default archiveStore;
<commit_msg>Should update archive store correctly when reviving.<commit_after>import { List, Map as $Map } from 'immutable';
import { RECEIVE_ARCHIVE, REVIVE_TOGGLE } from './archive-actions';

function getInitState () {
    return new $Map({ list: new List() });
}

const archiveStore = (state = getInitState(), action) => {
    switch (action.type) {
        case REVIVE_TOGGLE:
            return state.update('list', (list) => list.filter(item => item.name !== action.value));
        case RECEIVE_ARCHIVE:
            return state.set('list', new List(action.value));
        default:
            return state;
    }
};

export default archiveStore;
<|endoftext|>


<commit_before>var controllerDir;
var appName;

function getAppName() {
    var parts = __dirname.replace(/\\/g, '/').split('/');
    return parts[parts.length - 2].split('.')[0];
}

// Get js-controller directory to load libs
function getControllerDir(isInstall) {
    var fs = require('fs');
    // Find the js-controller location
    var controllerDir = __dirname.replace(/\\/g, '/');
    controllerDir = controllerDir.split('/');
    if (controllerDir[controllerDir.length - 3] === 'adapter') {
        controllerDir.splice(controllerDir.length - 3, 3);
        controllerDir = controllerDir.join('/');
    } else if (controllerDir[controllerDir.length - 3] === 'node_modules') {
        controllerDir.splice(controllerDir.length - 3, 3);
        controllerDir = controllerDir.join('/');
        if (fs.existsSync(controllerDir + '/node_modules/' + appName + '.js-controller')) {
            controllerDir += '/node_modules/' + appName + '.js-controller';
        } else if (fs.existsSync(controllerDir + '/node_modules/' + appName.toLowerCase() + '.js-controller')) {
            controllerDir += '/node_modules/' + appName.toLowerCase() + '.js-controller';
        } else if (!fs.existsSync(controllerDir + '/controller.js')) {
            if (!isInstall) {
                console.log('Cannot find js-controller');
                process.exit(10);
            } else {
                process.exit();
            }
        }
    } else {
        if (!isInstall) {
            console.log('Cannot find js-controller');
            process.exit(10);
        } else {
            process.exit();
        }
    }
    return controllerDir;
}

// Read controller configuration file
function getConfig() {
    var fs = require('fs');
    if (fs.existsSync(controllerDir + '/conf/' + appName + '.json')) {
        return JSON.parse(fs.readFileSync(controllerDir + '/conf/' + appName + '.json'));
    } else if (fs.existsSync(controllerDir + '/conf/' + appName.toLowerCase() + '.json')) {
        return JSON.parse(fs.readFileSync(controllerDir + '/conf/' + appName.toLowerCase() + '.json'));
    } else {
        throw new Error('Cannot find ' + controllerDir + '/conf/' + appName + '.json');
    }
}
appName       = getAppName();
controllerDir = getControllerDir(typeof process !== 'undefined' && process.argv && process.argv.indexOf('--install') !== -1);

exports.controllerDir = controllerDir;
exports.getConfig =     getConfig;
exports.adapter =       require(controllerDir + '/lib/adapter.js');
exports.appName =       appName;
<commit_msg>update utils.js<commit_after>var controllerDir;
var appName;

function getAppName() {
    var parts = __dirname.replace(/\\/g, '/').split('/');
    return parts[parts.length - 2].split('.')[0];
}

// Get js-controller directory to load libs
function getControllerDir(isInstall) {
    var fs = require('fs');
    // Find the js-controller location
    var controllerDir = __dirname.replace(/\\/g, '/');
    controllerDir = controllerDir.split('/');
    if (controllerDir[controllerDir.length - 3] === 'adapter') {
        controllerDir.splice(controllerDir.length - 3, 3);
        controllerDir = controllerDir.join('/');
    } else if (controllerDir[controllerDir.length - 3] === 'node_modules') {
        controllerDir.splice(controllerDir.length - 3, 3);
        controllerDir = controllerDir.join('/');
        if (fs.existsSync(controllerDir + '/node_modules/' + appName + '.js-controller')) {
            controllerDir += '/node_modules/' + appName + '.js-controller';
        } else if (fs.existsSync(controllerDir + '/node_modules/' + appName.toLowerCase() + '.js-controller')) {
            controllerDir += '/node_modules/' + appName.toLowerCase() + '.js-controller';
        } else if (!fs.existsSync(controllerDir + '/controller.js')) {
            if (!isInstall) {
                console.log('Cannot find js-controller');
                process.exit(10);
            } else {
                process.exit();
            }
        }
    } else if (fs.existsSync(__dirname + '/../../node_modules/' + appName.toLowerCase() + '.js-controller')) {
        controllerDir.splice(controllerDir.length - 2, 2);
        return controllerDir.join('/') + '/node_modules/' + appName.toLowerCase() + '.js-controller';
    } else {
        if (!isInstall) {
            console.log('Cannot find js-controller');
            process.exit(10);
        } else {
            process.exit();
        }
    }
    return controllerDir;
}

// Read controller configuration file
function getConfig() {
    var fs = require('fs');
    if (fs.existsSync(controllerDir + '/conf/' + appName + '.json')) {
        return JSON.parse(fs.readFileSync(controllerDir + '/conf/' + appName + '.json'));
    } else if (fs.existsSync(controllerDir + '/conf/' + appName.toLowerCase() + '.json')) {
        return JSON.parse(fs.readFileSync(controllerDir + '/conf/' + appName.toLowerCase() + '.json'));
    } else {
        throw new Error('Cannot find ' + controllerDir + '/conf/' + appName + '.json');
    }
}
appName       = getAppName();
controllerDir = getControllerDir(typeof process !== 'undefined' && process.argv && process.argv.indexOf('--install') !== -1);

exports.controllerDir = controllerDir;
exports.getConfig =     getConfig;
exports.Adapter =       require(controllerDir + '/lib/adapter.js');
exports.appName =       appName;
<|endoftext|>


<commit_before>/*
Node wrapper for Freshdesk v2 API

Copyright (C) 2016-2018 Arjun Komath <arjunkomath@gmail.com>
Copyright (C) 2016-2018 Maksim Koryukov <maxkoryukov@gmail.com>

This program is free software: you can redistribute it and/or modify
it under the terms of the MIT License, attached to this software package.

This program 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.

You should have received a copy of the MIT License along with this
program. If not, see <https://opensource.org/licenses/MIT>.

http://spdx.org/licenses/MIT
*/

/**
 * Freshdesk API utilities
 *
 * @module
 */

"use strict";

const debug = require("debug")("freshdesk-api");
const FormData = require("form-data");
const { request } = require("undici");

/**
 * Freshdesk's API protocol violations
 *
 * @param {String}  message Error message
 * @param {Number}  status  HTTP status of the received Freshdesk-response. Could be useful for debugging
 * @param {Object}  data    Parsed response of the Freshdesk API
 */
class FreshdeskError extends Error {
	constructor(message, data, res, req) {
		super();

		this.name = "FreshdeskError";
		this.message = message || "Error in Freshdesk's client API";
		this.stack = new Error().stack;

		this.data = data;

		this.status = res.statusCode;

		this.apiTarget = `${req.method} ${req.path}`;
		this.requestId = res.headers["x-request-id"];
	}
}

function createResponseHandler(cb) {
	return function(error, response, body, request) {
		if (error) {
			debug("Error on request: [%s], req path [%s] raw body: %o", error);
			return cb(error);
		}

		const extra = {
			pageIsLast: true,
			requestId: ""
		};

		debug("Got API response, status [%s]", response.status);

		if (
			response &&
			response.headers &&
			"string" === typeof response.headers.link
		) {
			debug(
				"Detected http-header LINK, page is not last",
				response.headers.link
			);
			extra.pageIsLast = false;
			// TODO: reconsider this property
			extra._headersLink = response.headers.link;
		}

		if (
			response &&
			response.headers &&
			"string" === typeof response.headers["x-request-id"]
		) {
			extra.requestId = response.headers["x-request-id"];
		}

		switch (response.statusCode) {
			// SUCCESS
			// https://httpstatuses.com/200 OK
			// https://httpstatuses.com/201 Created
			case 200:
			case 201:
				return cb(null, body, extra);

			// SUCCESS for DELETE operations
			// https://httpstatuses.com/204 No Content
			case 204:
				return cb(null, null, extra);

			// https://httpstatuses.com/404 Not found
			case 404:
				debug("path:[%s] raw body: %o", request.path);

				// In most casses 404 means, that there is no such entity on requested
				// Freshdesk domain. For example, you are trying to update non-existent
				// contact
				// But, it also could be a result of wrong URL (?!?!?)
				//
				// In most cases the body is EMPTY, so we will just warn about wrong entity
				return cb(
					new FreshdeskError(
						"The requested entity was not found",
						body,
						response,
						request
					)
				);

			// https://httpstatuses.com/409 Conflict  - NOT UNIQUE, where unique required
			case 409:
			default:
				debug("path:[%s] raw body: %o", request.path);
				return cb(new FreshdeskError(body.description, body, response, request));
		}
	};
}

// TODO: try to make less params here
async function makeRequest(method, auth, url, qs, data, cb) {
	// eslint-disable-line max-params
	const options = {
		method: method,
		headers: {
			"Content-Type": "application/json",
			Authorization: auth
		},
		query: qs
	};

	const fullUrl = new URL(url);
	const req = {
		...options,
		url,
		path: fullUrl.pathname
	};

	if (data) {
		if ("attachments" in data && Array.isArray(data.attachments)) {
			const fd = new FormData();

			for (let [entryKey, entryValue] of Object.entries(data)) {
				if (Array.isArray(entryValue)) {
					for (let arrElement of entryValue) {
						fd.append(entryKey + "[]", arrElement);
					}
				} else {
					fd.append(entryKey, entryValue);
				}
			}

			const promise = new Promise((resolve, reject) => {
				fd.submit({
					host: fullUrl.hostname,
					port: fullUrl.port,
					path: fullUrl.pathname,
					protocol: fullUrl.protocol,
					headers: {
						Authorization: auth
					}
				}, function(err, res) {
					if (err) {
						return reject(err);
					}
					let body = "";
					res.on("readable", () => {
						const value = res.read();
						if (value !== null) {
							body += value;
						}
					});
					res.on("end", () => {
						let resolvedBody;
						if ((res.headers["content-type"] && res.headers["content-type"].startsWith("application/json")) ||
							(res.headers["Content-Type"] && res.headers["Content-Type"].startsWith("application/json"))) {
							resolvedBody = JSON.parse(body);
						} else {
							resolvedBody = body;
						}
						resolve({
							responseBody: resolvedBody,
							response: res
						});
					});
					res.on("error", (err) => {
						reject(err);
					});
				});
			});

			try {
				const { response, responseBody } = await promise;
				return createResponseHandler(cb)(null, response, responseBody, req);
			} catch (err) {
				cb(err);
			}
		} else {
			options.body = JSON.stringify(data);
		}
	}

	try {
		const response = await request(url, options);
		const data = (response.statusCode !== 204 && (!response.headers["content-type"] || response.headers["content-type"].startsWith("application/json"))) ? await response.body.json() : await response.body.text();
		return createResponseHandler(cb)(null, response, data, req);
	} catch (error) {
		const data = request.body;
		return createResponseHandler(cb)(
			error,
			req,
			data,
			req
		);
	}
}

/**
 * Checks if value is null or undefined.
 *
 * @private
 *
 * @param  {*}       value    The value to check.
 * @return {boolean}          Returns `true` if value is `null` or `undefined`; else `false`.
 *
 */
function isNil(value) {
	if (value === null || typeof value === "undefined") {
		return true;
	}

	return false;
}

/**
 * Checks if value is classified as a Function object.
 *
 * @private
 *
 * @param  {*}       value    The value to check.
 * @return {boolean}          Returns `true` if value is a `function`; else `false`.
 */
function isFunction(value) {
	return typeof value === "function";
}

module.exports.makeRequest = makeRequest;
module.exports.FreshdeskError = FreshdeskError;
module.exports.isNil = isNil;
module.exports.isFunction = isFunction;

// For testing
module.exports.createResponseHandler = createResponseHandler;
<commit_msg>fix: Unexpected end of JSON input error when rate limit exceeded<commit_after>/*
Node wrapper for Freshdesk v2 API

Copyright (C) 2016-2018 Arjun Komath <arjunkomath@gmail.com>
Copyright (C) 2016-2018 Maksim Koryukov <maxkoryukov@gmail.com>

This program is free software: you can redistribute it and/or modify
it under the terms of the MIT License, attached to this software package.

This program 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.

You should have received a copy of the MIT License along with this
program. If not, see <https://opensource.org/licenses/MIT>.

http://spdx.org/licenses/MIT
*/

/**
 * Freshdesk API utilities
 *
 * @module
 */

"use strict";

const debug = require("debug")("freshdesk-api");
const FormData = require("form-data");
const { request } = require("undici");

/**
 * Freshdesk's API protocol violations
 *
 * @param {String}  message Error message
 * @param {Number}  status  HTTP status of the received Freshdesk-response. Could be useful for debugging
 * @param {Object}  data    Parsed response of the Freshdesk API
 */
class FreshdeskError extends Error {
	constructor(message, data, res, req) {
		super();

		this.name = "FreshdeskError";
		this.message = message || "Error in Freshdesk's client API";
		this.stack = new Error().stack;

		this.data = data;

		this.status = res.statusCode;

		this.apiTarget = `${req.method} ${req.path}`;
		this.requestId = res.headers["x-request-id"];
	}
}

function createResponseHandler(cb) {
	return function(error, response, body, request) {
		if (error) {
			debug("Error on request: [%s], req path [%s] raw body: %o", error);
			return cb(error);
		}

		const extra = {
			pageIsLast: true,
			requestId: ""
		};

		debug("Got API response, status [%s]", response.status);

		if (
			response &&
			response.headers &&
			"string" === typeof response.headers.link
		) {
			debug(
				"Detected http-header LINK, page is not last",
				response.headers.link
			);
			extra.pageIsLast = false;
			// TODO: reconsider this property
			extra._headersLink = response.headers.link;
		}

		if (
			response &&
			response.headers &&
			"string" === typeof response.headers["x-request-id"]
		) {
			extra.requestId = response.headers["x-request-id"];
		}

		switch (response.statusCode) {
			// SUCCESS
			// https://httpstatuses.com/200 OK
			// https://httpstatuses.com/201 Created
			case 200:
			case 201:
				return cb(null, body, extra);

			// SUCCESS for DELETE operations
			// https://httpstatuses.com/204 No Content
			case 204:
				return cb(null, null, extra);

			// https://httpstatuses.com/404 Not found
			case 404:
				debug("path:[%s] raw body: %o", request.path);

				// In most casses 404 means, that there is no such entity on requested
				// Freshdesk domain. For example, you are trying to update non-existent
				// contact
				// But, it also could be a result of wrong URL (?!?!?)
				//
				// In most cases the body is EMPTY, so we will just warn about wrong entity
				return cb(
					new FreshdeskError(
						"The requested entity was not found",
						body,
						response,
						request
					)
				);

			// https://httpstatuses.com/409 Conflict  - NOT UNIQUE, where unique required
			case 409:
			default:
				debug("path:[%s] raw body: %o", request.path);
				return cb(new FreshdeskError(body.description, body, response, request));
		}
	};
}

// TODO: try to make less params here
async function makeRequest(method, auth, url, qs, data, cb) {
	// eslint-disable-line max-params
	const options = {
		method: method,
		headers: {
			"Content-Type": "application/json",
			Authorization: auth
		},
		query: qs
	};

	const fullUrl = new URL(url);
	const req = {
		...options,
		url,
		path: fullUrl.pathname
	};

	if (data) {
		if ("attachments" in data && Array.isArray(data.attachments)) {
			const fd = new FormData();

			for (let [entryKey, entryValue] of Object.entries(data)) {
				if (Array.isArray(entryValue)) {
					for (let arrElement of entryValue) {
						fd.append(entryKey + "[]", arrElement);
					}
				} else {
					fd.append(entryKey, entryValue);
				}
			}

			const promise = new Promise((resolve, reject) => {
				fd.submit({
					host: fullUrl.hostname,
					port: fullUrl.port,
					path: fullUrl.pathname,
					protocol: fullUrl.protocol,
					headers: {
						Authorization: auth
					}
				}, function(err, res) {
					if (err) {
						return reject(err);
					}
					let body = "";
					res.on("readable", () => {
						const value = res.read();
						if (value !== null) {
							body += value;
						}
					});
					res.on("end", () => {
						let resolvedBody;
						if ((res.headers["content-type"] && res.headers["content-type"].startsWith("application/json")) ||
							(res.headers["Content-Type"] && res.headers["Content-Type"].startsWith("application/json"))) {
							resolvedBody = JSON.parse(body);
						} else {
							resolvedBody = body;
						}
						resolve({
							responseBody: resolvedBody,
							response: res
						});
					});
					res.on("error", (err) => {
						reject(err);
					});
				});
			});

			try {
				const { response, responseBody } = await promise;
				return createResponseHandler(cb)(null, response, responseBody, req);
			} catch (err) {
				cb(err);
			}
		} else {
			options.body = JSON.stringify(data);
		}
	}

	try {
		const response = await request(url, options);
		const data = (response.statusCode !== 204 && (response.headers["content-type"]?.startsWith("application/json"))) ? await response.body.json() : await response.body.text();
		return createResponseHandler(cb)(null, response, data, req);
	} catch (error) {
		const data = request.body;
		return createResponseHandler(cb)(
			error,
			req,
			data,
			req
		);
	}
}

/**
 * Checks if value is null or undefined.
 *
 * @private
 *
 * @param  {*}       value    The value to check.
 * @return {boolean}          Returns `true` if value is `null` or `undefined`; else `false`.
 *
 */
function isNil(value) {
	if (value === null || typeof value === "undefined") {
		return true;
	}

	return false;
}

/**
 * Checks if value is classified as a Function object.
 *
 * @private
 *
 * @param  {*}       value    The value to check.
 * @return {boolean}          Returns `true` if value is a `function`; else `false`.
 */
function isFunction(value) {
	return typeof value === "function";
}

module.exports.makeRequest = makeRequest;
module.exports.FreshdeskError = FreshdeskError;
module.exports.isNil = isNil;
module.exports.isFunction = isFunction;

// For testing
module.exports.createResponseHandler = createResponseHandler;
<|endoftext|>


<commit_before>
/*
 * Module dependencies
 */
var fs = require('fs');
var path = require('path');
var util = require('util');

var local = require('./local');

/*
 * Expose all the functions here
 */

exports = module.exports = {};

/*
 * `humanize` function
 *
 * @param {String} stack
 * @return {String} structured stack
 *
 * @api private
 */

function humanize(stack){

  var pack = {}, regex;

  if( stack === void 0 || stack === null )
    return null;
  if( !Array.isArray(stack) )
    stack = stack.split(/\n[ ]+at[ ]+/);

  stack = stack.join('\n   at  ');

  // no need to proceed
  if( stack.match(/\((.*node_modules.*)\)/) === null ){
    return stack;
  }

  stack.match(
    /\((.*node_modules.*)\)/g
  ).forEach(function(filename){

    var file;
    filename.replace(/node_modules.\w+(\-\w+|\.\w+|)/g,
      function($0,$1,$2){

        file = file ? file + path.sep + $0 : $0;

        if(!pack[file]){

          try {
            pack[file] = path.resolve( local.path, file, 'package.json' );
          } catch(err){
            pack[file] = file;
            return file;
          }

          pack[file] = JSON.parse( fs.readFileSync(pack[file]) );
          pack[file] = pack[file].name + '@' + pack[file].version;
        }

        return pack[file];
      }
    );
  });

  pack[local.path] = local.badge;
  regex = Object.keys(pack);

  if(regex.length > 1){
    regex = regex.sort().reverse().join('|');
  }

  return stack.replace(
    new RegExp(regex, 'g'),
    function($0){
      return pack[$0];
    }
  );
}
exports.humanize = humanize;

/*
 * `format` function
 *
 * @param {Error} error
 * @param {String} stack
 * @return {String} formatted stack
 *
 * @api private
 */

var template = (
  ' <name>: <message>' +
  '\n\n source: <source>' +
  '\n -- \n start <stack>' +
  '\n -- \n ' +
  '<arch>\n'
);

function format(error, stack){

  return (
     template
     .replace('<stack>', stack)
     .replace('<arch>', local.arch )
     .replace( local.path , local.badge )
     .replace(/.*@.*/,
        function($0){
          return $0.replace(/^[ ]+\w+[ ]+/, '    >  ');
        })
     .replace(/\n.*(<source>).*\n/,
      function($0, $1, $2, $3){
        var match = $3.match(/\((.*@.*)\)/);
        if(match === null)
          return '';
        else
          return $0.replace(new RegExp($1, 'g'), match[0]);
      })
    .replace(/<(name|message)>/g,
      function($0,$1){
        return error[$1];
      })
  );

}
exports.format = format;

/**
 * `flood` function
 * Formats every stack trace
 * Takes no parameter what so ever
 *
 */

function flood(){

  Error.prepareStackTrace = function(error, stack){

    Object.defineProperties(error, {
      message : {
        enumerable : false,
        configurable : true
      },
      arch : {
        enumerable : false,
        configurable : true,
        value : local.arch
      }
    });

    return format(
      error, humanize(stack)
    );
  };
}
exports.flood = flood;

var env = process.env;

if(env.NODE_ENV === 'test' ) {
  flood();
  Error.stackTraceLimit = Infinity;
}

/*
 * jaredhanson's merge
 * https://github.com/jaredhanson/utils-merge
 */

function merge(a,b){

  if(a && b){
    for(var key in b){
      a[key] = b[key];
    }
  }
  return a;
}
exports.merge =  merge;
<commit_msg>the problem of pointing the source<commit_after>
/*
 * Module dependencies
 */
var fs = require('fs');
var path = require('path');
var util = require('util');

var local = require('./local');

/*
 * Expose all the functions here
 */

exports = module.exports = {};

/*
 * `humanize` function
 *
 * @param {String} stack
 * @return {String} structured stack
 *
 * @api private
 */

function humanize(stack){

  var pack = {}, regex;

  if( stack === void 0 || stack === null )
    return null;
  if( !Array.isArray(stack) )
    stack = stack.split(/\n[ ]+at[ ]+/);

  stack = stack.join('\n   at  ');

  // no need to proceed
  if( stack.match(/\((.*node_modules.*)\)/) === null ){
    return stack;
  }

  stack.match(
    /\((.*node_modules.*)\)/g
  ).forEach(function(filename){

    var file;
    filename.replace(/node_modules.\w+(\-\w+|\.\w+|)/g,
      function($0,$1,$2){

        file = file ? file + path.sep + $0 : $0;

        if(!pack[file]){

          try {
            pack[file] = path.resolve( local.path, file, 'package.json' );
          } catch(err){
            pack[file] = file;
            return file;
          }

          pack[file] = JSON.parse( fs.readFileSync(pack[file]) );
          pack[file] = pack[file].name + '@' + pack[file].version;
        }

        return pack[file];
      }
    );
  });

  pack[local.path] = local.badge;
  regex = Object.keys(pack);

  if(regex.length > 1){
    regex = regex.sort().reverse().join('|');
  }

  return stack.replace(
    new RegExp(regex, 'g'),
    function($0){
      return pack[$0];
    }
  );
}
exports.humanize = humanize;

/*
 * `format` function
 *
 * @param {Error} error
 * @param {String} stack
 * @return {String} formatted stack
 *
 * @api private
 */

var template = [
  ' <name>: <message>',
  '\n\n source: <source>',
  '\n -- \n start <stack>',
  '\n -- \n ',
  '<arch>\n'
];

function format(error, stack){

  stack = template.join('')
   .replace('<stack>', stack )
   .replace('<arch>', local.arch )
   .replace( local.path , local.badge )
   .replace(/.*@.*/,
      function($0,$1,$2){
        return $0.replace(/^[ ]+\w+[ ]+/, '    >  ');
      })
  .replace(/<(name|message)>/g,
     function($0,$1){
       return error[$1];
     });

  var source = stack.match(/[ ]+>[ ]+.*\((.*@.*)\)/);
  if( source !== null ){
    stack = stack.replace(/<source>/, source[1]);
  } else {
    stack = stack.split(/\n/).splice(1,1).join('\n');
  }

  return stack;

}
exports.format = format;

/**
 * `flood` function
 * Formats every stack trace
 * Takes no parameter what so ever
 *
 */

function flood(){

  Error.prepareStackTrace = function(error, stack){

    Object.defineProperties(error, {
      message : {
        enumerable : false,
        configurable : true
      },
      arch : {
        enumerable : false,
        configurable : true,
        value : local.arch
      }
    });

    return format(
      error, humanize(stack)
    );
  };
}
exports.flood = flood;

var env = process.env;

if(env.NODE_ENV === 'test' ) {
  flood();
  Error.stackTraceLimit = Infinity;
}

/*
 * jaredhanson's merge
 * https://github.com/jaredhanson/utils-merge
 */

function merge(a,b){

  if(a && b){
    for(var key in b){
      a[key] = b[key];
    }
  }
  return a;
}
exports.merge =  merge;
<|endoftext|>


<commit_before>import { HTMLMediaAssembler } from './media'

const { HTMLVideoElement } = window

export class Video extends HTMLMediaAssembler {
    // todo
    /**
     * @returns {window.HTMLVideoElement}
     */
    static get interface() {
        return HTMLVideoElement
    }
}

/**
 * @param {*} [init]
 * @returns {Video}
 */
export function video(...init) {
    return new Video(...init)
}
<commit_msg>Video: complete interface<commit_after>import { HTMLMediaAssembler } from './media'

const { HTMLVideoElement } = window

export class Video extends HTMLMediaAssembler {
    /**
     * @param {Number} width
     */
    set width(width) {
        this.node.width = width
    }

    /**
     * @returns {Number}
     */
    get width() {
        return this.node.width
    }

    /**
     * @param {Number} height
     */
    set height(height) {
        this.node.height = height
    }

    /**
     * @returns {Number}
     */
    get height() {
        return this.node.height
    }

    /**
     * @returns {Number}
     */
    get videoWidth() {
        return this.node.videoWidth
    }

    /**
     * @returns {Number}
     */
    get videoHeight() {
        return this.node.videoHeight
    }

    /**
     * @param {String} poster
     */
    set poster(poster) {
        this.node.poster = poster
    }

    /**
     * @returns {String}
     */
    get poster() {
        return this.node.poster
    }

    /**
     * @returns {window.HTMLVideoElement}
     */
    static get interface() {
        return HTMLVideoElement
    }
}

/**
 * @param {*} [init]
 * @returns {Video}
 */
export function video(...init) {
    return new Video(...init)
}
<|endoftext|>


<commit_before>/**
 *  Module dependencies
 */

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

/**
 * Utility functions to synchronously test whether the giving path
 * is a file or a directory.
 */
var is = (function(ret) {
  ['File', 'Directory'].forEach(function(method) {
    var memo = {}
      , fileObj;
    ret[method] = function(path) {
      if (memo[path] !== undefined) {
        return memo[path];
      }
      try {
        fileObj = fs.statSync(path);
      } catch(e) {
        return memo[path] = false;
      }
      return memo[path] = fileObj['is'+method](path);
    }
  });
  return ret;
}({}));

/**
 *  Filtering files and sub-directories in a directory
 */
var filter = function(dir) {
  var ret = {};
  ['File', 'Directory'].forEach(function(method){
    ret[method] = function(cb) {
      if (is.Directory(dir)) {
        fs.readdir(dir, function(err, files) {
          files
            .filter(function(n) { return is[method](path.join(dir, n)) })
            .map(function(n) { cb.call(null, path.join(dir, n)) });
        });
      }
    };
  });
  return ret;
};

/**
 *  A Container for storing unique filenames.
 */
var fileNameCache = (function(cache) {
  return {
    push: function(name) {
      cache[name] = 1;
      return this;
    },
    each: function() {
      var temp = [];
      for (var name in cache) {
        if (cache.hasOwnProperty(name) && is.File(name)) {
          temp.push(name);
        }
      }
      Array.prototype.forEach.apply(temp, arguments);
      return this;
    },
    clear: function(){
      cache = {};
      return this;
    }
  };
}({}));

/**
 * Abstracting the way of avoiding duplicate function call.
 */
var worker = (function() {
  var free = true;
  return {
    busydoing: function(cb) {
      if (free) {
        free = false;
        cb.call();
      }
    },
    free: function() {
      free = true;
    }
  }
}());

/**
 * Delay function call and ignore invalid filenames
 */
var normalizeCall = function(cb, fname) {
  // Store each name of the modifying or temporary files generated by an editor.
  fileNameCache.push(fname);

  worker.busydoing(function() {
    // A heuristic delay of the write-to-file process
    setTimeout(function() {

      // When the write-to-file process is done, send all filtered filenames
      // to the callback function and call it.
      fileNameCache
        .each(function(f) { cb.call(null, f); })
        .clear();

      worker.free();

    }, 100);
  });
};

/**
 * Watch a file or a directory recursively
 *
 * @param {String} fpath
 * @param {Function} cb
 *
 *   watch('fpath', function(file) {
 *     console.log(file, ' changed');
 *   });
 */
function watch(fpath, cb) {
  console.log(fpath);
  if (is.File(fpath)) {
    fs.watchFile(fpath, function(err) {
      normalizeCall(cb, fpath);
    });
    return;
  }

  if (is.Directory(fpath)) {
    var filtered = filter(fpath);
    try {
      fs.watch(fpath, function(err, fname) {
        normalizeCall(cb,
          path.join(fpath, fname)
        );
      });
    } catch(e) {
      //In case the system limit of watching a directory using fs.watch method;
      //https://github.com/joyent/node/issues/2479
      filtered.File(function(file) {
        watch(file, cb);
      });
    }

    filtered.Directory(function(dir) {
      watch(dir, cb);
    });
  }

};

// Expose
module.exports = watch;

<commit_msg>clean up<commit_after>/**
 *  Module dependencies
 */

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

/**
 * Utility functions to synchronously test whether the giving path
 * is a file or a directory.
 */
var is = (function(ret) {
  ['File', 'Directory'].forEach(function(method) {
    var memo = {}
      , fileObj;
    ret[method] = function(path) {
      if (memo[path] !== undefined) {
        return memo[path];
      }
      try {
        fileObj = fs.statSync(path);
      } catch(e) {
        return memo[path] = false;
      }
      return memo[path] = fileObj['is'+method](path);
    }
  });
  return ret;
}({}));

/**
 *  Filtering files and sub-directories in a directory
 */
var filter = function(dir) {
  var ret = {};
  ['File', 'Directory'].forEach(function(method){
    ret[method] = function(cb) {
      if (is.Directory(dir)) {
        fs.readdir(dir, function(err, files) {
          files
            .filter(function(n) { return is[method](path.join(dir, n)) })
            .map(function(n) { cb.call(null, path.join(dir, n)) });
        });
      }
    };
  });
  return ret;
};

/**
 *  A Container for storing unique filenames.
 */
var fileNameCache = (function(cache) {
  return {
    push: function(name) {
      cache[name] = 1;
      return this;
    },
    each: function() {
      var temp = [];
      for (var name in cache) {
        if (cache.hasOwnProperty(name) && is.File(name)) {
          temp.push(name);
        }
      }
      Array.prototype.forEach.apply(temp, arguments);
      return this;
    },
    clear: function(){
      cache = {};
      return this;
    }
  };
}({}));

/**
 * Abstracting the way of avoiding duplicate function call.
 */
var worker = (function() {
  var free = true;
  return {
    busydoing: function(cb) {
      if (free) {
        free = false;
        cb.call();
      }
    },
    free: function() {
      free = true;
    }
  }
}());

/**
 * Delay function call and ignore invalid filenames
 */
var normalizeCall = function(cb, fname) {
  // Store each name of the modifying or temporary files generated by an editor.
  fileNameCache.push(fname);

  worker.busydoing(function() {
    // A heuristic delay of the write-to-file process
    setTimeout(function() {

      // When the write-to-file process is done, send all filtered filenames
      // to the callback function and call it.
      fileNameCache
        .each(function(f) { cb.call(null, f); })
        .clear();

      worker.free();

    }, 100);
  });
};

/**
 * Watch a file or a directory recursively
 *
 * @param {String} fpath
 * @param {Function} cb
 *
 *   watch('fpath', function(file) {
 *     console.log(file, ' changed');
 *   });
 */
function watch(fpath, cb) {

  if (is.File(fpath)) {
    fs.watchFile(fpath, function(err) {
      normalizeCall(cb, fpath);
    });
    return;
  }

  if (is.Directory(fpath)) {
    var filtered = filter(fpath);
    try {
      fs.watch(fpath, function(err, fname) {
        normalizeCall(cb,
          path.join(fpath, fname)
        );
      });
    } catch(e) {
      //In case the system limit of watching a directory using fs.watch method;
      //https://github.com/joyent/node/issues/2479
      filtered.File(function(file) {
        watch(file, cb);
      });
    }

    filtered.Directory(function(dir) {
      watch(dir, cb);
    });
  }

};

// Expose
module.exports = watch;

<|endoftext|>


<commit_before>module.exports = World;

function World(manager, file, info) {
  this._handle = info.handle;
  this._manager = manager;

  this.lastModified = file.lastModifiedDate;
  this.metadata = info.metadata;

  // TODO: Remove this logic once world metadata is automatically upgraded.
  var location, data, params;
  switch (info.metadata.__version__) {
    case 1:
      data = info.metadata.planet;
      params = data.config.celestialParameters;

      var coord = data.config.skyParameters.coordinate;
      if (coord) {
        location = coord.parentSystem.location;
      }

      break;
    case 2:
    case 3:
      data = info.metadata.worldTemplate;
      params = data.celestialParameters;

      if (params) {
        location = params.coordinate.location;
      }

      break;
    default:
      throw new Error('Unsupported metadata version ' + metadata.__version__);
  }

  this.tilesX = data.size[0];
  this.tilesY = data.size[1];

  this.spawnX = info.metadata.playerStart[0];
  this.spawnY = info.metadata.playerStart[1];

  // Ships don't have name or location.
  if (params) {
    this.name = params.name;
    this.biome = params.primaryBiomeName || params.scanData.primaryBiomeName;
  } else {
    if (file.name.match(/\.shipworld$/)) {
      this.name = 'Ship';
    } else {
      this.name = 'Unknown';
    }
    this.biome = null;
  }

  if (location) {
    this.x = location[0];
    this.y = location[1];
  } else {
    this.x = null;
    this.y = null;
  }

  this.seed = info.metadata.worldTemplate.seed;
}

World.prototype.close = function (callback) {
  this._manager.api.close(this._handle, callback);
  this._manager = null;
  this._handle = -1;
};

World.prototype.getRegion = function (x, y, callback) {
  if (!this._manager) throw new Error('The world file is closed');
  this._manager.api.getRegion(this._handle, x, y, callback);
};

World.prototype.isOpen = function () {
  return !!this._manager;
};
<commit_msg>Don't break on new worlds<commit_after>module.exports = World;

function World(manager, file, info) {
  this._handle = info.handle;
  this._manager = manager;

  this.lastModified = file.lastModifiedDate;
  this.metadata = info.metadata;

  // TODO: Remove this logic once world metadata is automatically upgraded.
  var location, data, params;
  switch (info.metadata.__version__) {
    case 1:
      data = info.metadata.planet;
      params = data.config.celestialParameters;

      var coord = data.config.skyParameters.coordinate;
      if (coord) {
        location = coord.parentSystem.location;
      }

      break;
    case 2:
    case 3:
    case 4:
    case 5:
    case 6:
      data = info.metadata.worldTemplate;
      params = data.celestialParameters;

      if (params) {
        location = params.coordinate.location;
      }

      break;
    default:
      throw new Error('Unsupported metadata version ' + metadata.__version__);
  }

  this.tilesX = data.size[0];
  this.tilesY = data.size[1];

  this.spawnX = info.metadata.playerStart[0];
  this.spawnY = info.metadata.playerStart[1];

  // Ships don't have name or location.
  if (params) {
    this.name = params.name;
    if (params.parameters) {
      this.biome = params.parameters.worldType;
    } else if (params.primaryBiomeName) {
      this.biome = params.primaryBiomeName;
    } else if (params.scanData) {
      this.biome = params.scanData.primaryBiomeName;
    }
  } else {
    if (file.name.match(/\.shipworld$/)) {
      this.name = 'Ship';
    } else {
      this.name = 'Unknown';
    }
    this.biome = null;
  }

  if (location) {
    this.x = location[0];
    this.y = location[1];
  } else {
    this.x = null;
    this.y = null;
  }

  this.seed = info.metadata.worldTemplate.seed;
}

World.prototype.close = function (callback) {
  this._manager.api.close(this._handle, callback);
  this._manager = null;
  this._handle = -1;
};

World.prototype.getRegion = function (x, y, callback) {
  if (!this._manager) throw new Error('The world file is closed');
  this._manager.api.getRegion(this._handle, x, y, callback);
};

World.prototype.isOpen = function () {
  return !!this._manager;
};
<|endoftext|>


<commit_before>var templates             = require('./templates');
var PassportProfileMapper = require('./claims/PassportProfileMapper');
var utils                 = require('./utils');
var saml11 = require('saml').Saml11;
var jwt                   = require('jsonwebtoken');

function asResource(res) {
  if(res.substr(0, 6) !== 'http:/' &&
      res.substr(0, 6) !== 'https:' &&
      res.substr(0, 4) !== 'urn:') {
    return 'urn:' + res;
  }
  return res;
}

/**
 * WSFederation middleware.
 *
 * This middleware creates a WSFed endpoint based on the user logged in identity.
 *
 * options:
 * - profileMapper(profile) a ProfileMapper implementation to convert a user profile to claims  (PassportProfile).
 * - getUserFromRequest(req) a function that given a request returns the user. By default req.user
 * - issuer string
 * - cert the public certificate
 * - key the private certificate to sign all tokens
 * - postUrl function (wtrealm, wreply, request, callback)
 *
 * @param  {[type]} options [description]
 * @return {[type]}         [description]
 */
module.exports = function(options) {
  options = options || {};
  options.profileMapper = options.profileMapper || PassportProfileMapper;
  options.getUserFromRequest = options.getUserFromRequest || function(req){ return req.user; };

  if(typeof options.getPostURL !== 'function') {
    throw new Error('getPostURL is required');
  }

  function renderResponse(res, postUrl, wctx, assertion) {
    res.set('Content-Type', 'text/html');
    res.send(templates.form({
      callback:        postUrl,
      wctx:            wctx,
      wresult:         assertion
    }));
  }

  function execute (postUrl, req, res, next) {
    var audience =  options.audience ||
                    req.query.wtrealm ||
                    req.query.wreply;

    if(!audience){
      return next(new Error('audience is required'));
    }

    audience = asResource(audience);

    var user = options.getUserFromRequest(req);
    if(!user) return res.send(401);

    var ctx = options.wctx || req.query.wctx;
    if (!options.jwt) {
      var profileMap = options.profileMapper(user);
      var claims = profileMap.getClaims(options);
      var ni = profileMap.getNameIdentifier(options);
      saml11.create({
        signatureAlgorithm:   options.signatureAlgorithm,
        digestAlgorithm:      options.digestAlgorithm,
        cert:                 options.cert,
        key:                  options.key,
        issuer:               asResource(options.issuer),
        lifetimeInSeconds:    options.lifetime || (60 * 60 * 8),
        audiences:            audience,
        attributes:           claims,
        nameIdentifier:       ni.nameIdentifier,
        nameIdentifierFormat: ni.nameIdentifierFormat,
        encryptionPublicKey:  options.encryptionPublicKey,
        encryptionCert:       options.encryptionCert
      }, function(err, assertion) {
        if (err) return next(err);
        var escapedWctx = utils.escape(utils.escape(ctx)); // we need an escaped value for RequestSecurityTokenResponse.Context
        var escapedAssertion = utils.escape(assertion); // we need an escaped value for RequestSecurityTokenResponse.Context
        assertion = '<t:RequestSecurityTokenResponse Context="'+ escapedWctx + '" xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust"><t:RequestedSecurityToken>' + escapedAssertion + '</t:RequestedSecurityToken></t:RequestSecurityTokenResponse>';

        return renderResponse(res, postUrl, ctx, assertion);
      });

    } else {
      jwt = jwt.sign(user, options.key.toString(), {
        expiresInMinutes: (options.lifetime || (60 * 60 * 8)) / 60,
        audience:         audience,
        issuer:           asResource(options.issuer),
        algorithm:        options.jwtAlgorithm || 'RS256'
      });

      return renderResponse(res, postUrl, ctx, jwt);
    }
  }

  return function (req, res, next) {
    options.getPostURL(req.query.wtrealm, req.query.wreply, req, function (err, postUrl) {
      if (err) return next(err);
      if (!postUrl) return res.send(400, 'postUrl is required');
      execute(postUrl, req, res, next);
    });
  };
};
<commit_msg>bug fixing<commit_after>var templates             = require('./templates');
var PassportProfileMapper = require('./claims/PassportProfileMapper');
var utils                 = require('./utils');
var saml11 = require('saml').Saml11;
var jwt                   = require('jsonwebtoken');

function asResource(res) {
  if(res.substr(0, 6) !== 'http:/' &&
      res.substr(0, 6) !== 'https:' &&
      res.substr(0, 4) !== 'urn:') {
    return 'urn:' + res;
  }
  return res;
}

/**
 * WSFederation middleware.
 *
 * This middleware creates a WSFed endpoint based on the user logged in identity.
 *
 * options:
 * - profileMapper(profile) a ProfileMapper implementation to convert a user profile to claims  (PassportProfile).
 * - getUserFromRequest(req) a function that given a request returns the user. By default req.user
 * - issuer string
 * - cert the public certificate
 * - key the private certificate to sign all tokens
 * - postUrl function (wtrealm, wreply, request, callback)
 *
 * @param  {[type]} options [description]
 * @return {[type]}         [description]
 */
module.exports = function(options) {
  options = options || {};
  options.profileMapper = options.profileMapper || PassportProfileMapper;
  options.getUserFromRequest = options.getUserFromRequest || function(req){ return req.user; };

  if(typeof options.getPostURL !== 'function') {
    throw new Error('getPostURL is required');
  }

  function renderResponse(res, postUrl, wctx, assertion) {
    res.set('Content-Type', 'text/html');
    res.send(templates.form({
      callback:        postUrl,
      wctx:            wctx,
      wresult:         assertion
    }));
  }

  function execute (postUrl, req, res, next) {
    var audience =  options.audience ||
                    req.query.wtrealm ||
                    req.query.wreply;

    if(!audience){
      return next(new Error('audience is required'));
    }

    audience = asResource(audience);

    var user = options.getUserFromRequest(req);
    if(!user) return res.send(401);

    var ctx = options.wctx || req.query.wctx;
    if (!options.jwt) {
      var profileMap = options.profileMapper(user);
      var claims = profileMap.getClaims(options);
      var ni = profileMap.getNameIdentifier(options);
      saml11.create({
        signatureAlgorithm:   options.signatureAlgorithm,
        digestAlgorithm:      options.digestAlgorithm,
        cert:                 options.cert,
        key:                  options.key,
        issuer:               asResource(options.issuer),
        lifetimeInSeconds:    options.lifetime || (60 * 60 * 8),
        audiences:            audience,
        attributes:           claims,
        nameIdentifier:       ni.nameIdentifier,
        nameIdentifierFormat: ni.nameIdentifierFormat,
        encryptionPublicKey:  options.encryptionPublicKey,
        encryptionCert:       options.encryptionCert
      }, function(err, assertion) {
        if (err) return next(err);
        var escapedWctx = utils.escape(utils.escape(ctx)); // we need an escaped value for RequestSecurityTokenResponse.Context
        var escapedAssertion = utils.escape(assertion); // we need an escaped value for RequestSecurityTokenResponse.Context
        assertion = '<t:RequestSecurityTokenResponse Context="'+ escapedWctx + '" xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust"><t:RequestedSecurityToken>' + escapedAssertion + '</t:RequestedSecurityToken></t:RequestSecurityTokenResponse>';

        return renderResponse(res, postUrl, ctx, assertion);
      });

    } else {
      var signed = jwt.sign(user, options.key.toString(), {
        expiresInMinutes: (options.lifetime || (60 * 60 * 8)) / 60,
        audience:         audience,
        issuer:           asResource(options.issuer),
        algorithm:        options.jwtAlgorithm || 'RS256'
      });

      return renderResponse(res, postUrl, ctx, signed);
    }
  }

  return function (req, res, next) {
    options.getPostURL(req.query.wtrealm, req.query.wreply, req, function (err, postUrl) {
      if (err) return next(err);
      if (!postUrl) return res.send(400, 'postUrl is required');
      execute(postUrl, req, res, next);
    });
  };
};
<|endoftext|>