<commit_before>var PATH = require('./path'),
    FS = require('fs');

exports.chdirOptParse = function() {
    return this.opt()
        .name('dir').short('C').long('chdir')
        .title('рабочая директория, по умолчанию текущая')
        .def(process.cwd())
        .val(function(d) {
            d = PATH.join(d, '/');
            process.chdir(d);
            return d;
        })
        .end();
};

exports.techsOptParse = function() {
    return this
        .opt()
            .name('addTech').short('t').long('add-tech')
            .title('добавить технологию')
            .arr()
            .end()
        .opt()
            .name('forceTech').short('T').long('force-tech')
            .title('использовать только эту технологию')
            .arr()
            .end()
        .opt()
            .name('noTech').short('n').long('no-tech')
            .title('исключить технологию из использования')
            .arr()
            .end()
};

exports.levelOptParse = function() {
    var def = exports.findLevel(process.cwd()),
        rel = PATH.relative(PATH.join(process.cwd(), '/'), def);
    return this.opt()
        .name('levelDir').short('l').long('level')
        .def(def)
        .title(['директория уровня переопределения, по умолчанию: ',
            !rel? '.' : rel, '/'].join(''))
        .val(function(d) { return PATH.join(d, '/') })
        .end();
};

exports.mergeTechs = function(level, opts) {
    // NOTE: если при создании блока/элемента/модификатора
    // указали --force-tech <name> или --no-tech, и в level.js
    // определена технология с таким именем/файлом на диске,
    // нужно использовать именно её
    var techs = opts.forceTech? {} : level.techs,
        optsTechs = [];

    opts.forceTech && optsTechs.push.apply(optsTechs, opts.forceTech);
    opts.addTech && optsTechs.push.apply(optsTechs, opts.addTech);

    optsTechs.forEach(function(t) {
        var tech = level.getTech(t),
            name = tech.getTechName();
        techs[name] || (techs[name] = tech);
    });

    opts.noTech && opts.noTech.forEach(function(t) {
        delete techs[level.getTech(t).getTechName()];
    });

    return techs;
};

exports.write = function(path, content) {
    FS.createWriteStream(path, { encoding: 'utf8' })
        .write(Array.isArray(content) ? content.join('') : content);
};

exports.mkdir = function(path) {
    try { FS.mkdirSync(path, 0777) } catch(ignore) {}
};

exports.mkdirs = function(path) {
    if (PATH.existsSync(path)) return;
    exports.mkdirs(PATH.dirname(path));
    exports.mkdir(path);
};

exports.isFile = function(path) {
    try {
        return FS.statSync(path).isFile();
    } catch(ignore) {}
    return false;
};

exports.isDirectory = function(path) {
    try {
        return FS.statSync(path).isDirectory();
    } catch(ignore) {}
    return false;
};

exports.isLevel = function(path) {
    return exports.isDirectory(path) &&
        exports.isFile(PATH.join(path, '.bem/level.js'));
};

exports.findLevel = function(path, startPath) {
    startPath = startPath || path;
    if (exports.isLevel(path)) return path;
    if (path == '/') return startPath;
    return exports.findLevel(PATH.dirname(path), startPath);
};

exports.fsWalkTree = function(root, fileCb, filterCb) {
    var files = FS.readdirSync(root);
    while (files.length > 0) {
        var path = PATH.join(root, files.shift());
        if(filterCb && !filterCb(path)) continue;
        fileCb(path);
        if(exports.isDirectory(path)) exports.fsWalkTree(path, fileCb, filterCb);
    }
};

exports.getDirs = function(path) {
    try {
        return exports.isDirectory(path)?
            FS.readdirSync(path)
                .filter(function(d) {
                    return !(/^\.svn$/.test(d)) && exports.isDirectory(PATH.join(path, d));
                })
                .sort() :
            [];
    } catch (e) {
        return [];
    }
};

exports.getFiles = function(path) {
    try {
        return exports.isDirectory(path)?
            FS.readdirSync(path)
                .filter(function(f) {
                    return exports.isFile(PATH.join(path, f));
                })
                .sort() :
            [];
    } catch (e) {
        return [];
    }
};

exports.isEmptyObject = function(obj) {
    for(var i in obj) return false;
    return true;
};

exports.isRequireError = function(e) {
    return /^Cannot find module/.test(e.message);
};

exports.isPath = function(str) {
    return str.indexOf('/') !== -1;
};

exports.isRequireable = function(path) {
    try {
        require.resolve(path);
        return true;
    } catch (e) {
        if(! exports.isRequireError(e)) throw e;
        return false;
    }
};

exports.arrayUnique = function(arr) {
    return arr.reduce(function(prev, cur) {
        if(prev.indexOf(cur) + 1) return prev;
        return prev.concat([cur]);
    }, []);
};

exports.arrayReverse = function(arr) {
    return arr.reduceRight(function(prev, cur) {
        prev.push(cur);
        return prev;
    }, []);
};

exports.getBemTechPath = function(name) {
    var bemTechs = 'bem/lib/techs',
        path = PATH.join(bemTechs, name);
    if(exports.isRequireable(path)) {
        return path;
    }
    return 'bem/lib/tech';
};

exports.stripModuleExt = function(path) {
    var exts = Object.keys(require.extensions).map(function(v) {
        return v.replace(/^\./, '');
    });
    return path.replace(new RegExp('\\.(' + exts.join('|') + ')$'), '');
};

exports.getNodePaths = function() {
    return (process.env.NODE_PATH || '').split(process.platform === 'windows' ? ';' : ':');
};

exports.mergeDecls = function mergeDecls(d1, d2) {
    var keys = {};
    d1?
        d1.forEach(function(o) { keys[o.name || o] = o }) :
        d1 = [];

    d2.forEach(function(o2) {
        var name = o2.name || o2;
        if (keys.hasOwnProperty(name)) {
            var o1 = keys[name];
            o2.elems && (o1.elems = mergeDecls(o1.elems, o2.elems));
            o2.mods && (o1.mods = mergeDecls(o1.mods, o2.mods));
            o2.vals && (o1.vals = mergeDecls(o1.vals, o2.vals));
            o2.techs && (o1.techs = mergeDecls(o1.techs, o2.techs));
        } else {
            d1.push(o2);
            keys[name] = o2;
        }
    });

    return d1;
};
<commit_msg>Sort files alphabetically in `fsWalkTree()` to smooth fs differences<commit_after>var PATH = require('./path'),
    FS = require('fs');

exports.chdirOptParse = function() {
    return this.opt()
        .name('dir').short('C').long('chdir')
        .title('рабочая директория, по умолчанию текущая')
        .def(process.cwd())
        .val(function(d) {
            d = PATH.join(d, '/');
            process.chdir(d);
            return d;
        })
        .end();
};

exports.techsOptParse = function() {
    return this
        .opt()
            .name('addTech').short('t').long('add-tech')
            .title('добавить технологию')
            .arr()
            .end()
        .opt()
            .name('forceTech').short('T').long('force-tech')
            .title('использовать только эту технологию')
            .arr()
            .end()
        .opt()
            .name('noTech').short('n').long('no-tech')
            .title('исключить технологию из использования')
            .arr()
            .end()
};

exports.levelOptParse = function() {
    var def = exports.findLevel(process.cwd()),
        rel = PATH.relative(PATH.join(process.cwd(), '/'), def);
    return this.opt()
        .name('levelDir').short('l').long('level')
        .def(def)
        .title(['директория уровня переопределения, по умолчанию: ',
            !rel? '.' : rel, '/'].join(''))
        .val(function(d) { return PATH.join(d, '/') })
        .end();
};

exports.mergeTechs = function(level, opts) {
    // NOTE: если при создании блока/элемента/модификатора
    // указали --force-tech <name> или --no-tech, и в level.js
    // определена технология с таким именем/файлом на диске,
    // нужно использовать именно её
    var techs = opts.forceTech? {} : level.techs,
        optsTechs = [];

    opts.forceTech && optsTechs.push.apply(optsTechs, opts.forceTech);
    opts.addTech && optsTechs.push.apply(optsTechs, opts.addTech);

    optsTechs.forEach(function(t) {
        var tech = level.getTech(t),
            name = tech.getTechName();
        techs[name] || (techs[name] = tech);
    });

    opts.noTech && opts.noTech.forEach(function(t) {
        delete techs[level.getTech(t).getTechName()];
    });

    return techs;
};

exports.write = function(path, content) {
    FS.createWriteStream(path, { encoding: 'utf8' })
        .write(Array.isArray(content) ? content.join('') : content);
};

exports.mkdir = function(path) {
    try { FS.mkdirSync(path, 0777) } catch(ignore) {}
};

exports.mkdirs = function(path) {
    if (PATH.existsSync(path)) return;
    exports.mkdirs(PATH.dirname(path));
    exports.mkdir(path);
};

exports.isFile = function(path) {
    try {
        return FS.statSync(path).isFile();
    } catch(ignore) {}
    return false;
};

exports.isDirectory = function(path) {
    try {
        return FS.statSync(path).isDirectory();
    } catch(ignore) {}
    return false;
};

exports.isLevel = function(path) {
    return exports.isDirectory(path) &&
        exports.isFile(PATH.join(path, '.bem/level.js'));
};

exports.findLevel = function(path, startPath) {
    startPath = startPath || path;
    if (exports.isLevel(path)) return path;
    if (path == '/') return startPath;
    return exports.findLevel(PATH.dirname(path), startPath);
};

exports.fsWalkTree = function(root, fileCb, filterCb) {
    var files = FS.readdirSync(root);
    files.sort();
    while (files.length > 0) {
        var path = PATH.join(root, files.shift());
        if(filterCb && !filterCb(path)) continue;
        fileCb(path);
        if(exports.isDirectory(path)) exports.fsWalkTree(path, fileCb, filterCb);
    }
};

exports.getDirs = function(path) {
    try {
        return exports.isDirectory(path)?
            FS.readdirSync(path)
                .filter(function(d) {
                    return !(/^\.svn$/.test(d)) && exports.isDirectory(PATH.join(path, d));
                })
                .sort() :
            [];
    } catch (e) {
        return [];
    }
};

exports.getFiles = function(path) {
    try {
        return exports.isDirectory(path)?
            FS.readdirSync(path)
                .filter(function(f) {
                    return exports.isFile(PATH.join(path, f));
                })
                .sort() :
            [];
    } catch (e) {
        return [];
    }
};

exports.isEmptyObject = function(obj) {
    for(var i in obj) return false;
    return true;
};

exports.isRequireError = function(e) {
    return /^Cannot find module/.test(e.message);
};

exports.isPath = function(str) {
    return str.indexOf('/') !== -1;
};

exports.isRequireable = function(path) {
    try {
        require.resolve(path);
        return true;
    } catch (e) {
        if(! exports.isRequireError(e)) throw e;
        return false;
    }
};

exports.arrayUnique = function(arr) {
    return arr.reduce(function(prev, cur) {
        if(prev.indexOf(cur) + 1) return prev;
        return prev.concat([cur]);
    }, []);
};

