<commit_before>/**
 * Status of page load.
 */

var pageLoaded = false;

/**
 * Inheritance.
 *
 * @param {Function} ctor a
 * @param {Function} ctor b
 * @api private
 */

exports.inherits = function inherits (a, b) {
  function c () { }
  c.prototype = b.prototype;
  a.prototype = new c;
};

/**
 * Object.keys
 */

exports.keys = Object.keys || function (obj) {
  var ret = [];
  var has = Object.prototype.hasOwnProperty;

  for (var i in obj) {
    if (has.call(obj, i)) {
      ret.push(i);
    }
  }

  return ret;
};

/**
 * Adds an event.
 *
 * @api private
 */

exports.on = function (element, event, fn, capture) {
  if (element.attachEvent) {
    element.attachEvent('on' + event, fn);
  } else if (element.addEventListener) {
    element.addEventListener(event, fn, capture);
  }
};

/**
 * Load utility.
 *
 * @api private
 */

exports.load = function (fn) {
  var global = exports.global();
  if (global.document && document.readyState === 'complete' || pageLoaded) {
    return fn();
  }

  exports.on(global, 'load', fn, false);
};

/**
 * Change the internal pageLoaded value.
 */

if ('undefined' != typeof window) {
  exports.load(function () {
    pageLoaded = true;
  });
}

/**
 * Defers a function to ensure a spinner is not displayed by the browser.
 *
 * @param {Function} fn
 * @api private
 */

exports.defer = function (fn) {
  if (!exports.ua.webkit || 'undefined' != typeof importScripts) {
    return fn();
  }

  exports.load(function () {
    setTimeout(fn, 100);
  });
};

/**
 * JSON parse.
 *
 * @see Based on jQuery#parseJSON (MIT) and JSON2
 * @api private
 */

var rvalidchars = /^[\],:{}\s]*$/;
var rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g;
var rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;
var rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g;
var rtrimLeft = /^\s+/;
var rtrimRight = /\s+$/;

exports.parseJSON = function (data) {
  var global = exports.global();

  if ('string' != typeof data || !data) {
    return null;
  }

  data = data.replace(rtrimLeft, '').replace(rtrimRight, '');

  // Attempt to parse using the native JSON parser first
  if (global.JSON && JSON.parse) {
    return JSON.parse(data);
  }

  if (rvalidchars.test(data.replace(rvalidescape, '@')
      .replace(rvalidtokens, ']')
      .replace(rvalidbraces, ''))) {
    return (new Function('return ' + data))();
  }
};

/**
 * UA / engines detection namespace.
 *
 * @namespace
 */

exports.ua = {};

/**
 * Whether the UA supports CORS for XHR.
 *
 * @api private
 */

exports.ua.hasCORS = 'undefined' != typeof XMLHttpRequest && (function () {
  var a;
  try {
    a = new XMLHttpRequest();
  } catch (e) {
    return false;
  }

  return a.withCredentials != undefined;
})();

/**
 * Detect webkit.
 *
 * @api private
 */

exports.ua.webkit = 'undefined' != typeof navigator &&
  /webkit/i.test(navigator.userAgent);

/**
 * Detect gecko.
 *
 * @api private
 */

exports.ua.gecko = 'undefined' != typeof navigator &&
  /gecko/i.test(navigator.userAgent);

/**
 * Detect android;
 */

exports.ua.android = 'undefined' != typeof navigator &&
  /android/i.test(navigator.userAgent);

/**
 * Detect iOS.
 */

exports.ua.ios = 'undefined' != typeof navigator &&
  /^(iPad|iPhone|iPod)$/.test(navigator.platform);
exports.ua.ios6 = exports.ua.ios && /OS 6_/.test(navigator.userAgent);

/**
 * XHR request helper.
 *
 * @param {Boolean} whether we need xdomain
 * @api private
 */

exports.request = function request (xdomain) {
  try {
    var _XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
    return new _XMLHttpRequest();
  } catch (e) {}

  if (xdomain && 'undefined' != typeof XDomainRequest && !exports.ua.hasCORS) {
    return new XDomainRequest();
  }

  // XMLHttpRequest can be disabled on IE
  try {
    if ('undefined' != typeof XMLHttpRequest && (!xdomain || exports.ua.hasCORS)) {
      return new XMLHttpRequest();
    }
  } catch (e) { }

  if (!xdomain) {
    try {
      return new ActiveXObject('Microsoft.XMLHTTP');
    } catch(e) { }
  }
};

/**
 * Parses an URI
 *
 * @author Steven Levithan <stevenlevithan.com> (MIT license)
 * @api private
 */

var re = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/;

var parts = [
    'source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host'
  , 'port', 'relative', 'path', 'directory', 'file', 'query', 'anchor'
];

exports.parseUri = function (str) {
  var m = re.exec(str || '')
    , uri = {}
    , i = 14;

  while (i--) {
    uri[parts[i]] = m[i] || '';
  }

  return uri;
};

/**
 * Compiles a querystring
 *
 * @param {Object}
 * @api private
 */

exports.qs = function (obj) {
  var str = '';

  for (var i in obj) {
    if (obj.hasOwnProperty(i)) {
      if (str.length) str += '&';
      str += encodeURIComponent(i) + '=' + encodeURIComponent(obj[i]);
    }
  }

  return str;
};

/**
 * Parses a simple querystring.
 *
 * @param {String} qs
 * @api private
 */

exports.qsParse = function(qs){
  var qry = {};
  var pairs = qs.split('&');
  for (var i = 0, l = pairs.length; i < l; i++) {
    var pair = pairs[i].split('=');
    qry[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);
  }
  return qry;
};
<commit_msg>util: use "component/global"<commit_after>
var global = require('global')();

/**
 * Status of page load.
 */

var pageLoaded = false;

/**
 * Inheritance.
 *
 * @param {Function} ctor a
 * @param {Function} ctor b
 * @api private
 */

exports.inherits = function inherits (a, b) {
  function c () { }
  c.prototype = b.prototype;
  a.prototype = new c;
};

/**
 * Object.keys
 */

exports.keys = Object.keys || function (obj) {
  var ret = [];
  var has = Object.prototype.hasOwnProperty;

  for (var i in obj) {
    if (has.call(obj, i)) {
      ret.push(i);
    }
  }

  return ret;
};

/**
 * Adds an event.
 *
 * @api private
 */

exports.on = function (element, event, fn, capture) {
  if (element.attachEvent) {
    element.attachEvent('on' + event, fn);
  } else if (element.addEventListener) {
    element.addEventListener(event, fn, capture);
  }
};

/**
 * Load utility.
 *
 * @api private
 */

exports.load = function (fn) {
  if (global.document && document.readyState === 'complete' || pageLoaded) {
    return fn();
  }

  exports.on(global, 'load', fn, false);
};

/**
 * Change the internal pageLoaded value.
 */

if ('undefined' != typeof window) {
  exports.load(function () {
    pageLoaded = true;
  });
}

/**
 * Defers a function to ensure a spinner is not displayed by the browser.
 *
 * @param {Function} fn
 * @api private
 */

exports.defer = function (fn) {
  if (!exports.ua.webkit || 'undefined' != typeof importScripts) {
    return fn();
  }

  exports.load(function () {
    setTimeout(fn, 100);
  });
};

/**
 * JSON parse.
 *
 * @see Based on jQuery#parseJSON (MIT) and JSON2
 * @api private
 */

var rvalidchars = /^[\],:{}\s]*$/;
var rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g;
var rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;
var rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g;
var rtrimLeft = /^\s+/;
var rtrimRight = /\s+$/;

exports.parseJSON = function (data) {
  if ('string' != typeof data || !data) {
    return null;
  }

  data = data.replace(rtrimLeft, '').replace(rtrimRight, '');

  // Attempt to parse using the native JSON parser first
  if (global.JSON && JSON.parse) {
    return JSON.parse(data);
  }

  if (rvalidchars.test(data.replace(rvalidescape, '@')
      .replace(rvalidtokens, ']')
      .replace(rvalidbraces, ''))) {
    return (new Function('return ' + data))();
  }
};

/**
 * UA / engines detection namespace.
 *
 * @namespace
 */

exports.ua = {};

/**
 * Whether the UA supports CORS for XHR.
 *
 * @api private
 */

exports.ua.hasCORS = 'undefined' != typeof XMLHttpRequest && (function () {
  var a;
  try {
    a = new XMLHttpRequest();
  } catch (e) {
    return false;
  }

  return a.withCredentials != undefined;
})();

/**
 * Detect webkit.
 *
 * @api private
 */

exports.ua.webkit = 'undefined' != typeof navigator &&
  /webkit/i.test(navigator.userAgent);

/**
 * Detect gecko.
 *
 * @api private
 */

exports.ua.gecko = 'undefined' != typeof navigator &&
  /gecko/i.test(navigator.userAgent);

/**
 * Detect android;
 */

exports.ua.android = 'undefined' != typeof navigator &&
  /android/i.test(navigator.userAgent);

/**
 * Detect iOS.
 */

exports.ua.ios = 'undefined' != typeof navigator &&
  /^(iPad|iPhone|iPod)$/.test(navigator.platform);
exports.ua.ios6 = exports.ua.ios && /OS 6_/.test(navigator.userAgent);

/**
 * XHR request helper.
 *
 * @param {Boolean} whether we need xdomain
 * @api private
 */

exports.request = function request (xdomain) {
  try {
    var _XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
    return new _XMLHttpRequest();
  } catch (e) {}

  if (xdomain && 'undefined' != typeof XDomainRequest && !exports.ua.hasCORS) {
    return new XDomainRequest();
  }

  // XMLHttpRequest can be disabled on IE
  try {
    if ('undefined' != typeof XMLHttpRequest && (!xdomain || exports.ua.hasCORS)) {
      return new XMLHttpRequest();
    }
  } catch (e) { }

  if (!xdomain) {
    try {
      return new ActiveXObject('Microsoft.XMLHTTP');
    } catch(e) { }
  }
};

/**
 * Parses an URI
 *
 * @author Steven Levithan <stevenlevithan.com> (MIT license)
 * @api private
 */

var re = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/;

var parts = [
    'source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host'
  , 'port', 'relative', 'path', 'directory', 'file', 'query', 'anchor'
];

exports.parseUri = function (str) {
  var m = re.exec(str || '')
    , uri = {}
    , i = 14;

  while (i--) {
    uri[parts[i]] = m[i] || '';
  }

  return uri;
};

/**
 * Compiles a querystring
 *
 * @param {Object}
 * @api private
 */