exports.arrayReverse = function(arr) {
    return arr.reduceRight(function(prev, cur) {
        prev.push(cur);
        return prev;
    }, []);
};

exports.getBemTechPath = function(name) {
    var bemTechs = 'bem/lib/techs',
        path = PATH.join(bemTechs, name);
    if(exports.isRequireable(path)) {
        return path;
    }
    return 'bem/lib/tech';
};

exports.stripModuleExt = function(path) {
    var exts = Object.keys(require.extensions).map(function(v) {
        return v.replace(/^\./, '');
    });
    return path.replace(new RegExp('\\.(' + exts.join('|') + ')$'), '');
};

exports.getNodePaths = function() {
    return (process.env.NODE_PATH || '').split(process.platform === 'windows' ? ';' : ':');
};

exports.mergeDecls = function mergeDecls(d1, d2) {
    var keys = {};
    d1?
        d1.forEach(function(o) { keys[o.name || o] = o }) :
        d1 = [];

    d2.forEach(function(o2) {
        var name = o2.name || o2;
        if (keys.hasOwnProperty(name)) {
            var o1 = keys[name];
            o2.elems && (o1.elems = mergeDecls(o1.elems, o2.elems));
            o2.mods && (o1.mods = mergeDecls(o1.mods, o2.mods));
            o2.vals && (o1.vals = mergeDecls(o1.vals, o2.vals));
            o2.techs && (o1.techs = mergeDecls(o1.techs, o2.techs));
        } else {
            d1.push(o2);
            keys[name] = o2;
        }
    });

    return d1;
};
<|endoftext|>


<commit_before>/**
 * Sitespeed.io - How speedy is your site? (http://www.sitespeed.io)
 * Copyright (c) 2014, Peter Hedenskog, Tobias Lidskog
 * and other contributors
 * Released under the Apache 2.0 License
 */
var Stats = require('fast-stats').Stats,
    crypto = require('crypto'),
    config = require('./conf'),
    url = require('url');

module.exports = {
    /**
     * Get the cache time in seconds for a YSlow component
     * a.k.a asset.
     *
     *
     * @param {YSLOW.component} comp a component
     * @return {Integer} The cache time in seconds
     */
    getCacheTime: function(comp) {

        // This is how we do it: max-age will always win (HTTP 1.1)
        // If max-age is found use it, else expires
        // if no cache header, return 0
        var maxAgeRegExp = /max-age=(\d+)/,
            expireTime = 0;

        var response = comp.headers.response;
        for (var headerName in response) {
            if (! response.hasOwnProperty(headerName))
                continue;

            // Cache-control always wins before Expires
            // in the HTTP spec
            if ('cache-control' === headerName.toLowerCase()) {
                var cacheControl = response[headerName];
                if (cacheControl) {
                    if (cacheControl.indexOf('no-cache') !== -1 ||
                        cacheControl.indexOf('no-store') !== -1) {
                        return 0;
                    }
                    var matches = cacheControl.match(maxAgeRegExp);
                    if (matches) {
                        return parseInt(matches[1], 10);
                    }
                }

            } else if ('expires' === headerName.toLowerCase()) {
                var expiresDate = new Date(response[headerName]);
                var now = new Date().getTime();
                expireTime = expiresDate.getTime() - now;
            }
        }

        return expireTime;
    },

    /**
    * Get the cache time statistics for
    * all YSlow components.
    */
    getCacheTimeStats: function(components) {
      var stats = new Stats();

      components.forEach(function(comp) {
        stats.push(module.exports.getCacheTime(comp));
      });

      return module.exports.getStatisticsObject(stats,0);
    },

    /**
    * Get the last modification time statistics for
    * all YSlow components.
    */
    getLastModStats: function(components) {
      var stats = new Stats();

      components.forEach(function(comp) {
        stats.push(module.exports.getTimeSinceLastMod(comp));
      });

      return module.exports.getStatisticsObject(stats,0);
    },

    /**
     * Get the time in seconds since a component was
     * last modified. If the server doesn't send a
     * last-modified header, the modified time will
     * be set to now.
     *
     *
     * @param the YSlow component
     * @return {Integer} The time in seconds or -1 if unknown
     */
    getTimeSinceLastMod: function(comp) {
        var now = new Date();
        var lastModifiedDate;
        var response = comp.headers.response;
        for (var headerName in response) {
            if (! response.hasOwnProperty(headerName))
                continue;

            if ('last-modified' === headerName.toLowerCase()) {
                lastModifiedDate = new Date(response[headerName]);
            } else if ('date' === headerName.toLowerCase()) {
                now = new Date(response[headerName]);
            }
        }

        // TODO how do we define this?
        if (!lastModifiedDate)
          return -1;

        return (now.getTime() - lastModifiedDate.getTime()) / 1000;
    },

    /**
     * Print seconds as the largest available time.
     * @param {Integer} seconds A number in seconds
     * @return {String} The time in nearest largest definition.
     */
    prettyPrintSeconds: function(seconds) {

      if (seconds === -1) return -1;

      var secondsPerYear = 365 * 24 * 60 * 60,
        secondsPerWeek = 60 * 60 * 24 * 7,
        secondsPerDay = 60 * 60 * 24,
        secondsPerHour = 60 * 60,
        secondsPerMinute = 60,
        sign = (seconds < 0) ? "-" : "";

      if (seconds < 0)
        seconds = Math.abs(seconds);

      if (seconds / secondsPerYear >= 1)
        return sign + Math.round(seconds / secondsPerYear) + " year" + ((Math.round(
          seconds / secondsPerYear) > 1) ? "s" : "");
      else if (seconds / secondsPerWeek >= 1)
        return sign + Math.round(seconds / secondsPerWeek) + " week" + ((Math.round(
          seconds / secondsPerWeek) > 1) ? "s" : "");
      else if (seconds / secondsPerDay >= 1)
        return sign + Math.round(seconds / secondsPerDay) + " day" + ((Math.round(
          seconds / secondsPerDay) > 1) ? "s" : "");
      else if (seconds / secondsPerHour >= 1)
        return sign + Math.round(seconds / secondsPerHour) + " hour" + ((Math.round(
          seconds / secondsPerHour) > 1) ? "s" : "");
      else if (seconds / secondsPerMinute >= 1)
        return sign + Math.round(seconds / secondsPerMinute) + " minute" + ((
          Math.round(seconds / secondsPerMinute) > 1) ? "s" : "");
      else return sign + seconds + " second" + ((seconds > 1) ? "s" : "");
    },

    /**
    * Get seconds, milliseconds or bytes in a human readable format.
    * Will turn seconds into the largest avalible time format (minutes, hours etc),
    * add ms to milliseconds and turn bytes into kiloytes.
    */
    getHumanReadable: function(data, value, showUnit) {
        if (data.unit === 'seconds')
            return this.prettyPrintSeconds(value);
        else if (data.unit === 'milliseconds')
           return value + (showUnit ? ' ms':'');
        else if (data.unit === 'bytes')
            return this.getKbSize(value, showUnit);
        else return value;
    },

    /**
    * If we have a matching rule definition, we will return the
    * matching Bootstrap CSS name, so that the CSS will have the right color.
    */
    getRuleColor: function(rule, value) {
        if (config.rules[rule]) {
          var diff = config.rules[rule].warning - config.rules[rule].error;
          if (diff > 0) {
            if (value>config.rules[rule].warning)
              return 'success';
            else if (value>config.rules[rule].error)
              return 'warning';
            return 'danger';
          }
          else {
            if (value<config.rules[rule].warning)
              return 'success';
            else if (value<config.rules[rule].error)
              return 'warning';
            return 'danger';
          }

        }
        // no matching rule
        return 'info';
        },

    /**
     * Summarize the size from multiple components.
     **/
    getSize: function(components) {
        return components.filter(function(comp) {
            return comp.size != '-1';
        }).reduce(function(sum, comp) {
            return sum + comp.size;
        }, 0);
    },

    /**
    * Make bytes human readable by turning it into kilobytes and
    * adding the String kb to the result.
    */
    getKbSize: function(size, showUnit) {
        // if we don't have any values in the stats
        if (isNaN(size))
          return 0 + ' kb';
        var remainder = size % (size > 100 ? 100 : 10);
        size -= remainder;
        return parseFloat(size / 1000) + (0 === (size % 1000) ? ".0" : "") + (showUnit?' kb':'');
    },

     select: function(object, keyPath, defaultValue) {
       return keyPath.split('.').reduce(function (result, key) {
         result = result[key];
         return result || defaultValue;
       }, object);
     },

    decodeURIComponent: function(value) {
        try {
            return decodeURIComponent(value);
        } catch (err) {
            return value;
        }
    },

    /**
    * Get the URL as a hash so it can be stored on disk.
    */
    getUrlHash: function(u) {
        var urlComponents = url.parse(u);
        var hash = crypto.createHash('md5').update(u).digest('hex').substr(0, 7);
        var name = urlComponents.pathname;
        if (name == '/') {
            name = urlComponents.hostname;
        } else {
            name = name.replace(/^\/|\/$/g, '').split('/').pop();
            name = name.split('.')[0];
        }
        return encodeURIComponent(name) + '-' + hash;
    },

    /**
    * Get the hostname from a URL String
    */
    getHostname: function(u) {
        u = this.decodeURIComponent(u);
        var hostname = u.split('/')[2];
        return (hostname && hostname.split(':')[0]) || '';
    },

    /**
    * Get a usable view of the statistics object. Will format the
    * result to decimals.
    */
    getStatisticsObject: function(stats, decimals) {
        return {
            min: stats.percentile(0).toFixed(decimals),
            max: stats.percentile(100).toFixed(decimals),
            p10: stats.percentile(10).toFixed(decimals),
            p70: stats.percentile(70).toFixed(decimals),
            p80: stats.percentile(80).toFixed(decimals),
            p90: stats.percentile(90).toFixed(decimals),
            p99: stats.percentile(99).toFixed(decimals),
            median: stats.median().toFixed(decimals),
            mean: stats.amean().toFixed(decimals)
        };
    },

    /**
    * Get the number of domains used for YSlow
    * components
    */
    getNumberOfDomains: function(components) {
        var self = this;
        var domains = this.aggregate(components,
            function (comp) {
                return self.getHostname(comp.url);
            }
        );

      return Object.keys(domains).length;
    },

  timingMetricsDefinition: {
        "firstPaintTime": "This is when the first paint happens on the screen, reported by the browser.",
        "serverConnectionTime": 'How long time it takes to connect to the server. Definition: connectEnd - connectStart',
        "domainLookupTime": 'The time it takes to do the DNS lookup. Definition: domainLookupEnd - domainLookupStart',
        "pageLoadTime": 'The time it takes for page to load, from initiation of the pageview (e.g., click on a page link) to load completion in the browser. Important: this is only relevant to some pages, depending on how you page is built. Definition: loadEventStart - navigationStart',
        "pageDownloadTime":'How long time does it take to download the page (the HTML). Definition: responseEnd - responseStart',
        "serverResponseTime": 'How long time does it take until the server respond. Definition: responseStart - requestStart',
        "domContentLoadedTime": "The time the browser takes to parse the document and execute deferred and parser-inserted scripts including the network time from the user's location to your server. Definition: domContentLoadedEventStart - navigationStart",
        "domInteractiveTime": "The time the browser takes to parse the document, including the network time from the user's location to your server. Definition: domInteractive - navigationStart",
        "redirectionTime": "Time spent on redirects. Definition: fetchStart - navigationStart",
        "backEndTime": 'The time it takes for the network and the server to generate and start sending the HTML. Definition: responseStart - navigationStart',
        "frontEndTime": 'The time it takes for the browser to parse and create the page. Definition: loadEventStart - responseEnd'
      },

  /**
  * Get the size in bytes for a specific domain
  */
  getSizeForDomain: function (domain, components) {
      var self = this;
      var hostAndSize = this.aggregate(components,
          function (comp) {
              return self.getHostname(comp.url);
          },
          function (comp) {
              return comp.size;
          }
      );

    return hostAndSize[domain];
  },

  /**
  * Get the number of assets per domain.
  */
  getAssetsPerDomain: function(components) {
      var self = this;
      return this.aggregate(components, function (comp) {
          return self.getHostname(comp.url);
      });
  },

  /**
  * Get the number of assets per content type.
  */
  getAssetsPerContentType: function(components) {
      return this.aggregate(components, function (comp) {
          return comp.type;
      });
  },

  /**
  * Get the size in bytes per content type.
  */
  getAssetsSizePerContentType: function(components) {
      return this.aggregate(components,
          function (comp) {
              return comp.type;
          },
          function (comp) {
              return comp.size;
          }
      );
  },

  aggregate: function (array, keyFunction, valueFunction) {
      return array.reduce(function (result, item) {
          var key = keyFunction ? keyFunction(item) : item;
          var value = valueFunction ? valueFunction(item) : 1;

          if (result.hasOwnProperty(key)) {
              result[key] += value;
          } else {
              result[key] = value;
          }
          return result;
      }, {});
  },

  /**
   * Hack to format Google Page Speed Insights result
   *
   **/
  gpsiReplacer: function(args, text) {

    if (args.length === 1) {
      return text.replace('$1', args[0].value);
    } else if (args.length === 2) {
      return text.replace('$1', args[0].value).replace('$2', args[1].value);
    } else if (args.length === 3) {
      return text.replace('$1', args[0].value).replace('$2', args[1].value).replace(
        '$3', args[2].value);
    } else return text;
  },

  /**
  * Get the URL from pageData.
  */
  getURLFromPageData: function(pageData) {
    if (pageData.yslow)
      return pageData.yslow.originalUrl;
    else if (pageData.browsertime)
      return pageData.browsertime[0].pageData.url;
    else if (pageData.gpsi)
    return pageData.gpsi.id;
    return 'undefined';
  },

  getGraphiteURLKey: function(theUrl) {
  myUrl = url.parse(theUrl);
  var protocol = myUrl.protocol.replace(':', '');
  var hostname = myUrl.hostname;
  var path = myUrl.pathname;

  if (path.indexOf(".") > -1) path = path.replace(".", "_");
  if (path.indexOf("~") > -1) path = path.replace("~", "_");

  if (path === '' || path === '/')
    return protocol + '.' + hostname + '.slash.';

  var key = protocol + '.' + hostname + '.' + path.replace('/', '.');
  if (key.indexOf('.', key.length - 1) !== -1)
    return key;
  else return key + '.';

}
};
<commit_msg>pretty 0 seconds, not 0 second<commit_after>/**
 * Sitespeed.io - How speedy is your site? (http://www.sitespeed.io)
 * Copyright (c) 2014, Peter Hedenskog, Tobias Lidskog
 * and other contributors
 * Released under the Apache 2.0 License
 */
var Stats = require('fast-stats').Stats,
    crypto = require('crypto'),
    config = require('./conf'),
    url = require('url');

module.exports = {
    /**
     * Get the cache time in seconds for a YSlow component
     * a.k.a asset.
     *
     *
     * @param {YSLOW.component} comp a component
     * @return {Integer} The cache time in seconds
     */
    getCacheTime: function(comp) {

        // This is how we do it: max-age will always win (HTTP 1.1)
        // If max-age is found use it, else expires
        // if no cache header, return 0
        var maxAgeRegExp = /max-age=(\d+)/,
            expireTime = 0;

        var response = comp.headers.response;
        for (var headerName in response) {
            if (! response.hasOwnProperty(headerName))
                continue;

            // Cache-control always wins before Expires
            // in the HTTP spec
            if ('cache-control' === headerName.toLowerCase()) {
                var cacheControl = response[headerName];
                if (cacheControl) {
                    if (cacheControl.indexOf('no-cache') !== -1 ||
                        cacheControl.indexOf('no-store') !== -1) {
                        return 0;
                    }
                    var matches = cacheControl.match(maxAgeRegExp);
                    if (matches) {
                        return parseInt(matches[1], 10);
                    }
                }

            } else if ('expires' === headerName.toLowerCase()) {
                var expiresDate = new Date(response[headerName]);
                var now = new Date().getTime();
                expireTime = expiresDate.getTime() - now;
            }
        }

        return expireTime;
    },

    /**
    * Get the cache time statistics for
    * all YSlow components.
    */
    getCacheTimeStats: function(components) {
      var stats = new Stats();

      components.forEach(function(comp) {
        stats.push(module.exports.getCacheTime(comp));
      });

      return module.exports.getStatisticsObject(stats,0);
    },

    /**
    * Get the last modification time statistics for
    * all YSlow components.
    */
    getLastModStats: function(components) {
      var stats = new Stats();

      components.forEach(function(comp) {
        stats.push(module.exports.getTimeSinceLastMod(comp));
      });

      return module.exports.getStatisticsObject(stats,0);
    },

    /**
     * Get the time in seconds since a component was
     * last modified. If the server doesn't send a
     * last-modified header, the modified time will
     * be set to now.
     *
     *
     * @param the YSlow component
     * @return {Integer} The time in seconds or -1 if unknown
     */
    getTimeSinceLastMod: function(comp) {
        var now = new Date();
        var lastModifiedDate;
        var response = comp.headers.response;
        for (var headerName in response) {
            if (! response.hasOwnProperty(headerName))
                continue;

            if ('last-modified' === headerName.toLowerCase()) {
                lastModifiedDate = new Date(response[headerName]);
            } else if ('date' === headerName.toLowerCase()) {
                now = new Date(response[headerName]);
            }
        }

        // TODO how do we define this?
        if (!lastModifiedDate)
          return -1;

        return (now.getTime() - lastModifiedDate.getTime()) / 1000;
    },

    /**
     * Print seconds as the largest available time.
     * @param {Integer} seconds A number in seconds
     * @return {String} The time in nearest largest definition.
     */
    prettyPrintSeconds: function(seconds) {

      if (seconds === -1) return -1;

      var secondsPerYear = 365 * 24 * 60 * 60,
        secondsPerWeek = 60 * 60 * 24 * 7,
        secondsPerDay = 60 * 60 * 24,
        secondsPerHour = 60 * 60,
        secondsPerMinute = 60,
        sign = (seconds < 0) ? "-" : "";

      if (seconds < 0)
        seconds = Math.abs(seconds);

      if (seconds / secondsPerYear >= 1)
        return sign + Math.round(seconds / secondsPerYear) + " year" + ((Math.round(
          seconds / secondsPerYear) > 1) ? "s" : "");
      else if (seconds / secondsPerWeek >= 1)
        return sign + Math.round(seconds / secondsPerWeek) + " week" + ((Math.round(
          seconds / secondsPerWeek) > 1) ? "s" : "");
      else if (seconds / secondsPerDay >= 1)
        return sign + Math.round(seconds / secondsPerDay) + " day" + ((Math.round(
          seconds / secondsPerDay) > 1) ? "s" : "");
      else if (seconds / secondsPerHour >= 1)
        return sign + Math.round(seconds / secondsPerHour) + " hour" + ((Math.round(
          seconds / secondsPerHour) > 1) ? "s" : "");
      else if (seconds / secondsPerMinute >= 1)
        return sign + Math.round(seconds / secondsPerMinute) + " minute" + ((
          Math.round(seconds / secondsPerMinute) > 1) ? "s" : "");
      else return sign + seconds + " second" + ((seconds > 1 || seconds === 0) ? "s" : "");
    },

    /**
    * Get seconds, milliseconds or bytes in a human readable format.
    * Will turn seconds into the largest avalible time format (minutes, hours etc),
    * add ms to milliseconds and turn bytes into kiloytes.
    */
    getHumanReadable: function(data, value, showUnit) {
        if (data.unit === 'seconds')
            return this.prettyPrintSeconds(value);
        else if (data.unit === 'milliseconds')
           return value + (showUnit ? ' ms':'');
        else if (data.unit === 'bytes')
            return this.getKbSize(value, showUnit);
        else return value;
    },

    /**
    * If we have a matching rule definition, we will return the
    * matching Bootstrap CSS name, so that the CSS will have the right color.
    */
    getRuleColor: function(rule, value) {
        if (config.rules[rule]) {
          var diff = config.rules[rule].warning - config.rules[rule].error;
          if (diff > 0) {
            if (value>config.rules[rule].warning)
              return 'success';
            else if (value>config.rules[rule].error)
              return 'warning';
            return 'danger';
          }
          else {
            if (value<config.rules[rule].warning)
              return 'success';
            else if (value<config.rules[rule].error)
              return 'warning';
            return 'danger';
          }

        }
        // no matching rule
        return 'info';
        },

    /**
     * Summarize the size from multiple components.
     **/
    getSize: function(components) {
        return components.filter(function(comp) {
            return comp.size != '-1';
        }).reduce(function(sum, comp) {
            return sum + comp.size;
        }, 0);
    },

    /**
    * Make bytes human readable by turning it into kilobytes and
    * adding the String kb to the result.
    */
    getKbSize: function(size, showUnit) {
        // if we don't have any values in the stats
        if (isNaN(size))
          return 0 + ' kb';
        var remainder = size % (size > 100 ? 100 : 10);
        size -= remainder;
        return parseFloat(size / 1000) + (0 === (size % 1000) ? ".0" : "") + (showUnit?' kb':'');
    },

     select: function(object, keyPath, defaultValue) {
       return keyPath.split('.').reduce(function (result, key) {
         result = result[key];
         return result || defaultValue;
       }, object);
     },

    decodeURIComponent: function(value) {
        try {
            return decodeURIComponent(value);
        } catch (err) {
            return value;
        }
    },

    /**
    * Get the URL as a hash so it can be stored on disk.
    */
    getUrlHash: function(u) {
        var urlComponents = url.parse(u);
        var hash = crypto.createHash('md5').update(u).digest('hex').substr(0, 7);
        var name = urlComponents.pathname;
        if (name == '/') {
            name = urlComponents.hostname;
        } else {
            name = name.replace(/^\/|\/$/g, '').split('/').pop();
            name = name.split('.')[0];
        }
        return encodeURIComponent(name) + '-' + hash;
    },

    /**
    * Get the hostname from a URL String
    */
    getHostname: function(u) {
        u = this.decodeURIComponent(u);
        var hostname = u.split('/')[2];
        return (hostname && hostname.split(':')[0]) || '';
    },

    /**
    * Get a usable view of the statistics object. Will format the
    * result to decimals.
    */
    getStatisticsObject: function(stats, decimals) {
        return {
            min: stats.percentile(0).toFixed(decimals),
            max: stats.percentile(100).toFixed(decimals),
            p10: stats.percentile(10).toFixed(decimals),
            p70: stats.percentile(70).toFixed(decimals),
            p80: stats.percentile(80).toFixed(decimals),
            p90: stats.percentile(90).toFixed(decimals),
            p99: stats.percentile(99).toFixed(decimals),
            median: stats.median().toFixed(decimals),
            mean: stats.amean().toFixed(decimals)
        };
    },

    /**
    * Get the number of domains used for YSlow
    * components
    */
    getNumberOfDomains: function(components) {
        var self = this;
        var domains = this.aggregate(components,
            function (comp) {
                return self.getHostname(comp.url);
            }
        );

      return Object.keys(domains).length;
    },

  timingMetricsDefinition: {
        "firstPaintTime": "This is when the first paint happens on the screen, reported by the browser.",
        "serverConnectionTime": 'How long time it takes to connect to the server. Definition: connectEnd - connectStart',
        "domainLookupTime": 'The time it takes to do the DNS lookup. Definition: domainLookupEnd - domainLookupStart',
        "pageLoadTime": 'The time it takes for page to load, from initiation of the pageview (e.g., click on a page link) to load completion in the browser. Important: this is only relevant to some pages, depending on how you page is built. Definition: loadEventStart - navigationStart',
        "pageDownloadTime":'How long time does it take to download the page (the HTML). Definition: responseEnd - responseStart',
        "serverResponseTime": 'How long time does it take until the server respond. Definition: responseStart - requestStart',
        "domContentLoadedTime": "The time the browser takes to parse the document and execute deferred and parser-inserted scripts including the network time from the user's location to your server. Definition: domContentLoadedEventStart - navigationStart",
        "domInteractiveTime": "The time the browser takes to parse the document, including the network time from the user's location to your server. Definition: domInteractive - navigationStart",
        "redirectionTime": "Time spent on redirects. Definition: fetchStart - navigationStart",
        "backEndTime": 'The time it takes for the network and the server to generate and start sending the HTML. Definition: responseStart - navigationStart',
        "frontEndTime": 'The time it takes for the browser to parse and create the page. Definition: loadEventStart - responseEnd'
      },

  /**
  * Get the size in bytes for a specific domain
  */
  getSizeForDomain: function (domain, components) {
      var self = this;
      var hostAndSize = this.aggregate(components,
          function (comp) {
              return self.getHostname(comp.url);
          },
          function (comp) {
              return comp.size;
          }
      );

    return hostAndSize[domain];
  },

  /**
  * Get the number of assets per domain.
  */
  getAssetsPerDomain: function(components) {
      var self = this;
      return this.aggregate(components, function (comp) {
          return self.getHostname(comp.url);
      });
  },

  /**
  * Get the number of assets per content type.
  */
  getAssetsPerContentType: function(components) {
      return this.aggregate(components, function (comp) {
          return comp.type;
      });
  },

  /**
  * Get the size in bytes per content type.
  */
  getAssetsSizePerContentType: function(components) {
      return this.aggregate(components,
          function (comp) {
              return comp.type;
          },
          function (comp) {
              return comp.size;
          }
      );
  },

  aggregate: function (array, keyFunction, valueFunction) {
      return array.reduce(function (result, item) {
          var key = keyFunction ? keyFunction(item) : item;
          var value = valueFunction ? valueFunction(item) : 1;

          if (result.hasOwnProperty(key)) {
              result[key] += value;
          } else {
              result[key] = value;
          }
          return result;
      }, {});
  },

  /**
   * Hack to format Google Page Speed Insights result
   *
   **/
  gpsiReplacer: function(args, text) {

    if (args.length === 1) {
      return text.replace('$1', args[0].value);
    } else if (args.length === 2) {
      return text.replace('$1', args[0].value).replace('$2', args[1].value);
    } else if (args.length === 3) {
      return text.replace('$1', args[0].value).replace('$2', args[1].value).replace(
        '$3', args[2].value);
    } else return text;
  },

  /**
  * Get the URL from pageData.
  */
  getURLFromPageData: function(pageData) {
    if (pageData.yslow)
      return pageData.yslow.originalUrl;
    else if (pageData.browsertime)
      return pageData.browsertime[0].pageData.url;
    else if (pageData.gpsi)
    return pageData.gpsi.id;
    return 'undefined';
  },

  getGraphiteURLKey: function(theUrl) {
  myUrl = url.parse(theUrl);
  var protocol = myUrl.protocol.replace(':', '');
  var hostname = myUrl.hostname;
  var path = myUrl.pathname;

  if (path.indexOf(".") > -1) path = path.replace(".", "_");
  if (path.indexOf("~") > -1) path = path.replace("~", "_");

  if (path === '' || path === '/')
    return protocol + '.' + hostname + '.slash.';

  var key = protocol + '.' + hostname + '.' + path.replace('/', '.');
  if (key.indexOf('.', key.length - 1) !== -1)
    return key;
  else return key + '.';

}
};
<|endoftext|>