exports.qs = function (obj) {
  var str = '';

  for (var i in obj) {
    if (obj.hasOwnProperty(i)) {
      if (str.length) str += '&';
      str += encodeURIComponent(i) + '=' + encodeURIComponent(obj[i]);
    }
  }

  return str;
};

/**
 * Parses a simple querystring.
 *
 * @param {String} qs
 * @api private
 */

exports.qsParse = function(qs){
  var qry = {};
  var pairs = qs.split('&');
  for (var i = 0, l = pairs.length; i < l; i++) {
    var pair = pairs[i].split('=');
    qry[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);
  }
  return qry;
};
<|endoftext|>


<commit_before>var fs = require('fs'),
    path = require('path'),
    _ = require('underscore'),
    Step = require('step');

var env = process.env.NODE_ENV || 'development';

// Recursive rm.
function rm(filepath, callback) {
    var killswitch = false;
    fs.stat(filepath, function(err, stat) {
        if (err) return callback(err);
        if (stat.isFile()) return fs.unlink(filepath, callback);
        if (!stat.isDirectory()) return callback(new Error('Unrecognized file.'));
        Step(function() {
            fs.readdir(filepath, this);
        },
        function(err, files) {
            if (err) throw err;
            if (files.length === 0) return this(null, []);
            var group = this.group();
            _(files).each(function(file) {
                rm(path.join(filepath, file), group());
            });
        },
        function(err) {
            if (err) return callback(err);
            fs.rmdir(filepath, callback);
        });
    });
}

// Like fs.symlink except that it will overwrite stale symlinks at the
// given path if it exists.
function forcelink(src, dest, options, callback) {
    if (!options || !options.cache) throw new Error('options.cache not defined!');
    if (!callback) throw new Error('callback not defined!');
    // uses relative path if linking to cache dir
    src = path.relative(options.cache, dest).slice(0, 2) !== '..' ? path.relative(path.dirname(dest), src) : src;
    fs.lstat(dest, function(err, stat) {
        // Error.
        if (err && err.code !== 'ENOENT')
            return callback(err);

        // Path does not exist. Symlink.
        if (err && err.code === 'ENOENT') {
            if (env == 'development') console.log("[millstone] linking '" + dest + "' -> '"  + src + "'");
            return fs.symlink(src, dest, callback);
        }

        // Path exists and is not a symlink. Do nothing.
        if (!stat.isSymbolicLink()) return callback();

        // Path exists and is a symlink. Check existing link path and update
        // if necessary.
        fs.readlink(dest, function(err, old) {
            if (err) return callback(err);
            if (old === src) return callback();
            fs.unlink(dest, function(err) {
                if (err) return callback(err);
                if (env == 'development') console.log("[millstone] re-linking '" + dest + "' -> '"  + src + "'");
                fs.symlink(src, dest, callback);
            });
        });
    });
}

function copyStream(src,dest,callback) {
    var src_stream = fs.createReadStream(src);
    src_stream.on('error', function(err) {
        return callback(err);
    });
    var dest_stream = fs.createWriteStream(dest);
    dest_stream.on('error', function(err) {
        return callback(err);
    });
    src_stream.on('end', function() {
        if (env == 'development') console.log("[millstone] finished copying '" + src + "' to '"  + dest + "'");
        return callback(null);
    });
    src_stream.pipe(dest_stream);
}

function copy(src, dest, options, callback) {
    if (!options) throw new Error('options not defined!');
    if (!callback) throw new Error('callback not defined!');
    fs.lstat(dest, function(err, dest_stat) {
        // Error.
        if (err && err.code !== 'ENOENT'){
            return callback(err);
        }

        // Dest path does not exist. Copy.
        if (err && err.code === 'ENOENT') {
            if (env == 'development') console.log("[millstone] attempting to copy '" + src + "' to '"  + dest + "'");
            return copyStream(src,dest,callback);
        }

        // Path exists and is a symlink. Do nothing.
        if (dest_stat.isSymbolicLink()) {
            return callback();
        }

        // Dest path exists and is a file. Check if it needs updating
        fs.lstat(src, function(err,src_stat) {
            // Error.
            if (err) {
                return callback(err);
            }
            // NOTE: we intentially do not compare the STAT exactly
            // because some windows users will be used to editing files
            // after they are copied. In future releases we should consider
            // simply doing if (src_stat != dest_stat)
            // check size to dodge potentially corrupt data
            // https://github.com/mapbox/tilemill/issues/1674
            if ((src_stat.size != dest_stat.size && src_stat.mtime < dest_stat.mtime) || src_stat.mtime > dest_stat.mtime) {
                if (env == 'development') console.log("[millstone] attempting to re-copy '" + src + "' to '"  + dest + "'");
                return copyStream(src,dest,callback);
            } else {
                return callback();
            }
        });
    });
}

function processSHP(src, dest, fn, options, callback) {
    if (!options) throw new Error('options not defined!');
    if (!fn) throw new Error('link function not defined!');
    if (!callback) throw new Error('callback not defined!');
    var basename = path.basename(src, path.extname(src)),
        srcdir = path.dirname(src),
        destdir = path.dirname(dest);

    // Group multiple calls
    var remaining,
        err;
    function done(err) {
        remaining --;
        if (!remaining) callback(err);
    }

    function forcemkdir(dir, callback) {
        fs.lstat(dir, function(err, stat) {
            if (err && err.code !== 'ENOENT') {
                return callback(err)
            } else if (!err && stat.isSymbolicLink()) {
                return fs.unlink(dir, function(err) {
                    if (err) return callback(err);
                    fs.mkdir(dir, 0755, callback);
                });

            } else {
                return fs.mkdir(dir, 0755, callback);
            }
        });
    }

    function processFiltered(err, files) {
        if (err) return callback(err);

        files = files.filter(function(f) {
            return path.basename(f, path.extname(f)) === basename;
        });

        remaining = files.length;

        files.forEach(function(f) {
            fn(path.join(srcdir, f), path.join(destdir, f), options, done);
        });
    }

    forcemkdir(destdir, function() {
        fs.readdir(srcdir, processFiltered);
    });
}

module.exports = {
    forcelink: forcelink,
    rm: rm,
    copy: copy,
    processSHP: processSHP
};
<commit_msg>more debug output for when symlinking or copying is shortcut<commit_after>var fs = require('fs'),
    path = require('path'),
    _ = require('underscore'),
    Step = require('step');

var env = process.env.NODE_ENV || 'development';

// Recursive rm.
function rm(filepath, callback) {
    var killswitch = false;
    fs.stat(filepath, function(err, stat) {
        if (err) return callback(err);
        if (stat.isFile()) return fs.unlink(filepath, callback);
        if (!stat.isDirectory()) return callback(new Error('Unrecognized file.'));
        Step(function() {
            fs.readdir(filepath, this);
        },
        function(err, files) {
            if (err) throw err;
            if (files.length === 0) return this(null, []);
            var group = this.group();
            _(files).each(function(file) {
                rm(path.join(filepath, file), group());
            });
        },
        function(err) {
            if (err) return callback(err);
            fs.rmdir(filepath, callback);
        });
    });
}

// Like fs.symlink except that it will overwrite stale symlinks at the
// given path if it exists.
function forcelink(src, dest, options, callback) {
    if (!options || !options.cache) throw new Error('options.cache not defined!');
    if (!callback) throw new Error('callback not defined!');
    // uses relative path if linking to cache dir
    src = path.relative(options.cache, dest).slice(0, 2) !== '..' ? path.relative(path.dirname(dest), src) : src;
    fs.lstat(dest, function(err, stat) {
        // Error.
        if (err && err.code !== 'ENOENT')
            return callback(err);

        // Path does not exist. Symlink.
        if (err && err.code === 'ENOENT') {
            if (env == 'development') console.log("[millstone] linking '" + dest + "' -> '"  + src + "'");
            return fs.symlink(src, dest, callback);
        }

        // Path exists and is not a symlink. Do nothing.
        if (!stat.isSymbolicLink()) {
            if (env == 'development') console.log("[millstone] skipping copying '" + src + "' because '"  + dest + " is an existing file");
            return callback();
        }

        // Path exists and is a symlink. Check existing link path and update if necessary.
        fs.readlink(dest, function(err, old) {
            if (err) return callback(err);
            if (old === src) return callback();
            fs.unlink(dest, function(err) {
                if (err) return callback(err);
                if (env == 'development') console.log("[millstone] re-linking '" + dest + "' -> '"  + src + "'");
                fs.symlink(src, dest, callback);
            });
        });
    });
}

function copyStream(src,dest,callback) {
    var src_stream = fs.createReadStream(src);
    src_stream.on('error', function(err) {
        return callback(err);
    });
    var dest_stream = fs.createWriteStream(dest);
    dest_stream.on('error', function(err) {
        return callback(err);
    });
    src_stream.on('end', function() {
        if (env == 'development') console.log("[millstone] finished copying '" + src + "' to '"  + dest + "'");
        return callback(null);
    });
    src_stream.pipe(dest_stream);
}

function copy(src, dest, options, callback) {
    if (!options) throw new Error('options not defined!');
    if (!callback) throw new Error('callback not defined!');
    fs.lstat(dest, function(err, dest_stat) {
        // Error.
        if (err && err.code !== 'ENOENT'){
            return callback(err);
        }

        // Dest path does not exist. Copy.
        if (err && err.code === 'ENOENT') {
            if (env == 'development') console.log("[millstone] attempting to copy '" + src + "' to '"  + dest + "'");
            return copyStream(src,dest,callback);
        }

        // Path exists and is a symlink. Do nothing.
        if (dest_stat.isSymbolicLink()) {
            if (env == 'development') console.log("[millstone] skipping copying '" + src + "' because '"  + dest + " is an existing symlink");
            return callback();
        }

        // Dest path exists and is a file. Check if it needs updating
        fs.lstat(src, function(err,src_stat) {
            // Error.
            if (err) {
                return callback(err);
            }
            // NOTE: we intentially do not compare the STAT exactly
            // because some windows users will be used to editing files
            // after they are copied. In future releases we should consider
            // simply doing if (src_stat != dest_stat)
            // check size to dodge potentially corrupt data
            // https://github.com/mapbox/tilemill/issues/1674
            if ((src_stat.size != dest_stat.size && src_stat.mtime < dest_stat.mtime) || src_stat.mtime > dest_stat.mtime) {
                if (env == 'development') console.log("[millstone] attempting to re-copy '" + src + "' to '"  + dest + "'");
                return copyStream(src,dest,callback);
            } else {
                return callback();
            }
        });
    });
}