<commit_before>(function (env) {
    "use strict";
    env.ddg_spice_near_earth_objects = function(api_result) {

        if (!api_result || !api_result.near_earth_objects || api_result.near_earth_objects.length === 0 || api_result.element_count === 0) {
            return Spice.failed('near_earth_objects');
        }

        // Put all NEOs into a single array
        var neo_list = [];
        for (var obj in api_result.near_earth_objects) {
            if (api_result.near_earth_objects.hasOwnProperty(obj)) {
                neo_list = neo_list.concat(api_result.near_earth_objects[obj]);
            }
        }

        // Render the response
        var result_text = (neo_list.length === 1) ? ' near earth object (asteroid)' : ' near earth objects (asteroids)';
        Spice.add({
            id: "near_earth_objects",
            name: "Answer",
            data: neo_list,

            meta: {
                sourceName: 'NASA',
                sourceUrl: 'http://neo.jpl.nasa.gov/',
                primaryText: 'Showing ' + neo_list.length + result_text
            },

            normalize: function(item) {
                // Format numbers first
                var distMiles = DDG.commifyNumber(DDG.abbrevNumber(item.close_approach_data[0].miss_distance.miles));
                var distKm = DDG.commifyNumber(DDG.abbrevNumber(item.close_approach_data[0].miss_distance.kilometers));
                var maxSizeMeters = DDG.commifyNumber(Math.round(item.estimated_diameter.meters.estimated_diameter_max));
                var maxSizeFeet = DDG.commifyNumber(Math.round(item.estimated_diameter.feet.estimated_diameter_max));

                return {
                    url: item.nasa_jpl_url,
                    title: item.name,
                    altSubtitle: 'SPK-ID: ' + item.neo_reference_id,
                    subtitle: 'Approach date: ' + item.close_approach_data[0].close_approach_date,
                    description: 'Has a diameter of up to ' + maxSizeMeters + ' meters (' + maxSizeFeet + ' feet) and will miss earth by ' + distKm + ' km (' + distMiles + ' miles).',
                };
            },

            templates: {
                group: 'text',
                detail: false,
                item_detail: false,
                variants: {
                    tileSubtitle: "1line"
                }
            }
        });
    };
}(this));
<commit_msg>Adding 'high' signal<commit_after>(function (env) {
    "use strict";
    env.ddg_spice_near_earth_objects = function(api_result) {

        if (!api_result || !api_result.near_earth_objects || api_result.near_earth_objects.length === 0 || api_result.element_count === 0) {
            return Spice.failed('near_earth_objects');
        }

        // Put all NEOs into a single array
        var neo_list = [];
        for (var obj in api_result.near_earth_objects) {
            if (api_result.near_earth_objects.hasOwnProperty(obj)) {
                neo_list = neo_list.concat(api_result.near_earth_objects[obj]);
            }
        }

        // Render the response
        var result_text = (neo_list.length === 1) ? ' near earth object (asteroid)' : ' near earth objects (asteroids)';
        Spice.add({
            id: "near_earth_objects",
            name: "Answer",
            data: neo_list,

            meta: {
                sourceName: 'NASA',
                sourceUrl: 'http://neo.jpl.nasa.gov/',
                primaryText: 'Showing ' + neo_list.length + result_text,
                signal: 'high'
            },

            normalize: function(item) {
                // Format numbers first
                var distMiles = DDG.commifyNumber(DDG.abbrevNumber(item.close_approach_data[0].miss_distance.miles));
                var distKm = DDG.commifyNumber(DDG.abbrevNumber(item.close_approach_data[0].miss_distance.kilometers));
                var maxSizeMeters = DDG.commifyNumber(Math.round(item.estimated_diameter.meters.estimated_diameter_max));
                var maxSizeFeet = DDG.commifyNumber(Math.round(item.estimated_diameter.feet.estimated_diameter_max));

                return {
                    url: item.nasa_jpl_url,
                    title: item.name,
                    altSubtitle: 'SPK-ID: ' + item.neo_reference_id,
                    subtitle: 'Approach date: ' + item.close_approach_data[0].close_approach_date,
                    description: 'Has a diameter of up to ' + maxSizeMeters + ' meters (' + maxSizeFeet + ' feet) and will miss earth by ' + distKm + ' km (' + distMiles + ' miles).',
                };
            },

            templates: {
                group: 'text',
                detail: false,
                item_detail: false,
                variants: {
                    tileSubtitle: "1line"
                }
            }
        });
    };
}(this));
<|endoftext|>


<commit_before>describe("About Arrays", function() {

  // We shall contemplate truth by testing reality, via spec expectations.
  it("should create arrays", function() {
    var emptyArray = [];
    expect(typeof(emptyArray)).toBe(FILL_ME_IN); // A mistake?-- http:javascript.crockford.com/remedial.html
    expect(emptyArray.length).toBe(FILL_ME_IN);

    var multiTypeArray = [0, 1, "two", function() { return 3; }, {value1: 4, value2: 5}, [6, 7]];
    expect(multiTypeArray[0]).toBe(FILL_ME_IN);
    expect(multiTypeArray[2]).toBe(FILL_ME_IN);
    expect(multiTypeArray[3]()).toBe(FILL_ME_IN);
    expect(multiTypeArray[4].value1).toBe(FILL_ME_IN);
    expect(multiTypeArray[4]["value2"]).toBe(FILL_ME_IN);
    expect(multiTypeArray[5][0]).toBe(FILL_ME_IN);
  });

  it("should understand array literals", function() {
    var array = [];
    expect(array).toEqual([]);

    array[0] = 1;
    expect(array).toEqual([1]);

    array[1] = 2;
    expect(array).toEqual([1, FILL_ME_IN]);

    array.push(3);
    expect(array).toEqual(FILL_ME_IN);
  });

  it("should understand array length", function() {
    var fourNumberArray = [1, 2, 3, 4];

    expect(fourNumberArray.length).toBe(FILL_ME_IN);
    fourNumberArray.push(5, 6);
    expect(fourNumberArray.length).toBe(FILL_ME_IN);

    var tenEmptyElementArray = new Array(10);
    expect(tenEmptyElementArray.length).toBe(FILL_ME_IN);

    tenEmptyElementArray.length = 5;
    expect(tenEmptyElementArray.length).toBe(FILL_ME_IN);
  });

  it("should slice arrays", function() {
    var array = ["peanut", "butter", "and", "jelly"];

    expect(array.slice(0, 1)).toEqual(FILL_ME_IN);
    expect(array.slice(0, 2)).toEqual(FILL_ME_IN);
    expect(array.slice(2, 2)).toEqual(FILL_ME_IN);
    expect(array.slice(2, 20)).toEqual(FILL_ME_IN);
    expect(array.slice(3, 0)).toEqual(FILL_ME_IN);
    expect(array.slice(3, 100)).toEqual(FILL_ME_IN);
    expect(array.slice(5, 1)).toEqual(FILL_ME_IN);
  });

  it("should know array references", function() {
    var array = [ "zero", "one", "two", "three", "four", "five" ];

    function passedByReference(refArray) {
      refArray[1] = "changed in function";
    }
    passedByReference(array);
    expect(array[1]).toBe(FILL_ME_IN);

    var assignedArray = array;
    assignedArray[5] = "changed in assignedArray";
    expect(array[5]).toBe(FILL_ME_IN);

    var copyOfArray = array.slice();
    copyOfArray[3] = "changed in copyOfArray";
    expect(array[3]).toBe(FILL_ME_IN);
  });

  it("should push and pop", function() {
    var array = [1, 2];
    array.push(3);

    expect(array).toEqual(FILL_ME_IN);

    var poppedValue = array.pop();
    expect(poppedValue).toBe(FILL_ME_IN);
    expect(array).toEqual(FILL_ME_IN);
  });

  it("should know about shifting arrays", function() {
    var array = [1, 2];

    array.unshift(3);
    expect(array).toEqual(FILL_ME_IN);

    var shiftedValue = array.shift();
    expect(shiftedValue).toEqual(FILL_ME_IN);
    expect(array).toEqual(FILL_ME_IN);
  });
});
<commit_msg>Modified AboutArrays so that all sections passed<commit_after>describe("About Arrays", function() {

  // We shall contemplate truth by testing reality, via spec expectations.
  it("should create arrays", function() {
    var emptyArray = [];
    expect(typeof(emptyArray)).toBe('object'); // A mistake?-- http:javascript.crockford.com/remedial.html
    expect(emptyArray.length).toBe(0);

    var multiTypeArray = [0, 1, "two", function() { return 3; }, {value1: 4, value2: 5}, [6, 7]];
    expect(multiTypeArray[0]).toBe(0);
    expect(multiTypeArray[2]).toBe("two");
    expect(multiTypeArray[3]()).toBe(3);
    expect(multiTypeArray[4].value1).toBe(4);
    expect(multiTypeArray[4]["value2"]).toBe(5);
    expect(multiTypeArray[5][0]).toBe(6);
  });

  it("should understand array literals", function() {
    var array = [];
    expect(array).toEqual([]);

    array[0] = 1;
    expect(array).toEqual([1]);

    array[1] = 2;
    expect(array).toEqual([1, 2]);

    array.push(3);
    expect(array).toEqual([1, 2, 3]);
  });

  it("should understand array length", function() {
    var fourNumberArray = [1, 2, 3, 4];

    expect(fourNumberArray.length).toBe(4);
    fourNumberArray.push(5, 6);
    expect(fourNumberArray.length).toBe(6);

    var tenEmptyElementArray = new Array(10);
    expect(tenEmptyElementArray.length).toBe(10);

    tenEmptyElementArray.length = 5;
    expect(tenEmptyElementArray.length).toBe(5);
  });

  it("should slice arrays", function() {
    var array = ["peanut", "butter", "and", "jelly"];

    expect(array.slice(0, 1)).toEqual(["peanut"]);
    expect(array.slice(0, 2)).toEqual(["peanut", "butter"]);
    expect(array.slice(2, 2)).toEqual([]);
    expect(array.slice(2, 20)).toEqual(["and", "jelly"]);
    expect(array.slice(3, 0)).toEqual([]);
    expect(array.slice(3, 100)).toEqual(["jelly"]);
    expect(array.slice(5, 1)).toEqual([]);
  });

  it("should know array references", function() {
    var array = [ "zero", "one", "two", "three", "four", "five" ];

    function passedByReference(refArray) {
      refArray[1] = "changed in function";
    }
    passedByReference(array);
    expect(array[1]).toBe("changed in function");

    var assignedArray = array;
    assignedArray[5] = "changed in assignedArray";
    expect(array[5]).toBe("changed in assignedArray");

    var copyOfArray = array.slice();
    copyOfArray[3] = "changed in copyOfArray";
    expect(array[3]).toBe("three");
  });

  it("should push and pop", function() {
    var array = [1, 2];
    array.push(3);

    expect(array).toEqual([1, 2, 3]);

    var poppedValue = array.pop();
    expect(poppedValue).toBe(3);
    expect(array).toEqual([1, 2]);
  });

  it("should know about shifting arrays", function() {
    var array = [1, 2];

    array.unshift(3);
    expect(array).toEqual([3, 1, 2]);

    var shiftedValue = array.shift();
    expect(shiftedValue).toEqual(3);
    expect(array).toEqual([1, 2]);
  });
});
<|endoftext|>


<commit_before>'use strict';

var _slice = Array.prototype.slice;

exports = module.exports = {};

// dependencies
//
exports.type = require('utils-type');
exports.merge = require('lodash.merge');
exports.inherits = require('inherits');
exports.asyncDone = require('async-done');

// assorted
//

exports.slice = function slice(args, index, top){
  return _slice.call(args, index, top);
};

exports.mapPush = function mapPush(argv, args, pos){
  if(!args.length){ return argv; }

  pos = (Number(pos) || 0) - 1;
  var top = argv.length;
  var len = args.length;

  var index = -1;
  while(++pos < len){
    if(++index < top){
      argv[index] = args[pos];
    } else {
      argv.push(args[pos]);
    }
  }

  return argv;
};

exports.classFactory = function classFactory(SuperCtor){
  return function extendsConstructor(mixin){
    function Ctor(props){
      if(!(this instanceof Ctor)){
        return new Ctor(props);
      }
      SuperCtor.apply(this, arguments);
    }
    exports.inherits(Ctor, SuperCtor);
    exports.merge(Ctor.prototype, exports.type(mixin).plainObject);
    return Ctor;
  };
};
<commit_msg>dev: added util.isFunction to filter down elements for newly created stacks<commit_after>'use strict';

var _slice = Array.prototype.slice;

exports = module.exports = {};

// dependencies
//
exports.type = require('utils-type');
exports.merge = require('lodash.merge');
exports.inherits = require('inherits');
exports.asyncDone = require('async-done');

// assorted
//

exports.slice = function slice(args, index, top){
  return _slice.call(args, index, top);
};

exports.mapPush = function mapPush(argv, args, pos){
  if(!args.length){ return argv; }

  pos = (Number(pos) || 0) - 1;
  var top = argv.length;
  var len = args.length;

  var index = -1;
  while(++pos < len){
    if(++index < top){
      argv[index] = args[pos];
    } else {
      argv.push(args[pos]);
    }
  }

  return argv;
};

exports.isFunction = function(value){
  return value && typeof value === 'function';
};

exports.classFactory = function classFactory(SuperCtor){
  return function extendsConstructor(mixin){
    function Ctor(props){
      if(!(this instanceof Ctor)){
        return new Ctor(props);
      }
      SuperCtor.apply(this, arguments);
    }
    exports.inherits(Ctor, SuperCtor);
    exports.merge(Ctor.prototype, exports.type(mixin).plainObject);
    return Ctor;
  };
};
<|endoftext|>