function processSHP(src, dest, fn, options, callback) {
    if (!options) throw new Error('options not defined!');
    if (!fn) throw new Error('link function not defined!');
    if (!callback) throw new Error('callback not defined!');
    var basename = path.basename(src, path.extname(src)),
        srcdir = path.dirname(src),
        destdir = path.dirname(dest);

    // Group multiple calls
    var remaining,
        err;
    function done(err) {
        remaining --;
        if (!remaining) callback(err);
    }

    function forcemkdir(dir, callback) {
        fs.lstat(dir, function(err, stat) {
            if (err && err.code !== 'ENOENT') {
                return callback(err)
            } else if (!err && stat.isSymbolicLink()) {
                return fs.unlink(dir, function(err) {
                    if (err) return callback(err);
                    fs.mkdir(dir, 0755, callback);
                });

            } else {
                return fs.mkdir(dir, 0755, callback);
            }
        });
    }

    function processFiltered(err, files) {
        if (err) return callback(err);

        files = files.filter(function(f) {
            return path.basename(f, path.extname(f)) === basename;
        });

        remaining = files.length;

        files.forEach(function(f) {
            fn(path.join(srcdir, f), path.join(destdir, f), options, done);
        });
    }

    forcemkdir(destdir, function() {
        fs.readdir(srcdir, processFiltered);
    });
}

module.exports = {
    forcelink: forcelink,
    rm: rm,
    copy: copy,
    processSHP: processSHP
};
<|endoftext|>


<commit_before>import { AbstractStackedCartesianChart } from '../../base';
import { wrapSVGText } from 'vizart-core'
import { CoronaOptions } from './Corona-Options';

import createCartesianStackedOpt from '../../options/createCartesianStackedOpt';

import { Stacks } from '../../data';

import { scaleLinear } from 'd3-scale';
import { interpolateArray } from 'd3-interpolate';
import { timer } from 'd3-timer';
import { mouse } from 'd3-selection';
import { easeCubic } from 'd3-ease';

import drawCanvas from './draw-canvas';
import applyVoronoi from '../../canvas/voronoi/apply';
import highlight from './highlight';
import transparentColor from "./get-transparent-color";
import cloneDeep from 'lodash-es/cloneDeep';

class Corona extends AbstractStackedCartesianChart {
    constructor(canvasId, _userOptions) {
        super(canvasId, _userOptions);
    }

    _animate() {
        const outerRadius = Math.min(this._options.chart.innerWidth / 2, this._options.chart.innerHeight / 2) - this._options.plots.outerRadiusMargin;
        const innerRadius = outerRadius * this._options.plots.innerRadiusRatio;
        const radiusScale = scaleLinear()
            .domain([this._getMetric().scale(this._data.minY), this._getMetric().scale(this._data.maxY)])
            .range([innerRadius, outerRadius]);

        const rawRadiusScale = radiusScale.copy().domain([this._data.minY, this._data.maxY]);

        const Duration = this._options.animation.duration.update;

        const initialState = this.previousState
            ? this.previousState
            : this._data.nested.map(d => {
                return {
                    key: d.key,
                    c: this._c(d),
                    s: d.key,
                    alpha: 0,
                    strokeAlpha: this._options.plots.strokeOpacity,
                    values: d.values.map((e, i) => {
                        return {
                            key: d.key,
                            angle: Math.PI * 2 * i / d.values.length,
                            r: innerRadius,
                            r0: innerRadius,
                            r1: innerRadius,
                            data: e.data
                        }
                    })
                }
            });

        const finalState = this._data.nested.map(d => {
            return {
                key: d.key,
                c: this._c(d),
                s: d.key,
                alpha: this._options.plots.areaOpacity,
                strokeAlpha: this._options.plots.strokeOpacity,
                values: d.values.map((e, i) => {
                    return {
                        key: d.key,
                        angle: Math.PI * 2 * i / d.values.length,
                        r: radiusScale(e.y),
                        r0: rawRadiusScale(e.y0),
                        r1: rawRadiusScale(e.y1),
                        data: e.data
                    }
                })
            }
        });
        // cache finalState as the initial state of next animation call
        this.previousState = finalState;

        const interpolateParticles = interpolateArray(initialState, finalState);

        let that = this;
        const ctx = that._frontContext;
        const opt = that._options;

        const batchRendering = timer((elapsed) => {
            const t = Math.min(1, easeCubic(elapsed / Duration));

            drawCanvas(ctx,
                interpolateParticles(t),
                opt,
                innerRadius,
                outerRadius,
                this._data.minY,
                this._data.maxY);

            if (t === 1) {
                batchRendering.stop();

                that._voronoi = applyVoronoi(ctx, opt, finalState.reduce((acc, p)=>{
                        acc = acc.concat(p.values.map(d=>{
                            return {
                                s: p.key,
                                label: that._getDimensionVal(d.data),
                                metric: d.data[p.key],
                                x: d.r * Math.sin(d.angle) + opt.chart.width / 2,
                                y: opt.chart.height - (d.r * Math.cos(d.angle) + opt.chart.height / 2),
                                c: p.c,
                                d: d,
                                data: d.data
                            }
                        }));
                        return acc;
                    }, []));

                // that._quadtree = applyQuadtree(that._frontContext,
                //     that._options, finalState);

                /**
                 * callback for when the mouse moves across the overlay
                 */
                function mouseMoveHandler() {
                    // get the current mouse position
                    const [mx, my] = mouse(this);
                    const QuadtreeRadius = 100;
                    // use the new diagram.find() function to find the Voronoi site
                    // closest to the mouse, limited by max distance voronoiRadius
                    const closest = that._voronoi.find(mx, my, QuadtreeRadius);
                    if (closest) {
                        const fadeOpacity = 0.1;

                        const optCopy = cloneDeep(opt);
                        optCopy.plots.levelColor = transparentColor(optCopy.plots.levelColor, fadeOpacity);
                        optCopy.plots.strokeOpacity = 0;

                        drawCanvas(ctx,
                            finalState.map(d=>{
                                const p = d;
                                p.alpha = d.key === closest.data.s
                                    ? 0.4
                                    : fadeOpacity;

                                p.strokeAlpha = d.key === closest.data.s
                                    ? 1
                                    : 0;

                                return p;
                            }),
                            optCopy,
                            innerRadius,
                            outerRadius,
                            that._data.minY,
                            that._data.maxY);

                        highlight(ctx, opt, closest.data);
                    } else {
                        drawCanvas(ctx,
                            finalState,
                            that._options,
                            innerRadius,
                            outerRadius,
                            that._data.minY,
                            that._data.maxY);
                    }
                }

                function mouseOutHandler() {
                    drawCanvas(ctx,
                        finalState,
                        opt,
                        innerRadius,
                        outerRadius,
                        that._data.minY,
                        that._data.maxY);
                }

                that._frontCanvas.on('mousemove', mouseMoveHandler);
                that._frontCanvas.on('mouseout', mouseOutHandler);

                that._listeners.call('rendered');
            }
        });

    }

    stackLayout() {
        this._options.plots.stackLayout = true;
        this._options.plots.stackMethod = Stacks.Zero;

        this.update();
    };

    expandLayout() {
        this._options.plots.stackLayout = true;
        this._options.plots.stackMethod = Stacks.Expand;

        this.update();
    };

    groupedLayout() {
        this._options.plots.stackLayout = false;

        this.update();
    };

    createOptions(_userOpt) {
        return createCartesianStackedOpt(CoronaOptions, _userOpt);
    };
}

export default Corona;<commit_msg>cleanup<commit_after>import { scaleLinear } from 'd3-scale';
import { interpolateArray } from 'd3-interpolate';
import { timer } from 'd3-timer';
import { mouse } from 'd3-selection';
import { easeCubic } from 'd3-ease';
import cloneDeep from 'lodash-es/cloneDeep';

import { AbstractStackedCartesianChart } from '../../base';
import { CoronaOptions } from './Corona-Options';
import createCartesianStackedOpt from '../../options/createCartesianStackedOpt';
import { Stacks } from '../../data';
import applyVoronoi from '../../canvas/voronoi/apply';

import drawCanvas from './draw-canvas';
import highlight from './highlight';
import transparentColor from "./get-transparent-color";

class Corona extends AbstractStackedCartesianChart {
    constructor(canvasId, _userOptions) {
        super(canvasId, _userOptions);
    }

    _animate() {
        const outerRadius = Math.min(this._options.chart.innerWidth / 2, this._options.chart.innerHeight / 2) - this._options.plots.outerRadiusMargin;
        const innerRadius = outerRadius * this._options.plots.innerRadiusRatio;
        const radiusScale = scaleLinear()
            .domain([this._getMetric().scale(this._data.minY), this._getMetric().scale(this._data.maxY)])
            .range([innerRadius, outerRadius]);

        const rawRadiusScale = radiusScale.copy().domain([this._data.minY, this._data.maxY]);

        const Duration = this._options.animation.duration.update;

        const initialState = this.previousState
            ? this.previousState
            : this._data.nested.map(d => {
                return {
                    key: d.key,
                    c: this._c(d),
                    s: d.key,
                    alpha: 0,
                    strokeAlpha: this._options.plots.strokeOpacity,
                    values: d.values.map((e, i) => {
                        return {
                            key: d.key,
                            angle: Math.PI * 2 * i / d.values.length,
                            r: innerRadius,
                            r0: innerRadius,
                            r1: innerRadius,
                            data: e.data
                        }
                    })
                }
            });

        const finalState = this._data.nested.map(d => {
            return {
                key: d.key,
                c: this._c(d),
                s: d.key,
                alpha: this._options.plots.areaOpacity,
                strokeAlpha: this._options.plots.strokeOpacity,
                values: d.values.map((e, i) => {
                    return {
                        key: d.key,
                        angle: Math.PI * 2 * i / d.values.length,
                        r: radiusScale(e.y),
                        r0: rawRadiusScale(e.y0),
                        r1: rawRadiusScale(e.y1),
                        data: e.data
                    }
                })
            }
        });
        // cache finalState as the initial state of next animation call
        this.previousState = finalState;

        const interpolateParticles = interpolateArray(initialState, finalState);

        let that = this;
        const ctx = that._frontContext;
        const opt = that._options;

        const batchRendering = timer((elapsed) => {
            const t = Math.min(1, easeCubic(elapsed / Duration));

            drawCanvas(ctx,
                interpolateParticles(t),
                opt,
                innerRadius,
                outerRadius,
                this._data.minY,
                this._data.maxY);

            if (t === 1) {
                batchRendering.stop();

                that._voronoi = applyVoronoi(ctx, opt, finalState.reduce((acc, p)=>{
                        acc = acc.concat(p.values.map(d=>{
                            return {
                                s: p.key,
                                label: that._getDimensionVal(d.data),
                                metric: d.data[p.key],
                                x: d.r * Math.sin(d.angle) + opt.chart.width / 2,
                                y: opt.chart.height - (d.r * Math.cos(d.angle) + opt.chart.height / 2),
                                c: p.c,
                                d: d,
                                data: d.data
                            }
                        }));
                        return acc;
                    }, []));

                // that._quadtree = applyQuadtree(that._frontContext,
                //     that._options, finalState);

                /**
                 * callback for when the mouse moves across the overlay
                 */
                function mouseMoveHandler() {
                    // get the current mouse position
                    const [mx, my] = mouse(this);
                    const QuadtreeRadius = 100;
                    // use the new diagram.find() function to find the Voronoi site
                    // closest to the mouse, limited by max distance voronoiRadius
                    const closest = that._voronoi.find(mx, my, QuadtreeRadius);
                    if (closest) {
                        const fadeOpacity = 0.1;

                        const optCopy = cloneDeep(opt);
                        optCopy.plots.levelColor = transparentColor(optCopy.plots.levelColor, fadeOpacity);
                        optCopy.plots.strokeOpacity = 0;

                        drawCanvas(ctx,
                            finalState.map(d=>{
                                const p = d;
                                p.alpha = d.key === closest.data.s
                                    ? 0.4
                                    : fadeOpacity;

                                p.strokeAlpha = d.key === closest.data.s
                                    ? 1
                                    : 0;

                                return p;
                            }),
                            optCopy,
                            innerRadius,
                            outerRadius,
                            that._data.minY,
                            that._data.maxY);

                        highlight(ctx, opt, closest.data);
                    } else {
                        drawCanvas(ctx,
                            finalState,
                            that._options,
                            innerRadius,
                            outerRadius,
                            that._data.minY,
                            that._data.maxY);
                    }
                }

                function mouseOutHandler() {
                    drawCanvas(ctx,
                        finalState,
                        opt,
                        innerRadius,
                        outerRadius,
                        that._data.minY,
                        that._data.maxY);
                }

                that._frontCanvas.on('mousemove', mouseMoveHandler);
                that._frontCanvas.on('mouseout', mouseOutHandler);

                that._listeners.call('rendered');
            }
        });

    }

    stackLayout() {
        this._options.plots.stackLayout = true;
        this._options.plots.stackMethod = Stacks.Zero;

        this.update();
    };

    expandLayout() {
        this._options.plots.stackLayout = true;
        this._options.plots.stackMethod = Stacks.Expand;

        this.update();
    };

    groupedLayout() {
        this._options.plots.stackLayout = false;

        this.update();
    };

    createOptions(_userOpt) {
        return createCartesianStackedOpt(CoronaOptions, _userOpt);
    };
}

export default Corona;<|endoftext|>


<commit_before>import path from 'path';
import easydate from 'easydate';
import fsWriteStreamAtomic from 'fs-write-stream-atomic';
import getRes from 'get-res';
import logSymbols from 'log-symbols';
import mem from 'mem';
import mkdirp from 'mkdirp';
import rimraf from 'rimraf';
import screenshotStream from 'screenshot-stream';
import viewportList from 'viewport-list';
import protocolify from 'protocolify';
import arrayUniq from 'array-uniq';
import filenamifyUrl from 'filenamify-url';
import template from 'lodash.template';
import pify from 'pify';
import plur from 'plur';

const getResMem = mem(getRes);
const viewportListMem = mem(viewportList);

/**
 * Fetch ten most popular resolutions
 *
 * @param {String} url
 * @param {Object} options
 * @api private
 */

export async function resolution(url, options) {
	for (const item of await getResMem()) {
		this.sizes.push(item.item);
		this.items.push(this.create(url, item.item, options));
	}
}

/**
 * Fetch keywords
 *
 * @param {Object} obj
 * @param {Object} options
 */

export async function viewport(obj, options) {
	for (const item of await viewportListMem(obj.keywords)) {
		this.sizes.push(item.size);
		obj.sizes.push(item.size);
	}

	for (const size of arrayUniq(obj.sizes)) {
		this.items.push(this.create(obj.url, size, options));
	}
}

/**
 * Save an array of streams to files
 *
 * @param {Array} streams
 * @api private
 */

export async function save(streams) {
	const files = [];

	async function end() {
		return await Promise.all(files.map(file => pify(rimraf)(file)));
	}

	process.on('SIGINT', async () => process.exit(await end()));

	return await Promise.all(streams.map(stream =>
		new Promise(async (resolve, reject) => {
			await pify(mkdirp)(this.dest());

			const dest = path.join(this.dest(), stream.filename);
			const write = fsWriteStreamAtomic(dest);

			files.push(write.__atomicTmp);

			stream.on('warn', this.emit.bind(this, 'warn'));
			stream.on('error', err => end().then(reject(err)));

			write.on('finish', resolve);
			write.on('error', err => end().then(reject(err)));

			stream.pipe(write);
		})
	));
}

/**
 * Create a pageres stream
 *
 * @param {String} uri
 * @param {String} size
 * @param {Object} options
 * @api private
 */

export function create(uri, size, options) {
	const sizes = size.split('x');
	const stream = screenshotStream(protocolify(uri), size, options);
	const filename = template(`${options.filename}.${options.format}`);

	if (path.isAbsolute(uri)) {
		uri = path.basename(uri);
	}

	stream.filename = filename({
		crop: options.crop ? '-cropped' : '',
		date: easydate('Y-M-d'),
		time: easydate('h-m-s'),
		size,
		width: sizes[0],
		height: sizes[1],
		url: filenamifyUrl(uri)
	});

	return stream;
}

/**
 * Success message
 *
 * @api private
 */

export function successMessage() {
	const stats = this.stats;
	const {screenshots, sizes, urls} = stats;
	const words = {
		screenshots: plur('screenshot', screenshots),
		sizes: plur('size', sizes),
		urls: plur('url', urls)
	};

	console.log(`\n${logSymbols.success} Generated ${screenshots} ${words.screenshots} from ${urls} ${words.urls} and ${sizes} ${words.sizes}`);
}
<commit_msg>fix lint issue<commit_after>import path from 'path';
import easydate from 'easydate';
import fsWriteStreamAtomic from 'fs-write-stream-atomic';
import getRes from 'get-res';
import logSymbols from 'log-symbols';
import mem from 'mem';
import mkdirp from 'mkdirp';
import rimraf from 'rimraf';
import screenshotStream from 'screenshot-stream';
import viewportList from 'viewport-list';
import protocolify from 'protocolify';
import arrayUniq from 'array-uniq';
import filenamifyUrl from 'filenamify-url';
import template from 'lodash.template';
import pify from 'pify';
import plur from 'plur';

const getResMem = mem(getRes);
const viewportListMem = mem(viewportList);

/**
 * Fetch ten most popular resolutions
 *
 * @param {String} url
 * @param {Object} options
 * @api private
 */

export async function resolution(url, options) {
	for (const item of await getResMem()) {
		this.sizes.push(item.item);
		this.items.push(this.create(url, item.item, options));
	}
}

/**
 * Fetch keywords
 *
 * @param {Object} obj
 * @param {Object} options
 */

export async function viewport(obj, options) {
	for (const item of await viewportListMem(obj.keywords)) {
		this.sizes.push(item.size);
		obj.sizes.push(item.size);
	}

	for (const size of arrayUniq(obj.sizes)) {
		this.items.push(this.create(obj.url, size, options));
	}
}

/**
 * Save an array of streams to files
 *
 * @param {Array} streams
 * @api private
 */

export async function save(streams) {
	const files = [];

	async function end() {
		return await Promise.all(files.map(file => pify(rimraf)(file)));
	}

	process.on('SIGINT', async () => process.exit(await end())); // eslint-disable-line

	return await Promise.all(streams.map(stream =>
		new Promise(async (resolve, reject) => {
			await pify(mkdirp)(this.dest());

			const dest = path.join(this.dest(), stream.filename);
			const write = fsWriteStreamAtomic(dest);

			files.push(write.__atomicTmp);

			stream.on('warn', this.emit.bind(this, 'warn'));
			stream.on('error', err => end().then(reject(err)));

			write.on('finish', resolve);
			write.on('error', err => end().then(reject(err)));

			stream.pipe(write);
		})
	));
}

/**
 * Create a pageres stream
 *
 * @param {String} uri
 * @param {String} size
 * @param {Object} options
 * @api private
 */

export function create(uri, size, options) {
	const sizes = size.split('x');
	const stream = screenshotStream(protocolify(uri), size, options);
	const filename = template(`${options.filename}.${options.format}`);

	if (path.isAbsolute(uri)) {
		uri = path.basename(uri);
	}

	stream.filename = filename({
		crop: options.crop ? '-cropped' : '',
		date: easydate('Y-M-d'),
		time: easydate('h-m-s'),
		size,
		width: sizes[0],
		height: sizes[1],
		url: filenamifyUrl(uri)
	});

	return stream;
}

/**
 * Success message
 *
 * @api private
 */

export function successMessage() {
	const stats = this.stats;
	const {screenshots, sizes, urls} = stats;
	const words = {
		screenshots: plur('screenshot', screenshots),
		sizes: plur('size', sizes),
		urls: plur('url', urls)
	};

	console.log(`\n${logSymbols.success} Generated ${screenshots} ${words.screenshots} from ${urls} ${words.urls} and ${sizes} ${words.sizes}`);
}
<|endoftext|>


<commit_before>'use strict';
const fs = require('fs');

const capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1);

module.exports = {
    stat: (path) => new Promise((fulfill, rej) => fs.stat(path, (er, data) => er ? rej(er) : fulfill(data))),

    applyPlaceholders(str, dirname, filename) {
        if (!str || !str.length) {
            return str;
        }

        return str
        .split('[dir]').join(dirname)
        .split('[Dir]').join(capitalize(dirname))
        .split('[file]').join(filename)
        .split('[File]').join(capitalize(filename));
    }
};
<commit_msg>use tabs<commit_after>'use strict';
const fs = require('fs');

const capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1);

module.exports = {
	stat: (path) => new Promise((fulfill, rej) => fs.stat(path, (er, data) => er ? rej(er) : fulfill(data))),

	applyPlaceholders(str, dirname, filename) {
		if (!str || !str.length) {
			return str;
		}

		return str
		.split('[dir]').join(dirname)
		.split('[Dir]').join(capitalize(dirname))
		.split('[file]').join(filename)
		.split('[File]').join(capitalize(filename));
	}
};
<|endoftext|>


<commit_before>// Dependencies ---------------------------------------------------------------
// ----------------------------------------------------------------------------
var Bluebird = require('bluebird'),
    Levenshtein = require('levenshtein'),
    glob = Bluebird.promisify(require('glob')),
    Spec = require('./Spec');

require('colors');