<commit_before>describe("About Arrays", function() {

  //We shall contemplate truth by testing reality, via spec expectations.
  it("should create arrays", function() {
    var emptyArray = [];
    expect(typeof(emptyArray)).toBe("object"); //A mistake? - http://javascript.crockford.com/remedial.html
    expect(emptyArray.length).toBe(0);

    var multiTypeArray = [0, 1, "two", function () { return 3; }, {value1: 4, value2: 5}, [6, 7]];
    expect(multiTypeArray[0]).toBe(0);
    expect(multiTypeArray[2]).toBe("two");
    expect(multiTypeArray[3]()).toBe(3);
    expect(multiTypeArray[4].value1).toBe(4);
    expect(multiTypeArray[4]["value2"]).toBe(5);
    expect(multiTypeArray[5][0]).toBe(6);
  });

  it("should understand array literals", function () {
    var array = [];
    expect(array).toEqual([]);

    array[0] = 1;
    expect(array).toEqual([1]);

    array[1] = 2;
    expect(array).toEqual([1, 2]);

    array.push(3);
    expect(array).toEqual([1,2,3]);
  });

  it("should understand array length", function () {
    var fourNumberArray = [1, 2, 3, 4];

    expect(fourNumberArray.length).toBe(4);
    fourNumberArray.push(5, 6);
    expect(fourNumberArray.length).toBe(6);

    var tenEmptyElementArray = new Array(10);
    expect(tenEmptyElementArray.length).toBe(10);

    tenEmptyElementArray.length = 5;
    expect(tenEmptyElementArray.length).toBe(5);
  });

  it("should slice arrays", function () {
    var array = ["peanut", "butter", "and", "jelly"];

    expect(array.slice(0, 1)).toEqual(["peanut"]);
    expect(array.slice(0, 2)).toEqual(["peanut","butter"]);
    expect(array.slice(2, 2)).toEqual([]);
    expect(array.slice(2, 20)).toEqual(["and","jelly"]);
    expect(array.slice(3, 0)).toEqual([]);
    expect(array.slice(3, 100)).toEqual(['jelly']);
    expect(array.slice(5, 1)).toEqual([]);
  });

  it("should know array references", function () {
    var array = [ "zero", "one", "two", "three", "four", "five" ];

    function passedByReference(refArray) {
        refArray[1] = "changed in function";
    }
    passedByReference(array);
    expect(array[1]).toBe(FILL_ME_IN);

    var assignedArray = array;
    assignedArray[5] = "changed in assignedArray";
    expect(array[5]).toBe(FILL_ME_IN);

    var copyOfArray = array.slice();
    copyOfArray[3] = "changed in copyOfArray";
    expect(array[3]).toBe(FILL_ME_IN);
  });

  it("should push and pop", function () {
    var array = [1, 2];
    array.push(3);

    expect(array).toEqual(FILL_ME_IN);

    var poppedValue = array.pop();
    expect(poppedValue).toBe(FILL_ME_IN);
    expect(array).toEqual(FILL_ME_IN);
  });

  it("should know about shifting arrays", function () {
    var array = [1, 2];

    array.unshift(3);
    expect(array).toEqual(FILL_ME_IN);

    var shiftedValue = array.shift();
    expect(shiftedValue).toEqual(FILL_ME_IN);
    expect(array).toEqual(FILL_ME_IN);
  });
});
<commit_msg>11 / 53 completes<commit_after>describe("About Arrays", function() {

  //We shall contemplate truth by testing reality, via spec expectations.
  it("should create arrays", function() {
    var emptyArray = [];
    expect(typeof(emptyArray)).toBe("object"); //A mistake? - http://javascript.crockford.com/remedial.html
    expect(emptyArray.length).toBe(0);

    var multiTypeArray = [0, 1, "two", function () { return 3; }, {value1: 4, value2: 5}, [6, 7]];
    expect(multiTypeArray[0]).toBe(0);
    expect(multiTypeArray[2]).toBe("two");
    expect(multiTypeArray[3]()).toBe(3);
    expect(multiTypeArray[4].value1).toBe(4);
    expect(multiTypeArray[4]["value2"]).toBe(5);
    expect(multiTypeArray[5][0]).toBe(6);
  });

  it("should understand array literals", function () {
    var array = [];
    expect(array).toEqual([]);

    array[0] = 1;
    expect(array).toEqual([1]);

    array[1] = 2;
    expect(array).toEqual([1, 2]);

    array.push(3);
    expect(array).toEqual([1,2,3]);
  });

  it("should understand array length", function () {
    var fourNumberArray = [1, 2, 3, 4];

    expect(fourNumberArray.length).toBe(4);
    fourNumberArray.push(5, 6);
    expect(fourNumberArray.length).toBe(6);

    var tenEmptyElementArray = new Array(10);
    expect(tenEmptyElementArray.length).toBe(10);

    tenEmptyElementArray.length = 5;
    expect(tenEmptyElementArray.length).toBe(5);
  });

  it("should slice arrays", function () {
    var array = ["peanut", "butter", "and", "jelly"];

    expect(array.slice(0, 1)).toEqual(["peanut"]);
    expect(array.slice(0, 2)).toEqual(["peanut","butter"]);
    expect(array.slice(2, 2)).toEqual([]);
    expect(array.slice(2, 20)).toEqual(["and","jelly"]);
    expect(array.slice(3, 0)).toEqual([]);
    expect(array.slice(3, 100)).toEqual(['jelly']);
    expect(array.slice(5, 1)).toEqual([]);
  });

  it("should know array references", function () {
    var array = [ "zero", "one", "two", "three", "four", "five" ];

    function passedByReference(refArray) {
        refArray[1] = "changed in function";
    }
    passedByReference(array);
    expect(array[1]).toBe('changed in function');

    var assignedArray = array;
    assignedArray[5] = "changed in assignedArray";
    expect(array[5]).toBe('changed in assignedArray');

    var copyOfArray = array.slice();
    copyOfArray[3] = "changed in copyOfArray";
    expect(array[3]).toBe("three");
  });

  it("should push and pop", function () {
    var array = [1, 2];
    array.push(3);

    expect(array).toEqual([1,2,3]);

    var poppedValue = array.pop();
    expect(poppedValue).toBe(3);
    expect(array).toEqual([1,2]);
  });

  it("should know about shifting arrays", function () {
    var array = [1, 2];

    array.unshift(3);
    expect(array).toEqual(FILL_ME_IN);

    var shiftedValue = array.shift();
    expect(shiftedValue).toEqual(FILL_ME_IN);
    expect(array).toEqual(FILL_ME_IN);
  });
});
<|endoftext|>


<commit_before>describe("About Arrays", function() {

  //We shall contemplate truth by testing reality, via spec expectations.
  it("should create arrays", function() {
    var emptyArray = [];
    expect(typeof(emptyArray)).toBe("object"); //A mistake? - http:javascript.crockford.com/remedial.html
    expect(emptyArray.length).toBe(0);

    var multiTypeArray = [0, 1, "two", function () { return 3; }, {value1: 4, value2: 5}, [6, 7]];
    expect(multiTypeArray[0]).toBe(0);
    expect(multiTypeArray[2]).toBe("two");
    expect(multiTypeArray[3]()).toBe(3);
    expect(multiTypeArray[4].value1).toBe(4);
    expect(multiTypeArray[4]["value2"]).toBe(5);
    expect(multiTypeArray[5][0]).toBe(6);
  });

  it("should understand array literals", function () {
    var array = [];
    expect(array).toEqual([]);

    array[0] = 1;
    expect(array).toEqual([1]);

    array[1] = 2;
    expect(array).toEqual([1, 2]);

    array.push(3);
    expect(array).toEqual([1, 2, 3]);
  });

  it("should understand array length", function () {
    var fourNumberArray = [1, 2, 3, 4];

    expect(fourNumberArray.length).toBe(FILL_ME_IN);
    fourNumberArray.push(5, 6);
    expect(fourNumberArray.length).toBe(FILL_ME_IN);

    var tenEmptyElementArray = new Array(10);
    expect(tenEmptyElementArray.length).toBe(FILL_ME_IN);

    tenEmptyElementArray.length = 5;
    expect(tenEmptyElementArray.length).toBe(FILL_ME_IN);
  });

  it("should slice arrays", function () {
    var array = ["peanut", "butter", "and", "jelly"];

    expect(array.slice(0, 1)).toEqual(FILL_ME_IN);
    expect(array.slice(0, 2)).toEqual(FILL_ME_IN);
    expect(array.slice(2, 2)).toEqual(FILL_ME_IN);
    expect(array.slice(2, 20)).toEqual(FILL_ME_IN);
    expect(array.slice(3, 0)).toEqual(FILL_ME_IN);
    expect(array.slice(3, 100)).toEqual(FILL_ME_IN);
    expect(array.slice(5, 1)).toEqual(FILL_ME_IN);
  });

  it("should know array references", function () {
    var array = [ "zero", "one", "two", "three", "four", "five" ];

    function passedByReference(refArray) {
      refArray[1] = "changed in function";
    }
    passedByReference(array);
    expect(array[1]).toBe(FILL_ME_IN);

    var assignedArray = array;
    assignedArray[5] = "changed in assignedArray";
    expect(array[5]).toBe(FILL_ME_IN);

    var copyOfArray = array.slice();
    copyOfArray[3] = "changed in copyOfArray";
    expect(array[3]).toBe(FILL_ME_IN);
  });

  it("should push and pop", function () {
    var array = [1, 2];
    array.push(3);

    expect(array).toEqual(FILL_ME_IN);

    var poppedValue = array.pop();
    expect(poppedValue).toBe(FILL_ME_IN);
    expect(array).toEqual(FILL_ME_IN);
  });

  it("should know about shifting arrays", function () {
    var array = [1, 2];

    array.unshift(3);
    expect(array).toEqual(FILL_ME_IN);

    var shiftedValue = array.shift();
    expect(shiftedValue).toEqual(FILL_ME_IN);
    expect(array).toEqual(FILL_ME_IN);
  });
});
<commit_msg>Yup, that's right I understand array lenghts... booo yaaa :)<commit_after>describe("About Arrays", function() {

  //We shall contemplate truth by testing reality, via spec expectations.
  it("should create arrays", function() {
    var emptyArray = [];
    expect(typeof(emptyArray)).toBe("object"); //A mistake? - http:javascript.crockford.com/remedial.html
    expect(emptyArray.length).toBe(0);

    var multiTypeArray = [0, 1, "two", function () { return 3; }, {value1: 4, value2: 5}, [6, 7]];
    expect(multiTypeArray[0]).toBe(0);
    expect(multiTypeArray[2]).toBe("two");
    expect(multiTypeArray[3]()).toBe(3);
    expect(multiTypeArray[4].value1).toBe(4);
    expect(multiTypeArray[4]["value2"]).toBe(5);
    expect(multiTypeArray[5][0]).toBe(6);
  });

  it("should understand array literals", function () {
    var array = [];
    expect(array).toEqual([]);

    array[0] = 1;
    expect(array).toEqual([1]);

    array[1] = 2;
    expect(array).toEqual([1, 2]);

    array.push(3);
    expect(array).toEqual([1, 2, 3]);
  });

  it("should understand array length", function () {
    var fourNumberArray = [1, 2, 3, 4];

    expect(fourNumberArray.length).toBe(4);
    fourNumberArray.push(5, 6);
    expect(fourNumberArray.length).toBe(6);

    var tenEmptyElementArray = new Array(10);
    expect(tenEmptyElementArray.length).toBe(10);

    tenEmptyElementArray.length = 5;
    expect(tenEmptyElementArray.length).toBe(5);
  });

  it("should slice arrays", function () {
    var array = ["peanut", "butter", "and", "jelly"];

    expect(array.slice(0, 1)).toEqual(FILL_ME_IN);
    expect(array.slice(0, 2)).toEqual(FILL_ME_IN);
    expect(array.slice(2, 2)).toEqual(FILL_ME_IN);
    expect(array.slice(2, 20)).toEqual(FILL_ME_IN);
    expect(array.slice(3, 0)).toEqual(FILL_ME_IN);
    expect(array.slice(3, 100)).toEqual(FILL_ME_IN);
    expect(array.slice(5, 1)).toEqual(FILL_ME_IN);
  });

  it("should know array references", function () {
    var array = [ "zero", "one", "two", "three", "four", "five" ];

    function passedByReference(refArray) {
      refArray[1] = "changed in function";
    }
    passedByReference(array);
    expect(array[1]).toBe(FILL_ME_IN);

    var assignedArray = array;
    assignedArray[5] = "changed in assignedArray";
    expect(array[5]).toBe(FILL_ME_IN);

    var copyOfArray = array.slice();
    copyOfArray[3] = "changed in copyOfArray";
    expect(array[3]).toBe(FILL_ME_IN);
  });

  it("should push and pop", function () {
    var array = [1, 2];
    array.push(3);

    expect(array).toEqual(FILL_ME_IN);

    var poppedValue = array.pop();
    expect(poppedValue).toBe(FILL_ME_IN);
    expect(array).toEqual(FILL_ME_IN);
  });

  it("should know about shifting arrays", function () {
    var array = [1, 2];

    array.unshift(3);
    expect(array).toEqual(FILL_ME_IN);

    var shiftedValue = array.shift();
    expect(shiftedValue).toEqual(FILL_ME_IN);
    expect(array).toEqual(FILL_ME_IN);
  });
});
<|endoftext|>


<commit_before>"use strict";

var extend = function(target) {
	Array.prototype.slice.call(arguments, 1).forEach(function(source) {
		for (var key in source) {
			if (source[key] !== undefined) {
				target[key] = source[key];
			}
		}
	});
};

var apnSetImmediate = function (method) {
	if("function" === typeof setImmediate) {
		setImmediate(method);
	}
	else {
		process.nextTick(method);
	}
};

module.exports.extend = extend;
module.exports.setImmediate = apnSetImmediate;
<commit_msg>Remove legacy setImmediate wrapper<commit_after>"use strict";

var extend = function(target) {
	Array.prototype.slice.call(arguments, 1).forEach(function(source) {
		for (var key in source) {
			if (source[key] !== undefined) {
				target[key] = source[key];
			}
		}
	});
};

module.exports.extend = extend;
<|endoftext|>


<commit_before>// common code slice
//////////////////////////////////////////////////////////////////////
// - constants
// - common methods

// @const
// 'a@1.2.3/abc' ->
// ['a@1.2.3/abc', 'a', '1.2.3', '/abc']

//                    01            2         3
var REGEX_PARSE_ID = /^((?:[^\/])+?)(?:@([^\/]+))?(\/.*)?$/;
// On android 2.2,
// `[^\/]+?` will fail to do the lazy match, but `(?:[^\/]+?)` works.
// Shit, go to hell!

// @param {string} resolved path-resolved module identifier
// 'a@1.0.0'    -> 'a@1.0.0'
// 'a'          -> 'a@latest'
// 'a/inner'    -> 'a@latest/inner'
function parseModuleId(resolved) {
  var match = resolved.match(REGEX_PARSE_ID);
  var name = match[1];

  // 'a/inner' -> 'a@latest/inner'
  var version = match[2] || 'latest';
  var path = match[3] || '';

  // There always be matches
  return {
    n: name,
    v: version,
    p: path
  };
}

// Ref: [semver](http://semver.org/)
// note that we must use '\-' rather than '-', becase '-' presents a range within brackets
// @const
var REGEX_MATCH_SEMVER = /^(\D*)(\d+)\.(\d+)\.(\d+)/i;
//                       0  1    2      3      4

// A very simple method to parse semver
// @return {Object} parsed semver object
function parseSemver(version) {
  var ret = {};
  if (version) {
    var match = version.match(REGEX_MATCH_SEMVER);

    // For example:
    // '~1.3.9-alpha/lang'
    if (match) {
      // decorator -> '~'
      ret.d = match[1];
      // major -> '1'
      ret.a = match[2];
      // minor -> '3'
      ret.b = match[3];
      // patch -> '9'
      ret.c = match[4];
    }
  }

  return ret;
}

// A very simple `mix` method
// copy all properties in the supplier to the receiver
// @param {Object} receiver
// @param {Object} supplier
// @returns {mixed} receiver
function mix(receiver, supplier) {
  var c;
  for (c in supplier) {
    receiver[c] = supplier[c];
  }
}

// greedy match:
var REGEX_DIR_MATCHER = /.*(?=\/.*$)/;

// Get the current directory from the location
//
// http://jsperf.com/regex-vs-split/2
// vs: http://jsperf.com/regex-vs-split
function dirname(uri) {
  var m = uri.match(REGEX_DIR_MATCHER);

  // abc/def  -> abc
  // abc      -> abc  // which is different with `path.dirname` of node.js
  // abc/     -> abc
  return m ? m[0] : uri;
}

// Canonicalize path
// similar to path.resolve() of node.js
// NOTICE that the difference between `pathResolve` and `path.resolve` of node.js is:
// `pathResolve` treats paths which dont begin with './' and '../' as top level paths,
// but node.js as a relative path.

// For example:
// pathResolve('a', 'b')    -> 'b'
// node_path.resolve('a', 'b')   -> 'a/b'

// pathResolve('a/b', './c')    -> 'a/b/c'
// pathResolve('a/b', '../c')   -> 'a/c'
// pathResolve('a//b', './c')   -> 'a//b/c'   - for 'a//b/c' is a valid uri

// #75:
// pathResolve('../abc', './c') -> '../abc/'
function pathResolve(from, to) {
  // relative
  if (isPathRelative(to)) {
    var parts = (dirname(from) + '/' + to).split('/');
    to = normalizeArray(parts).join('/');
  }

  return to;
}

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

// resolves . and .. elements in a path array with directory names there
// must be no slashes, empty elements, or device names (c:\) in the array
// (so also no leading and trailing slashes - it does not distinguish
// relative and absolute paths)
function normalizeArray(parts) {
  // if the path tries to go above the root, `up` ends up > 0
  var up = 0;
  var i = parts.length - 1;
  for (; i >= 0; i--) {
    var last = parts[i];
    if (last === '.') {
      parts.splice(i, 1);

    } else if (last === '..') {
      parts.splice(i, 1);
      up++;

    } else if (up) {
      parts.splice(i, 1);
      up--;
    }
  }

  // if the path is allowed to go above the root, restore leading ..s
  while (up--) {
    parts.unshift('..');
  }

  return parts;
}

// @param {string} path
function isPathRelative(path) {
  return path.indexOf('./') === 0 || path.indexOf('../') === 0;
}

function err (message) {
  throw new Error('neuron: ' + message);
}
<commit_msg>util: parseSemver will probably has fewer changes to have no match; #103<commit_after>// common code slice
//////////////////////////////////////////////////////////////////////
// - constants
// - common methods

// @const
// 'a@1.2.3/abc' ->
// ['a@1.2.3/abc', 'a', '1.2.3', '/abc']

//                    01            2         3
var REGEX_PARSE_ID = /^((?:[^\/])+?)(?:@([^\/]+))?(\/.*)?$/;
// On android 2.2,
// `[^\/]+?` will fail to do the lazy match, but `(?:[^\/]+?)` works.
// Shit, go to hell!

// @param {string} resolved path-resolved module identifier
// 'a@1.0.0'    -> 'a@1.0.0'
// 'a'          -> 'a@latest'
// 'a/inner'    -> 'a@latest/inner'
function parseModuleId(resolved) {
  var match = resolved.match(REGEX_PARSE_ID);
  var name = match[1];

  // 'a/inner' -> 'a@latest/inner'
  var version = match[2] || 'latest';
  var path = match[3] || '';

  // There always be matches
  return {
    n: name,
    v: version,
    p: path
  };
}

// Ref: [semver](http://semver.org/)
// note that we must use '\-' rather than '-', becase '-' presents a range within brackets
// @const
var REGEX_MATCH_SEMVER = /^(\D*)(?:(\d+)\.(\d+)\.(\d+))?/i;
//                       0  1       2      3      4

// A very simple method to parse semver
// @return {Object} parsed semver object
function parseSemver(version) {
  var ret = {};
  if (version) {
    var match = version.match(REGEX_MATCH_SEMVER);

    // For example:
    // '~1.3.9-alpha/lang'
    if (match) {
      // decorator -> '~'
      ret.d = match[1];
      // major -> '1'
      ret.a = match[2];
      // minor -> '3'
      ret.b = match[3];
      // patch -> '9'
      ret.c = match[4];
    }
  }

  return ret;
}

// A very simple `mix` method
// copy all properties in the supplier to the receiver
// @param {Object} receiver
// @param {Object} supplier
// @returns {mixed} receiver
function mix(receiver, supplier) {
  var c;
  for (c in supplier) {
    receiver[c] = supplier[c];
  }
}

// greedy match:
var REGEX_DIR_MATCHER = /.*(?=\/.*$)/;

// Get the current directory from the location
//
// http://jsperf.com/regex-vs-split/2
// vs: http://jsperf.com/regex-vs-split
function dirname(uri) {
  var m = uri.match(REGEX_DIR_MATCHER);

  // abc/def  -> abc
  // abc      -> abc  // which is different with `path.dirname` of node.js
  // abc/     -> abc
  return m ? m[0] : uri;
}

// Canonicalize path
// similar to path.resolve() of node.js
// NOTICE that the difference between `pathResolve` and `path.resolve` of node.js is:
// `pathResolve` treats paths which dont begin with './' and '../' as top level paths,
// but node.js as a relative path.

// For example:
// pathResolve('a', 'b')    -> 'b'
// node_path.resolve('a', 'b')   -> 'a/b'

// pathResolve('a/b', './c')    -> 'a/b/c'
// pathResolve('a/b', '../c')   -> 'a/c'
// pathResolve('a//b', './c')   -> 'a//b/c'   - for 'a//b/c' is a valid uri

// #75:
// pathResolve('../abc', './c') -> '../abc/'
function pathResolve(from, to) {
  // relative
  if (isPathRelative(to)) {
    var parts = (dirname(from) + '/' + to).split('/');
    to = normalizeArray(parts).join('/');
  }

  return to;
}

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

// resolves . and .. elements in a path array with directory names there
// must be no slashes, empty elements, or device names (c:\) in the array
// (so also no leading and trailing slashes - it does not distinguish
// relative and absolute paths)
function normalizeArray(parts) {
  // if the path tries to go above the root, `up` ends up > 0
  var up = 0;
  var i = parts.length - 1;
  for (; i >= 0; i--) {
    var last = parts[i];
    if (last === '.') {
      parts.splice(i, 1);

    } else if (last === '..') {
      parts.splice(i, 1);
      up++;

    } else if (up) {
      parts.splice(i, 1);
      up--;
    }
  }

  // if the path is allowed to go above the root, restore leading ..s
  while (up--) {
    parts.unshift('..');
  }

  return parts;
}

// @param {string} path
function isPathRelative(path) {
  return path.indexOf('./') === 0 || path.indexOf('../') === 0;
}

function err (message) {
  throw new Error('neuron: ' + message);
}
<|endoftext|>