// Utilities ------------------------------------------------------------------
// ----------------------------------------------------------------------------
var util = {

    getFilesFromPattern: function(pattern) {

        var exp = util.getPatternExp(pattern);
        return glob(pattern).then(function(paths) {
            return paths.map(function(path) {
                var m = path.match(exp);
                return {
                    path: path,
                    directory: m[2],
                    name: m[3]
                };
            });
        });

    },

    replaceFilenameFromPatterns: function(filename, from, to) {

        var fromExp = util.getPatternExp(from),
            parts = filename.match(fromExp).slice(2);

        to = to.replace(/\/\*\*/g, function() {
            return parts[0] ? '/' + parts[0] : '';
        });

        to = to.replace(/\*/, function() {
            return parts[parts.length - 1];
        });

        return to;

    },

    getPatternExp: function(pattern) {

        pattern = pattern.replace(/\/\*\*/g, '###');
        pattern = pattern.replace(/\//g, '\\/');
        pattern = pattern.replace(/\./g, '.').replace('*', '([^\\/]*?)') + '$';
        pattern = pattern.replace(/\#\#\#/g, '(\/(.*?))?');

        return new RegExp(pattern);

    },

    getSpecsFromFiles: function(files) {

        // Create mapping
        var map = {
            features: {},
            tests: {},
            all: {}
        };

        files.features.forEach(function(path) {
            map.features[path.name] = path;
            map.all[path.name] = new Spec(path.name, {
                filename: path.path,
                col: -1,
                line: -1
            });
        });

        files.tests.forEach(function(path) {
            map.tests[path.name] = path;
            map.all[path.name] = new Spec(path.name, {
                filename: path.path,
                col: -1,
                line: -1
            });
        });

        var specs = [];
        for(var i in map.all) {
            if (map.all.hasOwnProperty(i)) {

                var spec = map.all[i];
                if (map.features.hasOwnProperty(i)) {
                    spec.setFeatures(map.features[i].path);
                }

                if (map.tests.hasOwnProperty(i)) {
                    spec.setTests(map.tests[i].path);
                }

                specs.push(spec);

            }
        }

        return specs;

    },

    matchUp: function(a, b, both, missingB, missingA, maxDistance) {

        util.matchItemsByTitle(a, b, maxDistance).forEach(function(pair) {

            if (pair[0] && pair[1]) {
                both(pair[0], pair[1], pair[2]);

            } else if (!pair[1]) {
                missingB(pair[0]);

            } else {
                missingA(pair[1]);
            }

        });

    },

    matchItemsByTitle: function(a, b, maxDistance) {

        // Default maximum levenshtein distance
        maxDistance = maxDistance || 50;

        var leftToMatch = a.slice(),
            others = b.slice(),
            matching = [];

        // Go through all As and find the one with the lowest matching distance
        while(leftToMatch.length) {

            var min = 100000000000,
                matched = {
                    a: null,
                    b: null,
                    distance: 0
                };

            leftToMatch.forEach(function(a) {

                var c = util.findByClosestTitle(a.getTitle(), others);

                if (c.distance < min && c.value) {

                    var at = a.getTitle(),
                        ot = c.value.getTitle(),
                        range = util.findCommonEnds(at, ot);

                    // Compare the raw title value for matching words
                    var common = util.findCommonWords(a.getRawTitle(), ot);

                    // Always take the lowest levenshtein distance in case it
                    // falls under our maximum distances
                    if (c.distance < maxDistance && common !== 0) {

                        matched.a = a;
                        matched.b = c.value;
                        matched.distance = c.distance;
                        matched.range = range;
                        min = c.distance;

                    // Otherwise do a second compare for matching subtext
                    } else {

                        // First remove common start and end strings
                        at = at.slice(range[0], at.length - range[1]);
                        ot = ot.slice(range[0], ot.length - range[1]);

                        // Now split the words and find common parts
                        common = util.findCommonWords(at, ot);

                        // If the distance divided by the common subtext length
                        // is smaller than our max distance, we still match up
                        if (c.distance / common < maxDistance) {
                            matched.a = a;
                            matched.b = c.value;
                            matched.distance = c.distance;
                            min = c.distance;
                        }

                    }

                }

            });

            // No matches
            if (matched.a === null && matched.b === null) {
                break;
            }

            // Push the matches
            matching.push([matched.a, matched.b, matched.distance]);

            // Removed matched items
            leftToMatch.splice(leftToMatch.indexOf(matched.a), 1);
            others.splice(others.indexOf(matched.b), 1);

        }

        // Push the rest of the non matching a into into the results
        leftToMatch.forEach(function(a) {
            matching.push([a, null, 0]);
        });

        // Push the rest of the non matching b into into the results
        others.forEach(function(b) {
            matching.push([null, b, 0]);
        });

        return matching;

    },

    findCommonEnds: function(a, b) {

        var length = Math.min(a.length, b.length),
            startIsConsequtive = true,
            start = 0,
            endIsConsequtive = true,
            end = 0;

        for(var i = 0; i < length; i++) {

            if (a[i] === b[i] && startIsConsequtive) {
                start++;

            } else {
                startIsConsequtive = false;
            }

            if (a[a.length - i - 1] === b[b.length - i - 1] && endIsConsequtive) {
                end++;

            } else {
                endIsConsequtive = false;
            }

        }

        return [start, end];

    },

    findCommonWords: function(a, b) {

        a = a.toLowerCase().split(/\s/);
        b = b.toLowerCase().split(/\s/);

        var common = 0;
        for(var i = 0, l = a.length; i < l; i++) {
            if (b.indexOf(a[i]) !== -1) {
                common += a[i].length;
            }
        }

        return common;

    },

    findByClosestTitle: function(title, items) {

        var min = 1000000000,
            value = null;

        items.forEach(function(item) {

            var l = new Levenshtein(title, item.getTitle());
            if (l.distance < min) {
                value = item;
                min = l.distance;
            }

        });

        return {
            distance: min,
            value: value
        };

    },

    traverse: function(node, validator, callback, parent, results) {
        results = results || [];
        validator = typeof validator === 'function' ? validator : function() { return true; };
        util.traverseSub(node, validator, callback, parent || { type: 'File' }, results);
        return results;
    },

    traverseSub: function(node, validator, callback, parent, results) {

        if (node instanceof Array) {
            for(var i = 0, l = node.length; i < l; i++) {
                util.traverseSub(node[i], validator, callback, parent, results);
            }

        } else if (node !== null) {

            // Run the validator function on the node if it exists
            var valid = validator(node, parent);

            // Skip sub tree and node if requested
            if (valid !== null) {

                for(var key in node) {

                    // Skip parent references or mia properties (prefixed with $)
                    if (key[0] !== '$'
                        && key !== 'type'
                        && key !== 'range'
                        && key !== 'tokens'
                        && key !== 'comments'
                        && key !== 'leadingComments'
                        && key !== 'trailingComments'
                        && key !== 'extendedRange'
                        && key !== 'kind'
                        && key !== 'operator'
                        && typeof node[key] === 'object') {

                        util.traverseSub(node[key], validator, callback, node, results);
                    }

                }

                // Invoke callback bottom up
                if (valid) {
                    var result = callback(node, parent);
                    if (result) {
                        results.push(result);
                    }
                }

            }

        }

    },

    description: function(desc) {

        var lines = desc.split(/[\n\r]/g),
            first = 0,
            emptyStart = false,
            last = lines.length,
            emptyEnd = false;

        // Ignore leading and trailing empty lines
        var minLeading = 1000;
        for(var i = 0, l = lines.length; i < l; i++) {

            if (lines[i].trim() === '' && emptyStart === false) {
                first = i + 1;

            } else {
                emptyStart = true;
            }

            if (lines[lines.length - i -1 ].trim() === '' && emptyEnd === false) {
                last = i - 1;

            } else {
                emptyEnd = true;
            }

        }

        lines = lines.slice(first, last);

        for(i = 0, l = lines.length; i < l; i++) {
            var leading = lines[i].length - lines[i].replace(/^\s+/, '').length;
            minLeading = Math.min(minLeading, leading);
        }

        for(i = 0, l = lines.length; i < l; i++) {
            lines[i] = lines[i].substring(minLeading);
        }

        return lines.join('\n');

    },

    // Colors -----------------------------------------------------------------
    _noColor: !process.stdout.isTTY || process.env.JUNIT_REPORT_PATH,

    color: function(string, value) {

        if (util._noColor) {
            return string;

        } else if (string !== undefined) {
            return string.toString()[value || 'white'];

        } else {
            return '';
        }

    }

};

// Color Codes
util.color.Path = 'blue';
util.color.Value = 'cyan';
util.color.Key = 'green';
util.color.Message = 'yellow';
util.color.Error = 'red';
util.color.Location = 'grey';
util.color.White = 'white';

// Exports --------------------------------------------------------------------
// ----------------------------------------------------------------------------
module.exports = util;

<commit_msg>Correctly support multiple tests / features with the same filename<commit_after>// Dependencies ---------------------------------------------------------------
// ----------------------------------------------------------------------------
var Bluebird = require('bluebird'),
    Levenshtein = require('levenshtein'),
    glob = Bluebird.promisify(require('glob')),
    Spec = require('./Spec');

require('colors');

// Utilities ------------------------------------------------------------------
// ----------------------------------------------------------------------------
var util = {

    getFilesFromPattern: function(pattern) {

        var exp = util.getPatternExp(pattern);
        return glob(pattern).then(function(paths) {
            return paths.map(function(path) {
                var m = path.match(exp);
                return {
                    path: path,
                    id: m[2] + '#' + m[3],
                    directory: m[2],
                    name: m[3]
                };
            });
        });

    },

    replaceFilenameFromPatterns: function(filename, from, to) {

        var fromExp = util.getPatternExp(from),
            parts = filename.match(fromExp).slice(2);

        to = to.replace(/\/\*\*/g, function() {
            return parts[0] ? '/' + parts[0] : '';
        });

        to = to.replace(/\*/, function() {
            return parts[parts.length - 1];
        });

        return to;

    },

    getPatternExp: function(pattern) {

        pattern = pattern.replace(/\/\*\*/g, '###');
        pattern = pattern.replace(/\//g, '\\/');
        pattern = pattern.replace(/\./g, '.').replace('*', '([^\\/]*?)') + '$';
        pattern = pattern.replace(/\#\#\#/g, '(\/(.*?))?');

        return new RegExp(pattern);

    },

    getSpecsFromFiles: function(files) {

        // Create mapping
        var map = {
            features: {},
            tests: {},
            all: {}
        };

        files.features.forEach(function(path) {
            map.features[path.id] = path;
            map.all[path.id] = new Spec(path.name, {
                filename: path.path,
                col: -1,
                line: -1
            });
        });

        files.tests.forEach(function(path) {
            map.tests[path.id] = path;
            map.all[path.id] = new Spec(path.name, {
                filename: path.path,
                col: -1,
                line: -1
            });
        });

        var specs = [];
        for(var i in map.all) {
            if (map.all.hasOwnProperty(i)) {

                var spec = map.all[i];
                if (map.features.hasOwnProperty(i)) {
                    spec.setFeatures(map.features[i].path);
                }

                if (map.tests.hasOwnProperty(i)) {
                    spec.setTests(map.tests[i].path);
                }

                specs.push(spec);

            }
        }

        specs.sort(function(a, b) {
            return a.getTitle().localeCompare(b.getTitle());
        });

        return specs;

    },

    matchUp: function(a, b, both, missingB, missingA, maxDistance) {

        util.matchItemsByTitle(a, b, maxDistance).forEach(function(pair) {

            if (pair[0] && pair[1]) {
                both(pair[0], pair[1], pair[2]);

            } else if (!pair[1]) {
                missingB(pair[0]);

            } else {
                missingA(pair[1]);
            }

        });

    },

    matchItemsByTitle: function(a, b, maxDistance) {

        // Default maximum levenshtein distance
        maxDistance = maxDistance || 50;

        var leftToMatch = a.slice(),
            others = b.slice(),
            matching = [];

        // Go through all As and find the one with the lowest matching distance
        while(leftToMatch.length) {

            var min = 100000000000,
                matched = {
                    a: null,
                    b: null,
                    distance: 0
                };

            leftToMatch.forEach(function(a) {

                var c = util.findByClosestTitle(a.getTitle(), others);

                if (c.distance < min && c.value) {

                    var at = a.getTitle(),
                        ot = c.value.getTitle(),
                        range = util.findCommonEnds(at, ot);

                    // Compare the raw title value for matching words
                    var common = util.findCommonWords(a.getRawTitle(), ot);

                    // Always take the lowest levenshtein distance in case it
                    // falls under our maximum distances
                    if (c.distance < maxDistance && common !== 0) {

                        matched.a = a;
                        matched.b = c.value;
                        matched.distance = c.distance;
                        matched.range = range;
                        min = c.distance;

                    // Otherwise do a second compare for matching subtext
                    } else {

                        // First remove common start and end strings
                        at = at.slice(range[0], at.length - range[1]);
                        ot = ot.slice(range[0], ot.length - range[1]);

                        // Now split the words and find common parts
                        common = util.findCommonWords(at, ot);

                        // If the distance divided by the common subtext length
                        // is smaller than our max distance, we still match up
                        if (c.distance / common < maxDistance) {
                            matched.a = a;
                            matched.b = c.value;
                            matched.distance = c.distance;
                            min = c.distance;
                        }

                    }

                }

            });

            // No matches
            if (matched.a === null && matched.b === null) {
                break;
            }

            // Push the matches
            matching.push([matched.a, matched.b, matched.distance]);

            // Removed matched items
            leftToMatch.splice(leftToMatch.indexOf(matched.a), 1);
            others.splice(others.indexOf(matched.b), 1);

        }

        // Push the rest of the non matching a into into the results
        leftToMatch.forEach(function(a) {
            matching.push([a, null, 0]);
        });

        // Push the rest of the non matching b into into the results
        others.forEach(function(b) {
            matching.push([null, b, 0]);
        });

        return matching;

    },

    findCommonEnds: function(a, b) {

        var length = Math.min(a.length, b.length),
            startIsConsequtive = true,
            start = 0,
            endIsConsequtive = true,
            end = 0;

        for(var i = 0; i < length; i++) {

            if (a[i] === b[i] && startIsConsequtive) {
                start++;

            } else {
                startIsConsequtive = false;
            }

            if (a[a.length - i - 1] === b[b.length - i - 1] && endIsConsequtive) {
                end++;

            } else {
                endIsConsequtive = false;
            }

        }

        return [start, end];

    },

    findCommonWords: function(a, b) {

        a = a.toLowerCase().split(/\s/);
        b = b.toLowerCase().split(/\s/);

        var common = 0;
        for(var i = 0, l = a.length; i < l; i++) {
            if (b.indexOf(a[i]) !== -1) {
                common += a[i].length;
            }
        }

        return common;

    },

    findByClosestTitle: function(title, items) {

        var min = 1000000000,
            value = null;

        items.forEach(function(item) {

            var l = new Levenshtein(title, item.getTitle());
            if (l.distance < min) {
                value = item;
                min = l.distance;
            }

        });

        return {
            distance: min,
            value: value
        };

    },

    traverse: function(node, validator, callback, parent, results) {
        results = results || [];
        validator = typeof validator === 'function' ? validator : function() { return true; };
        util.traverseSub(node, validator, callback, parent || { type: 'File' }, results);
        return results;
    },

    traverseSub: function(node, validator, callback, parent, results) {

        if (node instanceof Array) {
            for(var i = 0, l = node.length; i < l; i++) {
                util.traverseSub(node[i], validator, callback, parent, results);
            }

        } else if (node !== null) {

            // Run the validator function on the node if it exists
            var valid = validator(node, parent);

            // Skip sub tree and node if requested
            if (valid !== null) {

                for(var key in node) {

                    // Skip parent references or mia properties (prefixed with $)
                    if (key[0] !== '$'
                        && key !== 'type'
                        && key !== 'range'
                        && key !== 'tokens'
                        && key !== 'comments'
                        && key !== 'leadingComments'
                        && key !== 'trailingComments'
                        && key !== 'extendedRange'
                        && key !== 'kind'
                        && key !== 'operator'
                        && typeof node[key] === 'object') {

                        util.traverseSub(node[key], validator, callback, node, results);
                    }

                }

                // Invoke callback bottom up
                if (valid) {
                    var result = callback(node, parent);
                    if (result) {
                        results.push(result);
                    }
                }

            }

        }

    },

    description: function(desc) {

        var lines = desc.split(/[\n\r]/g),
            first = 0,
            emptyStart = false,
            last = lines.length,
            emptyEnd = false;

        // Ignore leading and trailing empty lines
        var minLeading = 1000;
        for(var i = 0, l = lines.length; i < l; i++) {

            if (lines[i].trim() === '' && emptyStart === false) {
                first = i + 1;

            } else {
                emptyStart = true;
            }

            if (lines[lines.length - i -1 ].trim() === '' && emptyEnd === false) {
                last = i - 1;

            } else {
                emptyEnd = true;
            }

        }

        lines = lines.slice(first, last);

        for(i = 0, l = lines.length; i < l; i++) {
            var leading = lines[i].length - lines[i].replace(/^\s+/, '').length;
            minLeading = Math.min(minLeading, leading);
        }

        for(i = 0, l = lines.length; i < l; i++) {
            lines[i] = lines[i].substring(minLeading);
        }

        return lines.join('\n');

    },

    // Colors -----------------------------------------------------------------
    _noColor: !process.stdout.isTTY || process.env.JUNIT_REPORT_PATH,

    color: function(string, value) {

        if (util._noColor) {
            return string;

        } else if (string !== undefined) {
            return string.toString()[value || 'white'];

        } else {
            return '';
        }

    }

};

// Color Codes
util.color.Path = 'blue';
util.color.Value = 'cyan';
util.color.Key = 'green';
util.color.Message = 'yellow';
util.color.Error = 'red';
util.color.Location = 'grey';
util.color.White = 'white';

// Exports --------------------------------------------------------------------
// ----------------------------------------------------------------------------
module.exports = util;

<|endoftext|>


<commit_before>var http = require('http')
  , https = require('https')
  , through = require('through2')
  , concat = require('concat-stream')
  , ajax = require('vigour-js/browser/network/ajax')

module.exports = exports

exports.url = function(str) {
  return /^https?:\/\//.test(str)
}

exports.defaults = function (options) {
	var defaults = [
		{ k: 'maxTries', v: 1 }
	  , { k: 'retryDelayType', v: 'exp' }
	  , { k: 'retryDelay', v: 500 }
	  , { k: 'retryOn404', v: false }
	  , { k: 'respectRetryAfter', v: true }
	  , { k: 'maxRetryDelay', v: 60000 }
	]
	defaults.forEach(function (item) {
		options[item.k] = options[item.k] || item.v
	})
}

exports.readHttp = function (url, options, cb) {
	exports.getRetry(url, options, function (err, throughStream) {
		if (err) {
			cb(err)
		} else {
			throughStream.pipe(concat(function (data) {
				cb(null, data)
			}))
		}
	})
}

exports.readAjax = function (url, options, cb) {
	exports.ajaxRetry(url, options, function (err, data) {
		if (err) {
			cb(err)
		} else {
			cb(null, data)
		}
	})
}

exports.getRetry = function (url, options, cb) {
	exports.retryFactory(exports.get, options)(url, options, cb)
}

exports.ajaxRetry = function (url, options, cb) {
	exports.retryFactory(exports.ajaxGet, options)(url, options, cb)
}

exports.ajaxGet = function (url, options, cb) {
	ajax({
		url: url
		, complete: function (data, xhrProgressEvent) {
			return setupRetry(xhrProgressEvent.target.status
				,	 xhrProgressEvent.target.getResponseHeader('Retry-After')
				, options
				, function (err) {
					if (err) {
						cb(err)
					} else {
						cb(null, data)
					}
				})

		}
		, error: function (err) {
			return cb(err)
		}
	})
}

exports.get = function (url, options, cb) {
	var throughStream = through()
	;(/^https/.test(url) ? https : http).get(url
		, function (res) {
			return setupRetry(res.statusCode
				, res.headers['retry-after']
				, options
				, function (err) {
					if (err) {
						res.resume()
						return cb(err)
					} else {
						res.pipe(throughStream)
						return cb(null, throughStream)
					}
				})
		})
}

function setupRetry (statusCode, retryAfter, options, cb) {
	var error
		, parsed
		, diff
	if (statusCode === 500 || statusCode === 503 || (options.retryOn404 && statusCode === 404)) {
		error = new Error("Remote server error (" + statusCode + ")")
		error.statusCode = statusCode
		error.retry = true
		if (retryAfter) {
			error.retryAfterContent = retryAfter
			parsed = parseInt(retryAfter, 10)
			if (parsed) {
				error.retryAfter = parsed * 1000
			} else {
				parsed = (new Date(retryAfter)).getTime()
				if (parsed) {
					diff = parsed - Date.now()
					if (diff > 0) {
						error.retryAfter = diff
					}
				}
			}
			if (error.retryAfter > options.maxRetryDelay) {
				error.retry = false
				error.message += "; Retry-After delay over maxRetryDelay"
			}
		}
		return cb(error)
	} else if (statusCode === 200) {
		return cb()
	} else {
		error = new Error("Error GETting url. StatusCode: " + statusCode)
		error.statusCode = statusCode
		error.retry = false
		return cb(error)
	}
}

exports.retryFactory = function (fn, options) {
	return function () {
		var tryNb = 0
			, args = [].slice.call(arguments)
			, cb = args.pop()

		attempt()

		function attempt () {
			fn.apply(null, args.concat(function (err, throughStream) {
				var error
					, retryDelay
				if (err) {
					if (err.retry) {
						if (tryNb >= options.maxTries) {
							error = err
							error.message += ". Maximum number of attempts reached"
							error.maxTries = options.maxTries
							return cb(error)
						} else {
							if (options.respectRetryAfter && err.retryAfter) {
								retryDelay = err.retryAfter
							} else if (options.retryDelayType === 'exp') {
			          retryDelay = options.retryDelay * Math.pow(2, tryNb)
			        } else if (options.retryDelayType === 'linear') {
			          retryDelay = options.retryDelay * tryNb
			        } else /*if (options.retryDelayType === 'constant') */{
			          retryDelay = options.retryDelay
			        }
			        tryNb += 1
			        if (retryDelay > options.maxRetryDelay) {
			        	retryDelay = options.maxRetryDelay
			        }
							setTimeout(attempt, retryDelay)
						}
					} else {
						error = err
						return cb(error)
					}
				} else {
					return cb(null, throughStream)
				}
			}))
		}
	}
}<commit_msg>Remove use of [].forEach and Date.now<commit_after>var http = require('http')
  , https = require('https')
  , through = require('through2')
  , concat = require('concat-stream')
  , ajax = require('vigour-js/browser/network/ajax')

module.exports = exports

exports.url = function(str) {
  return /^https?:\/\//.test(str)
}

exports.defaults = function (options) {
	var defaults = [
			{ k: 'maxTries', v: 1 }
		  , { k: 'retryDelayType', v: 'exp' }
		  , { k: 'retryDelay', v: 500 }
		  , { k: 'retryOn404', v: false }
		  , { k: 'respectRetryAfter', v: true }
		  , { k: 'maxRetryDelay', v: 60000 }
		]
		, l = defaults.length
		, i
	for (i = 0; i < l; i += 1) {
		options[defaults[i].k] = options[defaults[i].k] || defaults[i].v
	}
}

exports.readHttp = function (url, options, cb) {
	exports.getRetry(url, options, function (err, throughStream) {
		if (err) {
			cb(err)
		} else {
			throughStream.pipe(concat(function (data) {
				cb(null, data)
			}))
		}
	})
}

exports.readAjax = function (url, options, cb) {
	exports.ajaxRetry(url, options, function (err, data) {
		if (err) {
			cb(err)
		} else {
			cb(null, data)
		}
	})
}

exports.getRetry = function (url, options, cb) {
	exports.retryFactory(exports.get, options)(url, options, cb)
}

exports.ajaxRetry = function (url, options, cb) {
	exports.retryFactory(exports.ajaxGet, options)(url, options, cb)
}

exports.ajaxGet = function (url, options, cb) {
	ajax({
		url: url
		, complete: function (data, xhrProgressEvent) {
			return setupRetry(xhrProgressEvent.target.status
				,	 xhrProgressEvent.target.getResponseHeader('Retry-After')
				, options
				, function (err) {
					if (err) {
						cb(err)
					} else {
						cb(null, data)
					}
				})

		}
		, error: function (err) {
			return cb(err)
		}
	})
}

exports.get = function (url, options, cb) {
	var throughStream = through()
	;(/^https/.test(url) ? https : http).get(url
		, function (res) {
			return setupRetry(res.statusCode
				, res.headers['retry-after']
				, options
				, function (err) {
					if (err) {
						res.resume()
						return cb(err)
					} else {
						res.pipe(throughStream)
						return cb(null, throughStream)
					}
				})
		})
}

function setupRetry (statusCode, retryAfter, options, cb) {
	var error
		, parsed
		, diff
		, date
	if (statusCode === 500 || statusCode === 503 || (options.retryOn404 && statusCode === 404)) {
		error = new Error("Remote server error (" + statusCode + ")")
		error.statusCode = statusCode
		error.retry = true
		if (retryAfter) {
			error.retryAfterContent = retryAfter
			parsed = parseInt(retryAfter, 10)
			if (parsed) {
				error.retryAfter = parsed * 1000
			} else {
				parsed = (new Date(retryAfter)).getTime()
				if (parsed) {
					date = new Date()
					diff = parsed - date.getTime()
					if (diff > 0) {
						error.retryAfter = diff
					}
				}
			}
			if (error.retryAfter > options.maxRetryDelay) {
				error.retry = false
				error.message += "; Retry-After delay over maxRetryDelay"
			}
		}
		return cb(error)
	} else if (statusCode === 200) {
		return cb()
	} else {
		error = new Error("Error GETting url. StatusCode: " + statusCode)
		error.statusCode = statusCode
		error.retry = false
		return cb(error)
	}
}

exports.retryFactory = function (fn, options) {
	return function () {
		var tryNb = 0
			, args = [].slice.call(arguments)
			, cb = args.pop()

		attempt()

		function attempt () {
			fn.apply(null, args.concat(function (err, throughStream) {
				var error
					, retryDelay
				if (err) {
					if (err.retry) {
						if (tryNb >= options.maxTries) {
							error = err
							error.message += ". Maximum number of attempts reached"
							error.maxTries = options.maxTries
							return cb(error)
						} else {
							if (options.respectRetryAfter && err.retryAfter) {
								retryDelay = err.retryAfter
							} else if (options.retryDelayType === 'exp') {
			          retryDelay = options.retryDelay * Math.pow(2, tryNb)
			        } else if (options.retryDelayType === 'linear') {
			          retryDelay = options.retryDelay * tryNb
			        } else /*if (options.retryDelayType === 'constant') */{
			          retryDelay = options.retryDelay
			        }
			        tryNb += 1
			        if (retryDelay > options.maxRetryDelay) {
			        	retryDelay = options.maxRetryDelay
			        }
							setTimeout(attempt, retryDelay)
						}
					} else {
						error = err
						return cb(error)
					}
				} else {
					return cb(null, throughStream)
				}
			}))
		}
	}
}<|endoftext|>


<commit_before>
/**
 * socket.io
 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
 * MIT Licensed
 */

(function (exports, global) {

  /**
   * Utilities namespace.
   *
   * @namespace
   */

  var util = exports.util = {};

  /**
   * Parses an URI
   *
   * @author Steven Levithan <stevenlevithan.com> (MIT license)
   * @api public
   */

  var re = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/;

  var parts = ['source', 'protocol', 'authority', 'userInfo', 'user', 'password',
               'host', 'port', 'relative', 'path', 'directory', 'file', 'query',
               'anchor'];

  util.parseUri = function (str) {
    var m = re.exec(str || '')
      , uri = {}
      , i = 14;

    while (i--) {
      uri[parts[i]] = m[i] || '';
    }

    return uri;
  };

  /**
   * Produces a unique url that identifies a Socket.IO connection.
   *
   * @param {Object} uri
   * @api public
   */

  util.uniqueUri = function (uri) {
    var protocol = uri.protocol
      , host = uri.host
      , port = uri.port;

    if ('document' in global) {
      host = host || document.domain;
      port = port || (protocol == 'https'
        && document.location.protocol !== 'https:' ? 443 : document.location.port);
    } else {
      host = host || 'localhost';

      if (!port && protocol == 'https') {
        port = 443;
      }
    }

    return (protocol || 'http') + '://' + host + ':' + (port || 80);
  };

  /**
   * Mergest 2 query strings in to once unique query string
   *
   * @param {String} base
   * @param {String} addition
   * @api public
   */

  util.query = function (base, addition) {
    var query = util.chunkQuery(base || '')
      , components = [];

    util.merge(query, util.chunkQuery(addition || ''));
    for (var part in query) {
      if (query.hasOwnProperty(part)) {
        components.push(part + '=' + query[part]);
      }
    }

    return components.length ? '?' + components.join('&') : '';
  };

  /**
   * Transforms a querystring in to an object
   *
   * @param {String} qs
   * @api public
   */

  util.chunkQuery = function (qs) {
    var query = {}
      , params = qs.split('&')
      , i = 0
      , l = params.length
      , kv;

    for (; i < l; ++i) {
      kv = params[i].split('=');
      if (kv[0]) {
        query[kv[0]] = decodeURIComponent(kv[1]);
      }
    }

    return query;
  };

  /**
   * Executes the given function when the page is loaded.
   *
   *     io.util.load(function () { console.log('page loaded'); });
   *
   * @param {Function} fn
   * @api public
   */

  var pageLoaded = false;

  util.load = function (fn) {
    if ('document' in global && document.readyState === 'complete' || pageLoaded) {
      return fn();
    }

    util.on(global, 'load', fn, false);
  };

  /**
   * Adds an event.
   *
   * @api private
   */

  util.on = function (element, event, fn, capture) {
    if (element.attachEvent) {
      element.attachEvent('on' + event, fn);
    } else if (element.addEventListener) {
      element.addEventListener(event, fn, capture);
    }
  };

  /**
   * Generates the correct `XMLHttpRequest` for regular and cross domain requests.
   *
   * @param {Boolean} [xdomain] Create a request that can be used cross domain.
   * @returns {XMLHttpRequest|false} If we can create a XMLHttpRequest.
   * @api private
   */

  util.request = function (xdomain) {
    // if node
    var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
    return new XMLHttpRequest();
    // end node

    if (xdomain && 'undefined' != typeof XDomainRequest) {
      return new XDomainRequest();
    }

    if ('undefined' != typeof XMLHttpRequest && (!xdomain || util.ua.hasCORS)) {
      return new XMLHttpRequest();
    }

    if (!xdomain) {
      try {
        return new ActiveXObject('Microsoft.XMLHTTP');
      } catch(e) { }
    }

    return null;
  };

  /**
   * XHR based transport constructor.
   *
   * @constructor
   * @api public
   */

  /**
   * Change the internal pageLoaded value.
   */

  if ('undefined' != typeof window) {
    util.load(function () {
      pageLoaded = true;
    });
  }

  /**
   * Defers a function to ensure a spinner is not displayed by the browser
   *
   * @param {Function} fn
   * @api public
   */

  util.defer = function (fn) {
    if (!util.ua.webkit || 'undefined' != typeof importScripts) {
      return fn();
    }

    util.load(function () {
      setTimeout(fn, 100);
    });
  };

  /**
   * Merges two objects.
   *
   * @api public
   */

  util.merge = function merge (target, additional, deep, lastseen) {
    var seen = lastseen || []
      , depth = typeof deep == 'undefined' ? 2 : deep
      , prop;

    for (prop in additional) {
      if (additional.hasOwnProperty(prop) && util.indexOf(seen, prop) < 0) {
        if (typeof target[prop] !== 'object' || !depth) {
          target[prop] = additional[prop];
          seen.push(additional[prop]);
        } else {
          util.merge(target[prop], additional[prop], depth - 1, seen);
        }
      }
    }

    return target;
  };

  /**
   * Merges prototypes from objects
   *
   * @api public
   */

  util.mixin = function (ctor, ctor2) {
    util.merge(ctor.prototype, ctor2.prototype);
  };

  /**
   * Shortcut for prototypical and static inheritance.
   *
   * @api private
   */

  util.inherit = function (ctor, ctor2) {
    function f() {};
    f.prototype = ctor2.prototype;
    ctor.prototype = new f;
  };

  /**
   * Checks if the given object is an Array.
   *
   *     io.util.isArray([]); // true
   *     io.util.isArray({}); // false
   *
   * @param Object obj
   * @api public
   */

  util.isArray = Array.isArray || function (obj) {
    return Object.prototype.toString.call(obj) === '[object Array]';
  };

  /**
   * Intersects values of two arrays into a third
   *
   * @api public
   */

  util.intersect = function (arr, arr2) {
    var ret = []
      , longest = arr.length > arr2.length ? arr : arr2
      , shortest = arr.length > arr2.length ? arr2 : arr;

    for (var i = 0, l = shortest.length; i < l; i++) {
      if (~util.indexOf(longest, shortest[i]))
        ret.push(shortest[i]);
    }

    return ret;
  }

  /**
   * Array indexOf compatibility.
   *
   * @see bit.ly/a5Dxa2
   * @api public
   */

  util.indexOf = function (arr, o, i) {
    if (Array.prototype.indexOf) {
      return Array.prototype.indexOf.call(arr, o, i);
    }

    for (var j = arr.length, i = i < 0 ? i + j < 0 ? 0 : i + j : i || 0;
         i < j && arr[i] !== o; i++);

    return j <= i ? -1 : i;
  };

  /**
   * Converts enumerables to array.
   *
   * @api public
   */

  util.toArray = function (enu) {
    var arr = [];

    for (var i = 0, l = enu.length; i < l; i++)
      arr.push(enu[i]);

    return arr;
  };

  /**
   * UA / engines detection namespace.
   *
   * @namespace
   */

  util.ua = {};

  /**
   * Whether the UA supports CORS for XHR.
   *
   * @api public
   */

  util.ua.hasCORS = 'undefined' != typeof XMLHttpRequest && (function () {
    try {
      var a = new XMLHttpRequest();
    } catch (e) {
      return false;
    }

    return a.withCredentials != undefined;
  })();

  /**
   * Detect webkit.
   *
   * @api public
   */

  util.ua.webkit = 'undefined' != typeof navigator
    && /webkit/i.test(navigator.userAgent);

})(
    'undefined' != typeof window ? io : module.exports
  , this
);
<commit_msg>Added reference to global object<commit_after>
/**
 * socket.io
 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
 * MIT Licensed
 */

(function (exports, global) {

  /**
   * Utilities namespace.
   *
   * @namespace
   */

  var util = exports.util = {};

  /**
   * Parses an URI
   *
   * @author Steven Levithan <stevenlevithan.com> (MIT license)
   * @api public
   */

  var re = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/;

  var parts = ['source', 'protocol', 'authority', 'userInfo', 'user', 'password',
               'host', 'port', 'relative', 'path', 'directory', 'file', 'query',
               'anchor'];

  util.parseUri = function (str) {
    var m = re.exec(str || '')
      , uri = {}
      , i = 14;

    while (i--) {
      uri[parts[i]] = m[i] || '';
    }

    return uri;
  };

  /**
   * Produces a unique url that identifies a Socket.IO connection.
   *
   * @param {Object} uri
   * @api public
   */

  util.uniqueUri = function (uri) {
    var protocol = uri.protocol
      , host = uri.host
      , port = uri.port;

    if ('document' in global) {
      host = host || document.domain;
      port = port || (protocol == 'https'
        && document.location.protocol !== 'https:' ? 443 : document.location.port);
    } else {
      host = host || 'localhost';

      if (!port && protocol == 'https') {
        port = 443;
      }
    }

    return (protocol || 'http') + '://' + host + ':' + (port || 80);
  };

  /**
   * Mergest 2 query strings in to once unique query string
   *
   * @param {String} base
   * @param {String} addition
   * @api public
   */

  util.query = function (base, addition) {
    var query = util.chunkQuery(base || '')
      , components = [];

    util.merge(query, util.chunkQuery(addition || ''));
    for (var part in query) {
      if (query.hasOwnProperty(part)) {
        components.push(part + '=' + query[part]);
      }
    }

    return components.length ? '?' + components.join('&') : '';
  };

  /**
   * Transforms a querystring in to an object
   *
   * @param {String} qs
   * @api public
   */

  util.chunkQuery = function (qs) {
    var query = {}
      , params = qs.split('&')
      , i = 0
      , l = params.length
      , kv;

    for (; i < l; ++i) {
      kv = params[i].split('=');
      if (kv[0]) {
        query[kv[0]] = decodeURIComponent(kv[1]);
      }
    }

    return query;
  };

  /**
   * Executes the given function when the page is loaded.
   *
   *     io.util.load(function () { console.log('page loaded'); });
   *
   * @param {Function} fn
   * @api public
   */

  var pageLoaded = false;

  util.load = function (fn) {
    if ('document' in global && document.readyState === 'complete' || pageLoaded) {
      return fn();
    }

    util.on(global, 'load', fn, false);
  };

  /**
   * Adds an event.
   *
   * @api private
   */

  util.on = function (element, event, fn, capture) {
    if (element.attachEvent) {
      element.attachEvent('on' + event, fn);
    } else if (element.addEventListener) {
      element.addEventListener(event, fn, capture);
    }
  };

  /**
   * Generates the correct `XMLHttpRequest` for regular and cross domain requests.
   *
   * @param {Boolean} [xdomain] Create a request that can be used cross domain.
   * @returns {XMLHttpRequest|false} If we can create a XMLHttpRequest.
   * @api private
   */

  util.request = function (xdomain) {
    // if node
    var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
    return new XMLHttpRequest();
    // end node

    if (xdomain && 'undefined' != typeof XDomainRequest) {
      return new XDomainRequest();
    }

    if ('undefined' != typeof XMLHttpRequest && (!xdomain || util.ua.hasCORS)) {
      return new XMLHttpRequest();
    }

    if (!xdomain) {
      try {
        return new ActiveXObject('Microsoft.XMLHTTP');
      } catch(e) { }
    }

    return null;
  };

  /**
   * XHR based transport constructor.
   *
   * @constructor
   * @api public
   */

  /**
   * Change the internal pageLoaded value.
   */

  if ('undefined' != typeof window) {
    util.load(function () {
      pageLoaded = true;
    });
  }

  /**
   * Defers a function to ensure a spinner is not displayed by the browser
   *
   * @param {Function} fn
   * @api public
   */

  util.defer = function (fn) {
    if (!util.ua.webkit || 'undefined' != typeof importScripts) {
      return fn();
    }

    util.load(function () {
      setTimeout(fn, 100);
    });
  };

  /**
   * Merges two objects.
   *
   * @api public
   */

  util.merge = function merge (target, additional, deep, lastseen) {
    var seen = lastseen || []
      , depth = typeof deep == 'undefined' ? 2 : deep
      , prop;

    for (prop in additional) {
      if (additional.hasOwnProperty(prop) && util.indexOf(seen, prop) < 0) {
        if (typeof target[prop] !== 'object' || !depth) {
          target[prop] = additional[prop];
          seen.push(additional[prop]);
        } else {
          util.merge(target[prop], additional[prop], depth - 1, seen);
        }
      }
    }

    return target;
  };

  /**
   * Merges prototypes from objects
   *
   * @api public
   */

  util.mixin = function (ctor, ctor2) {
    util.merge(ctor.prototype, ctor2.prototype);
  };

  /**
   * Shortcut for prototypical and static inheritance.
   *
   * @api private
   */

  util.inherit = function (ctor, ctor2) {
    function f() {};
    f.prototype = ctor2.prototype;
    ctor.prototype = new f;
  };

  /**
   * Checks if the given object is an Array.
   *
   *     io.util.isArray([]); // true
   *     io.util.isArray({}); // false
   *
   * @param Object obj
   * @api public
   */

  util.isArray = Array.isArray || function (obj) {
    return Object.prototype.toString.call(obj) === '[object Array]';
  };

  /**
   * Intersects values of two arrays into a third
   *
   * @api public
   */

  util.intersect = function (arr, arr2) {
    var ret = []
      , longest = arr.length > arr2.length ? arr : arr2
      , shortest = arr.length > arr2.length ? arr2 : arr;

    for (var i = 0, l = shortest.length; i < l; i++) {
      if (~util.indexOf(longest, shortest[i]))
        ret.push(shortest[i]);
    }

    return ret;
  }

  /**
   * Array indexOf compatibility.
   *
   * @see bit.ly/a5Dxa2
   * @api public
   */

  util.indexOf = function (arr, o, i) {
    if (Array.prototype.indexOf) {
      return Array.prototype.indexOf.call(arr, o, i);
    }

    for (var j = arr.length, i = i < 0 ? i + j < 0 ? 0 : i + j : i || 0;
         i < j && arr[i] !== o; i++);

    return j <= i ? -1 : i;
  };

  /**
   * Converts enumerables to array.
   *
   * @api public
   */

  util.toArray = function (enu) {
    var arr = [];

    for (var i = 0, l = enu.length; i < l; i++)
      arr.push(enu[i]);

    return arr;
  };

  /**
   * UA / engines detection namespace.
   *
   * @namespace
   */

  util.ua = {};

  /**
   * Whether the UA supports CORS for XHR.
   *
   * @api public
   */

  util.ua.hasCORS = 'undefined' != typeof XMLHttpRequest && (function () {
    try {
      var a = new XMLHttpRequest();
    } catch (e) {
      return false;
    }

    return a.withCredentials != undefined;
  })();

  /**
   * Detect webkit.
   *
   * @api public
   */

  util.ua.webkit = 'undefined' != typeof navigator
    && /webkit/i.test(navigator.userAgent);

})('undefined' != typeof io ? io : module.exports, this);
<|endoftext|>