<commit_before>(function(scope) {
    'use strict';

    var exec,
        rendy,
        Scope = scope.window ? window : global;

    if (typeof module === 'object' && module.exports) {
        exec = require('execon');
        rendy = require('rendy');
        module.exports = new UtilProto(exec);
    } else if (!Scope.Util) {
        exec = window.exec;
        rendy = window.rendy;
        Scope.Util = new UtilProto(exec);
    }

    function UtilProto(exec) {
        var Util = this;

        this.check              = new checkProto();

        function checkProto() {
            /**
             * Check is all arguments with names present
             *
             * @param name
             * @param arg
             */
            function check(args, names) {
                var msg         = '',
                    name        = '',
                    template    = '{{ name }} coud not be empty!',

                    indexOf     = Array.prototype.indexOf,

                    lenNames    = names.length,
                    lenArgs     = args.length,
                    lessArgs    = lenArgs < lenNames,
                    emptyIndex  = indexOf.call(args),
                    isEmpty     = ~emptyIndex && emptyIndex <= lenNames - 1;

                if (lessArgs || isEmpty) {
                    if (lessArgs)
                        name        = names[lenNames - 1];
                    else
                        name        = names[emptyIndex];

                    msg         = rendy(template, {
                        name: name
                    });

                    throw Error(msg);
                }

                return check;
            }

            check.check = check;

            /**
             * Check is type of arg with name is equal to type
             *
             * @param name
             * @param arg
             * @param type
             */
            check.type  = function(name, arg, type) {
                var is = Util.type(arg) === type;

                if (!is)
                    throw Error(name + ' should be ' + type);

                return check;
            };

            return check;
        }

        /**
         * Copy properties from from to to
         *
         * @param from
         * @param to
         */
        this.copyObj                = function(to, from) {
            if (!from) {
                from    = to;
                to      = {};
            }

            if (to)
                Object.keys(from).forEach(function(name) {
                    to[name]    = from[name];
                });

            return to;
        };

        /**
         * copy objFrom properties to target
         *
         * @target
         * @objFrom
         */
        this.extend                 = function(target, objFrom) {
            var obj,
                keys,
                proto,
                isFunc  = Util.type.function(objFrom),
                isArray = Util.type.array(objFrom),
                isObj   = Util.type.object(target),
                ret     = isObj ? target : {};

            if (isArray)
                objFrom.forEach(function(item) {
                   ret = Util.extend(target, item);
                });

            else if (objFrom) {
                obj     = isFunc ? new objFrom() : objFrom;
                keys    = Object.keys(obj);

                if (!keys.length) {
                    proto = Object.getPrototypeOf(objFrom);
                    keys  = Object.keys(proto);
                }

                keys.forEach(function(name) {
                    ret[name] = obj[name];
                });
            }

            return ret;
        };

        /**
         * extend proto
         *
         * @obj
         */
        this.extendProto           = function(obj) {
            var ret, F      = function() {};
            F.prototype     = Util.extend({}, obj);
            ret             = new F();

            return ret;
        };

        this.json               = new JsonProto();

        function JsonProto() {
            /**
             * @param str
             */
            this.parse      = function(str) {
                var obj;

                Util.exec.try(function() {
                    obj = JSON.parse(str);
                });

                return obj;
            },

            /**
             * @param obj
             */
            this.stringify  = function(obj) {
                var str;

                Util.exec.try(function() {
                    str = JSON.stringify(obj, null, 4);
                });

                return str;
            };
        }

        this.escapeRegExp = function(str) {
            var isStr   = Util.type.string(str);

            if (isStr)
                str = str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');

            return str;
        };

        /**
         * get regexp from wild card
         */
        this.getRegExp              = function(wildcard) {
            var regExp;

            if (!wildcard)
                wildcard = '*';

            wildcard    = '^' + wildcard /* search from start of line */
                .replace('.', '\\.')
                .replace('*', '.*')
                .replace('?', '.?');

            wildcard    += '$'; /* search to end of line */

            regExp      = new RegExp(wildcard);

            return regExp;
        };

        this.type                   = new TypeProto();

        function TypeProto() {
            /**
             * get type of variable
             *
             * @param variable
             */
            function type(variable) {
                var regExp      = /\s([a-zA-Z]+)/,
                    str         = {}.toString.call(variable),
                    typeBig     = str.match(regExp)[1],
                    result      = typeBig.toLowerCase();

                return result;
            }

            /**
             * functions check is variable is type of name
             *
             * @param variable
             */
            function typeOf(name, variable) {
                return type(variable) === name;
            }

            function typeOfSimple(name, variable) {
                return typeof variable === name;
            }

            ['null', 'arrayBuffer', 'file', 'array', 'object']
                .forEach(function(name) {
                    type[name] = typeOf.bind(null, name);
                });

            ['string', 'undefined', 'boolean', 'number', 'function']
                .forEach(function(name) {
                    type[name] = typeOfSimple.bind(null, name);
                });

            return type;
        }

        this.exec                       = exec;

        /**
         * function gets file extension
         *
         * @param pFileName
         * @return Ext
         */
        this.getExt                     = function(name) {
            var ret     = '',
                dot,
                isStr   = Util.type.string(name);

            if (isStr) {
                dot = name.lastIndexOf('.');

                if (~dot)
                    ret = name.substr(dot);
            }

            return ret;
        };

       /**
         * get values from Object Array name properties
         * or
         * @pObj
         */
        this.getNamesFromObjArray       = function(arr) {
            var ret     = [];

            if (!Array.isArray(arr))
                throw Error('arr should be array!');

            ret = arr.map(function(item) {
                return item.name;
            });

            return ret;
        };

        /**
         * find object by name in arrray
         *
         * @param array
         * @param name
         */
        this.findObjByNameInArr         = function(array, name) {
            var ret;

             if (!Array.isArray(array))
                throw Error('array should be array!');

            if (typeof name !== 'string')
                throw Error('name should be string!');

            array.some(function(item) {
                var is = item.name === name,
                    isArray = Util.type.array(item);

                if (is)
                    ret = item;
                else if (isArray)
                    item.some(function(item) {
                        is = item.name === name;

                        if (is)
                            ret = item.data;

                        return is;
                    });

                return is;
            });

            return ret;
        };

        /**
         * start timer
         * @param name
         */
        this.time                       = function(name) {
            var console     = Scope.console;

            Util.exec.ifExist(console, 'time', [name]);

            return this;
        };

        /**
         * stop timer
         * @param name
         */
        this.timeEnd                   = function(name) {
            var console    = Scope.console;

            Util.exec.ifExist(console, 'timeEnd', [name]);

            return this;
        };
    }

})(this);
<commit_msg>refactor(util) findObjByNameInArr: Util.type.array -> Array.isArray<commit_after>(function(scope) {
    'use strict';

    var exec,
        rendy,
        Scope = scope.window ? window : global;

    if (typeof module === 'object' && module.exports) {
        exec = require('execon');
        rendy = require('rendy');
        module.exports = new UtilProto(exec);
    } else if (!Scope.Util) {
        exec = window.exec;
        rendy = window.rendy;
        Scope.Util = new UtilProto(exec);
    }

    function UtilProto(exec) {
        var Util = this;

        this.check              = new checkProto();

        function checkProto() {
            /**
             * Check is all arguments with names present
             *
             * @param name
             * @param arg
             */
            function check(args, names) {
                var msg         = '',
                    name        = '',
                    template    = '{{ name }} coud not be empty!',

                    indexOf     = Array.prototype.indexOf,

                    lenNames    = names.length,
                    lenArgs     = args.length,
                    lessArgs    = lenArgs < lenNames,
                    emptyIndex  = indexOf.call(args),
                    isEmpty     = ~emptyIndex && emptyIndex <= lenNames - 1;

                if (lessArgs || isEmpty) {
                    if (lessArgs)
                        name        = names[lenNames - 1];
                    else
                        name        = names[emptyIndex];

                    msg         = rendy(template, {
                        name: name
                    });

                    throw Error(msg);
                }

                return check;
            }

            check.check = check;

            /**
             * Check is type of arg with name is equal to type
             *
             * @param name
             * @param arg
             * @param type
             */
            check.type  = function(name, arg, type) {
                var is = Util.type(arg) === type;

                if (!is)
                    throw Error(name + ' should be ' + type);

                return check;
            };

            return check;
        }

        /**
         * Copy properties from from to to
         *
         * @param from
         * @param to
         */
        this.copyObj                = function(to, from) {
            if (!from) {
                from    = to;
                to      = {};
            }

            if (to)
                Object.keys(from).forEach(function(name) {
                    to[name]    = from[name];
                });

            return to;
        };

        /**
         * copy objFrom properties to target
         *
         * @target
         * @objFrom
         */
        this.extend                 = function(target, objFrom) {
            var obj,
                keys,
                proto,
                isFunc  = Util.type.function(objFrom),
                isArray = Util.type.array(objFrom),
                isObj   = Util.type.object(target),
                ret     = isObj ? target : {};

            if (isArray)
                objFrom.forEach(function(item) {
                   ret = Util.extend(target, item);
                });

            else if (objFrom) {
                obj     = isFunc ? new objFrom() : objFrom;
                keys    = Object.keys(obj);

                if (!keys.length) {
                    proto = Object.getPrototypeOf(objFrom);
                    keys  = Object.keys(proto);
                }

                keys.forEach(function(name) {
                    ret[name] = obj[name];
                });
            }

            return ret;
        };

        /**
         * extend proto
         *
         * @obj
         */
        this.extendProto           = function(obj) {
            var ret, F      = function() {};
            F.prototype     = Util.extend({}, obj);
            ret             = new F();

            return ret;
        };

        this.json               = new JsonProto();

        function JsonProto() {
            /**
             * @param str
             */
            this.parse      = function(str) {
                var obj;

                Util.exec.try(function() {
                    obj = JSON.parse(str);
                });

                return obj;
            },

            /**
             * @param obj
             */
            this.stringify  = function(obj) {
                var str;

                Util.exec.try(function() {
                    str = JSON.stringify(obj, null, 4);
                });

                return str;
            };
        }

        this.escapeRegExp = function(str) {
            var isStr   = Util.type.string(str);

            if (isStr)
                str = str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');

            return str;
        };

        /**
         * get regexp from wild card
         */
        this.getRegExp              = function(wildcard) {
            var regExp;

            if (!wildcard)
                wildcard = '*';

            wildcard    = '^' + wildcard /* search from start of line */
                .replace('.', '\\.')
                .replace('*', '.*')
                .replace('?', '.?');

            wildcard    += '$'; /* search to end of line */

            regExp      = new RegExp(wildcard);

            return regExp;
        };

        this.type                   = new TypeProto();

        function TypeProto() {
            /**
             * get type of variable
             *
             * @param variable
             */
            function type(variable) {
                var regExp      = /\s([a-zA-Z]+)/,
                    str         = {}.toString.call(variable),
                    typeBig     = str.match(regExp)[1],
                    result      = typeBig.toLowerCase();

                return result;
            }

            /**
             * functions check is variable is type of name
             *
             * @param variable
             */
            function typeOf(name, variable) {
                return type(variable) === name;
            }

            function typeOfSimple(name, variable) {
                return typeof variable === name;
            }

            ['null', 'arrayBuffer', 'file', 'array', 'object']
                .forEach(function(name) {
                    type[name] = typeOf.bind(null, name);
                });

            ['string', 'undefined', 'boolean', 'number', 'function']
                .forEach(function(name) {
                    type[name] = typeOfSimple.bind(null, name);
                });

            return type;
        }

        this.exec                       = exec;

        /**
         * function gets file extension
         *
         * @param pFileName
         * @return Ext
         */
        this.getExt                     = function(name) {
            var ret     = '',
                dot,
                isStr   = Util.type.string(name);

            if (isStr) {
                dot = name.lastIndexOf('.');

                if (~dot)
                    ret = name.substr(dot);
            }

            return ret;
        };

       /**
         * get values from Object Array name properties
         * or
         * @pObj
         */
        this.getNamesFromObjArray       = function(arr) {
            var ret     = [];

            if (!Array.isArray(arr))
                throw Error('arr should be array!');

            ret = arr.map(function(item) {
                return item.name;
            });

            return ret;
        };

        /**
         * find object by name in arrray
         *
         * @param array
         * @param name
         */
        this.findObjByNameInArr         = function(array, name) {
            var ret;

             if (!Array.isArray(array))
                throw Error('array should be array!');

            if (typeof name !== 'string')
                throw Error('name should be string!');

            array.some(function(item) {
                var is = item.name === name,
                    isArray = Array.isArray(item);

                if (is)
                    ret = item;
                else if (isArray)
                    item.some(function(item) {
                        is = item.name === name;

                        if (is)
                            ret = item.data;

                        return is;
                    });

                return is;
            });

            return ret;
        };

        /**
         * start timer
         * @param name
         */
        this.time                       = function(name) {
            var console     = Scope.console;

            Util.exec.ifExist(console, 'time', [name]);

            return this;
        };

        /**
         * stop timer
         * @param name
         */
        this.timeEnd                   = function(name) {
            var console    = Scope.console;

            Util.exec.ifExist(console, 'timeEnd', [name]);

            return this;
        };
    }

})(this);
<|endoftext|>