<commit_before>var ___ = require('lodash'),
    asynEach = require('async-foreach').forEach,
    fs = require('graceful-fs'),
    globby = require('globby'),
    path = require('path'),
    PDF = require('pdfkit'),
    phantom = require('phantom'),
    Q = require('q'),
    request = require('request'),
    sizeOf = require('image-size'),
    utils = require('./utils'),
    xml2js = require('xml2js');

var pageContent = [];

/**
 * Handles:
 *   sitemap http request
 *   create local copy of sitemap
 *   converts xml to json
 * @author Steven Britton
 * @date   2016-03-24
 * @param  {Object}   options Produced from config process
 * @return {Function}         Promise
 */
function handleSitemap(options) {

    utils.log.verbose('getSitemap');

    var deferred = Q.defer(),
        failedAuthCounter = 0,
        siteMapName = options.domain.sitemap.url + '.' + options.domain.sitemap.type,
        url = utils.urlCheckProtocol(options.sitemapURL);

    if (url === '') {
        deferred.reject(new Error('Missing Configuration Setting - sitemap is not defined'));
        return deferred.promise;
    }

    /**
     * Saves a local copy of a sitemap.xml file
     * @author Steven Britton
     * @date   2016-03-22
     * @param  {String}     siteMapName   Sitemap name
     * @param  {String}     data          Sitemap body
     * @return {Function}   promise       resolve or reject
     */
    function saveSitemap(siteMapName, data) {

        var deferred = Q.defer();

        fs.writeFile(siteMapName, data, function(error) {

            if (error) {
                deferred.reject(new Error(error));
            } else {
                utils.log.note('⤷ Saving local ' + siteMapName + ' file');
                deferred.resolve();
            }

        });
        return deferred.promise;
    }

    /**
     * Converts XML formatted string to JSON
     * @author Steven Britton
     * @date   2016-03-22
     * @param  {buffer}    data     Sitemap body
     * @return {Function}  promise  resolve or reject
     */
    function convertSitemap(data) {

        utils.log.verbose('Converting XML sitemap to JSON');

        var deferred = Q.defer(),
            error = null,
            parser = new xml2js.Parser(),
            pages = [];

        parser.parseString(data, function(err, result) {

            if (err) {
                deferred.reject(new Error(err));
            }

            if (result.urlset && ___.isArray(result.urlset.url)) {
                pages = result.urlset.url.map(function(item) {
                    return item.loc[0];
                });

                deferred.resolve(pages);
            }

            // check for multiple sitemaps returned
            else if (___.isArray(result.sitemapindex.sitemap)) {

                error = 'Multiple sitemaps returned \n';

                error += '\nPlease update your siteshooter.yml sitemap setting to 1 of the ' + result.sitemapindex.sitemap.length + ' listed sitemaps';

                result.sitemapindex.sitemap.map(function(item) {
                    error += '\n' + item.loc[0];
                });

                deferred.reject(new Error(error));

            }
        });

        return deferred.promise;
    }

    /**
     * Chains saveSitemap and convertSitmap
     * @author Steven Britton
     * @date   2016-03-24
     * @param  {String}     siteMapName name of sitemap name to target
     * @param  {Object}     response    http response
     * @return {Function}   promise     resolve or reject
     */
    function processSitemap(siteMapName, response) {

        return saveSitemap(siteMapName, response.body)
            .then(function() {
                return convertSitemap(response.body);
            })
            .then(function(pages) {
                deferred.resolve(pages);
            }, function(error) {

                utils.log.note('⤷ Removing local ' + siteMapName + ' file');

                utils.rm(siteMapName);

                deferred.reject(error);
            });
    }

    /**
     * Recursive Request callback function
     * @author Steven Britton
     * @date   2016-03-24
     * @param  {object}     error    returned request error
     * @param  {object}     response returned request response
     * @return {Function}   promise  resolve or reject
     */
    function handleResponseStatus(error, response) {

        if (error) {
            return deferred.reject(error);
        }

        utils.log.verbose(response.statusCode);

        switch (response.statusCode) {

            case 200:

                processSitemap(siteMapName, response);

                break;

            case 301:

                var redirectLocation = response.headers.location;

                utils.log.note('    ⤷ 301 Redirecting to ' + redirectLocation);

                request.get(redirectLocation, {
                    'followRedirect': false,
                    'auth': {
                        'user': options.domain.auth.user,
                        'pass': options.domain.auth.pwd,
                        'sendImmediately': true
                    }
                }, handleResponseStatus);

                break;

            case 401:

                // allow only 1 authenication failure
                if (failedAuthCounter > 0) {
                    return deferred.reject(response.statusCode + ' Unauthorized - Please verify that your stored credentials are correct');
                }

                utils.log.note('  ⤷ 401 Authentication required');
                utils.log.note('    ⤷ Checking for stored credentials in siteshooter.yml file');

                // do we have stored credentials?
                if (options.domain.auth.user !== null && options.domain.auth.pwd !== null) {

                    utils.log.note('    ✔ Credentials are stored');
                    utils.log.note('    ⤷ Attempting to access sitemap with credentials');

                } else {
                    return deferred.reject('Missing settings in siteshooter.yml file \n domain.auth.user \n domain.auth.pwd');
                }

                request.get(url, {
                    'followRedirect': false,
                    'auth': {
                        'user': options.domain.auth.user,
                        'pass': options.domain.auth.pwd,
                        'sendImmediately': true
                    }
                }, handleResponseStatus);

                failedAuthCounter++;

                break;

            default:

                utils.log.verbose(response);

                // something is not accounted for
                return deferred.reject(new Error(response.statusCode + ' Page ' + response.statusMessage));

        }

    }

    // look for local sitemap.xml file first
    fs.readFile(siteMapName, function(err, data) {
        if (!err) {

            // local sitemap.xml file exists, so use it and move on

            utils.log.note('  ⤷ Using local ' + siteMapName);

            convertSitemap(data)
                .then(function(pages) {
                    deferred.resolve(pages);
                }, function(error) {

                    deferred.reject(error);
                });

        } else {

            utils.log.verbose('Getting external sitemap');

            /**
             * Recursive request call
             * @status 200 - process sitemap and resolve promise
             * @status 300 - redirect response information back to handleResponseStatus
             * @status 401 - include stored credentials and send request to handleResponseStatus
             */
            request(url, handleResponseStatus);

        }
    });

    return deferred.promise;
}

function handleScreenshots(pages, options) {

    utils.log.verbose('handleScreenshots', pages);

    var d = Q.defer();

    function renderPage(url, done) {

        var folder = utils.urlToDir(url),
            viewports = options.viewports,
            output, key;

        phantom.create().then(function(ph) {
            ph.createPage().then(function(page) {

                // do we have stored credentials?
                if (options.domain.auth.user !== null && options.domain.auth.pwd !== null) {

                    utils.log.note('   ⤷  Setting Authentication');

                    page.setting('userName', options.domain.auth.user);
                    page.setting('password', options.domain.auth.pwd);
                }

                page.open(url).then(function(status) {

                    function renderView(n) {

                        if (!!n) {
                            key = n - 1;

                            var _pageContent = page.property('content');

                            utils.log.note('       ⤷ Viewport ' + viewports[key].width + 'x' + viewports[key].height);

                            page.property('viewportSize', { 'width': viewports[key].width, 'height': viewports[key].height });

                            output = path.join(options.paths.output, folder, viewports[key].width + '.png');

                            setTimeout(function() {
                                page.render(output).then(function() {

                                    pageContent.push({
                                        'page': key,
                                        'content': _pageContent
                                    });
                                    renderView(key);

                                });
                            }, options.screenshot.delay);

                        } else {

                            ph.exit();

                            done();

                        }
                    }

                    if (status === 'success') {

                        utils.log.note('   ⤷  Page ' + folder);

                        renderView(viewports.length);

                    } else {
                        ph.exit(1);

                        return done('Failed connection: ' + url);
                    }
                });

            });
        });
    }

    asynEach(pages, function(page) {
        var done = this.async();

        renderPage(page, function(err) {

            if (err) {
                utils.log.error(err);
            }

            done();

        });

    }, function(success, array) {

        d.resolve();
    });

    return d.promise;
}

function handlePDF(options) {

    utils.log.verbose('createPDF');

    var deferred = Q.defer(),
        date = utils.getDate(),
        pdfs = [];

    function getFiles(size) {
        return globby.sync([path.join(options.paths.output, '**', '*' + size + '.png')]);
    }

    function createPDF(viewport, dimensions, arrImages, done) {

        utils.log.verbose('createPDF', dimensions);

        var pdfPath = path.resolve(options.paths.output, utils.urlToDir(options.domain.name) + '-' + viewport + '-' + date + '.pdf');

        utils.log.verbose('pdfPath', pdfPath);

        var pdf = new PDF({
            layout: 'portrait',
            size: [dimensions.width, sizeOf(arrImages[0]).height],
            margin: 0
        });

        pdf.pipe(fs.createWriteStream(pdfPath));

        arrImages.forEach(function(png, i) {

            if (i > 0) {
                pdf.addPage({
                    margin: 0,
                    size: [sizeOf(png).width, sizeOf(png).height],
                    width: sizeOf(png).width,
                    height: sizeOf(png).height
                });
            }
            pdf.image(png);

        });

        pdf.end();

        done();

    }

    // load array of viewports and their respective .png files
    pdfs = options.viewports.map(function(item, i) {
        return {
            'viewport': item.viewport,
            'dimensions': { 'width': item.width, 'height': item.height },
            'files': getFiles(item.width)
        };
    });

    // create individual pdfs based on viewport
    asynEach(pdfs, function(item, i) {

        var done = this.async();

        // make sure we have some screenshots
        if (item.files.length > 0) {
            createPDF(item.viewport, item.dimensions, item.files, function() {

                done();

            });
        } else {
            utils.log.warn('Screenshots for viewport ' + item.viewport + ' do not exist.');

            done();
        }

    }, function(success, array) {

        if (success) {
            deferred.resolve();
        }

    });

    return deferred.promise;
}

module.exports = {
    run: function(options) {

        var deferred = Q.defer();

        return utils.executeWhen(options.sitemapURL !== '', () => handleSitemap(options), '⤷ Getting sitemap file: ' + options.sitemapURL)
            .then(function(pages) {
                return utils.executeWhen(true, () => handleScreenshots(pages, options), '   ⤷ Generating screenshots');
            })
            .then(function() {
                return utils.executeWhen(true, () => handlePDF(options), '   ⤷ Generating PDFs');
            })
            .done(function() {
                    utils.log.success('Done taking screenshots and generating PDFs');
                    deferred.resolve();
                },
                function(err) {
                    utils.log.error(err);
                    deferred.reject(err);
                });
    }
};
<commit_msg>spacing<commit_after>var ___ = require('lodash'),
    asynEach = require('async-foreach').forEach,
    fs = require('graceful-fs'),
    globby = require('globby'),
    path = require('path'),
    PDF = require('pdfkit'),
    phantom = require('phantom'),
    Q = require('q'),
    request = require('request'),
    sizeOf = require('image-size'),
    utils = require('./utils'),
    xml2js = require('xml2js');

var pageContent = [];

/**
 * Handles:
 *   sitemap http request
 *   create local copy of sitemap
 *   converts xml to json
 * @author Steven Britton
 * @date   2016-03-24
 * @param  {Object}   options Produced from config process
 * @return {Function}         Promise
 */
function handleSitemap(options) {

    utils.log.verbose('getSitemap');

    var deferred = Q.defer(),
        failedAuthCounter = 0,
        siteMapName = options.domain.sitemap.url + '.' + options.domain.sitemap.type,
        url = utils.urlCheckProtocol(options.sitemapURL);

    if (url === '') {
        deferred.reject(new Error('Missing Configuration Setting - sitemap is not defined'));
        return deferred.promise;
    }

    /**
     * Saves a local copy of a sitemap.xml file
     * @author Steven Britton
     * @date   2016-03-22
     * @param  {String}     siteMapName   Sitemap name
     * @param  {String}     data          Sitemap body
     * @return {Function}   promise       resolve or reject
     */
    function saveSitemap(siteMapName, data) {

        var deferred = Q.defer();

        fs.writeFile(siteMapName, data, function(error) {

            if (error) {
                deferred.reject(new Error(error));
            } else {
                utils.log.note('⤷ Saving local ' + siteMapName + ' file');
                deferred.resolve();
            }

        });
        return deferred.promise;
    }

    /**
     * Converts XML formatted string to JSON
     * @author Steven Britton
     * @date   2016-03-22
     * @param  {buffer}    data     Sitemap body
     * @return {Function}  promise  resolve or reject
     */
    function convertSitemap(data) {

        utils.log.verbose('Converting XML sitemap to JSON');

        var deferred = Q.defer(),
            error = null,
            parser = new xml2js.Parser(),
            pages = [];

        parser.parseString(data, function(err, result) {

            if (err) {
                deferred.reject(new Error(err));
            }

            if (result.urlset && ___.isArray(result.urlset.url)) {
                pages = result.urlset.url.map(function(item) {
                    return item.loc[0];
                });

                deferred.resolve(pages);
            }

            // check for multiple sitemaps returned
            else if (___.isArray(result.sitemapindex.sitemap)) {

                error = 'Multiple sitemaps returned \n';

                error += '\nPlease update your siteshooter.yml sitemap setting to 1 of the ' + result.sitemapindex.sitemap.length + ' listed sitemaps';

                result.sitemapindex.sitemap.map(function(item) {
                    error += '\n' + item.loc[0];
                });

                deferred.reject(new Error(error));

            }
        });

        return deferred.promise;
    }

    /**
     * Chains saveSitemap and convertSitmap
     * @author Steven Britton
     * @date   2016-03-24
     * @param  {String}     siteMapName name of sitemap name to target
     * @param  {Object}     response    http response
     * @return {Function}   promise     resolve or reject
     */
    function processSitemap(siteMapName, response) {

        return saveSitemap(siteMapName, response.body)
            .then(function() {
                return convertSitemap(response.body);
            })
            .then(function(pages) {
                deferred.resolve(pages);
            }, function(error) {

                utils.log.note('⤷ Removing local ' + siteMapName + ' file');

                utils.rm(siteMapName);

                deferred.reject(error);
            });
    }

    /**
     * Recursive Request callback function
     * @author Steven Britton
     * @date   2016-03-24
     * @param  {object}     error    returned request error
     * @param  {object}     response returned request response
     * @return {Function}   promise  resolve or reject
     */
    function handleResponseStatus(error, response) {

        if (error) {
            return deferred.reject(error);
        }

        utils.log.verbose(response.statusCode);

        switch (response.statusCode) {

            case 200:

                processSitemap(siteMapName, response);

                break;

            case 301:

                var redirectLocation = response.headers.location;

                utils.log.note('    ⤷ 301 Redirecting to ' + redirectLocation);

                request.get(redirectLocation, {
                    'followRedirect': false,
                    'auth': {
                        'user': options.domain.auth.user,
                        'pass': options.domain.auth.pwd,
                        'sendImmediately': true
                    }
                }, handleResponseStatus);

                break;

            case 401:

                // allow only 1 authenication failure
                if (failedAuthCounter > 0) {
                    return deferred.reject(response.statusCode + ' Unauthorized - Please verify that your stored credentials are correct');
                }

                utils.log.note('  ⤷ 401 Authentication required');
                utils.log.note('    ⤷ Checking for stored credentials in siteshooter.yml file');

                // do we have stored credentials?
                if (options.domain.auth.user !== null && options.domain.auth.pwd !== null) {

                    utils.log.note('    ✔ Credentials are stored');
                    utils.log.note('    ⤷ Attempting to access sitemap with credentials');

                } else {
                    return deferred.reject('Missing settings in siteshooter.yml file \n domain.auth.user \n domain.auth.pwd');
                }

                request.get(url, {
                    'followRedirect': false,
                    'auth': {
                        'user': options.domain.auth.user,
                        'pass': options.domain.auth.pwd,
                        'sendImmediately': true
                    }
                }, handleResponseStatus);

                failedAuthCounter++;

                break;

            default:

                utils.log.verbose(response);

                // something is not accounted for
                return deferred.reject(new Error(response.statusCode + ' Page ' + response.statusMessage));

        }

    }

    // look for local sitemap.xml file first
    fs.readFile(siteMapName, function(err, data) {
        if (!err) {

            // local sitemap.xml file exists, so use it and move on

            utils.log.note('  ⤷ Using local ' + siteMapName);

            convertSitemap(data)
                .then(function(pages) {
                    deferred.resolve(pages);
                }, function(error) {

                    deferred.reject(error);
                });

        } else {

            utils.log.verbose('Getting external sitemap');

            /**
             * Recursive request call
             * @status 200 - process sitemap and resolve promise
             * @status 300 - redirect response information back to handleResponseStatus
             * @status 401 - include stored credentials and send request to handleResponseStatus
             */
            request(url, handleResponseStatus);

        }
    });

    return deferred.promise;
}

function handleScreenshots(pages, options) {

    utils.log.verbose('handleScreenshots', pages);

    var d = Q.defer();

    function renderPage(url, done) {

        var folder = utils.urlToDir(url),
            viewports = options.viewports,
            output, key;

        phantom.create().then(function(ph) {
            ph.createPage().then(function(page) {

                // do we have stored credentials?
                if (options.domain.auth.user !== null && options.domain.auth.pwd !== null) {

                    utils.log.note('   ⤷  Setting Authentication');

                    page.setting('userName', options.domain.auth.user);
                    page.setting('password', options.domain.auth.pwd);
                }

                page.open(url).then(function(status) {

                    function renderView(n) {

                        if (!!n) {
                            key = n - 1;

                            var _pageContent = page.property('content');

                            utils.log.note('       ⤷ Viewport ' + viewports[key].width + 'x' + viewports[key].height);

                            page.property('viewportSize', { 'width': viewports[key].width, 'height': viewports[key].height });

                            output = path.join(options.paths.output, folder, viewports[key].width + '.png');

                            setTimeout(function() {
                                page.render(output).then(function() {

                                    pageContent.push({
                                        'page': key,
                                        'content': _pageContent
                                    });
                                    renderView(key);

                                });
                            }, options.screenshot.delay);

                        } else {

                            ph.exit();

                            done();

                        }
                    }

                    if (status === 'success') {

                        utils.log.note('   ⤷  Page ' + folder);

                        renderView(viewports.length);

                    } else {
                        ph.exit(1);

                        return done('Failed connection: ' + url);
                    }
                });

            });
        });
    }

    asynEach(pages, function(page) {
        var done = this.async();

        renderPage(page, function(err) {

            if (err) {
                utils.log.error(err);
            }

            done();

        });

    }, function(success, array) {

        d.resolve();
    });

    return d.promise;
}

function handlePDF(options) {

    utils.log.verbose('createPDF');

    var deferred = Q.defer(),
        date = utils.getDate(),
        pdfs = [];

    function getFiles(size) {
        return globby.sync([path.join(options.paths.output, '**', '*' + size + '.png')]);
    }

    function createPDF(viewport, dimensions, arrImages, done) {

        utils.log.verbose('createPDF', dimensions);

        var pdfPath = path.resolve(options.paths.output, utils.urlToDir(options.domain.name) + '-' + viewport + '-' + date + '.pdf');

        utils.log.verbose('pdfPath', pdfPath);

        var pdf = new PDF({
            layout: 'portrait',
            size: [dimensions.width, sizeOf(arrImages[0]).height],
            margin: 0
        });

        pdf.pipe(fs.createWriteStream(pdfPath));

        arrImages.forEach(function(png, i) {

            if (i > 0) {
                pdf.addPage({
                    margin: 0,
                    size: [sizeOf(png).width, sizeOf(png).height],
                    width: sizeOf(png).width,
                    height: sizeOf(png).height
                });
            }
            pdf.image(png);

        });

        pdf.end();

        done();

    }

    // load array of viewports and their respective .png files
    pdfs = options.viewports.map(function(item, i) {
        return {
            'viewport': item.viewport,
            'dimensions': { 'width': item.width, 'height': item.height },
            'files': getFiles(item.width)
        };
    });

    // create individual pdfs based on viewport
    asynEach(pdfs, function(item, i) {

        var done = this.async();

        // make sure we have some screenshots
        if (item.files.length > 0) {
            createPDF(item.viewport, item.dimensions, item.files, function() {

                done();

            });
        } else {
            utils.log.warn('Screenshots for viewport ' + item.viewport + ' do not exist.');

            done();
        }

    }, function(success, array) {

        if (success) {
            deferred.resolve();
        }

    });

    return deferred.promise;
}

module.exports = {
    run: function(options) {

        var deferred = Q.defer();

        return utils.executeWhen(options.sitemapURL !== '', () => handleSitemap(options), '⤷ Getting sitemap file: ' + options.sitemapURL)
            .then(function(pages) {
                return utils.executeWhen(true, () => handleScreenshots(pages, options), '   ⤷ Generating screenshots');
            })
            .then(function() {
                return utils.executeWhen(true, () => handlePDF(options), '   ⤷ Generating PDFs');
            })
            .done(function() {
                    utils.log.success('Done taking screenshots and generating PDFs');
                    deferred.resolve();
                },
                function(err) {
                    utils.log.error(err);
                    deferred.reject(err);
                });
    }
};
<|endoftext|>


<commit_before>'use strict';

const pd = require('pretty-data').pd;

const BoundingBox = require('./BoundingBox');
const denormalise = require('./denormalise');
const entityToPolyline = require('./entityToPolyline');
const colors = require('./util/colors');
const logger = require('./util/logger');

function polylineToPath(rgb, polyline) {
  const color24bit = rgb[2] | (rgb[1] << 8) | (rgb[0] << 16);
  let prepad = color24bit.toString(16);
  for (let i = 0, il = 6 - prepad.length; i < il; ++i) {
    prepad = '0' + prepad;
  }
  let hex = '#' + prepad;

  // SVG is white by default, so make white lines black
  if (hex === '#ffffff') {
    hex = '#000000';
  }

  const d = polyline.reduce(function(acc, point, i) {
    acc += (i === 0) ?'M' : 'L';
    acc += point[0] + ',' + point[1];
    return acc;
  }, '');
  return '<path fill="none" stroke="' + hex + '" stroke-width="0.1%" d="' + d + '"/>';
}

/**
 * Convert the interpolate polylines to SVG
 */
module.exports = function(parsed) {

  const entities = denormalise(parsed);
  const polylines = entities.map(e => {
    return entityToPolyline(e);
  });

  const bbox = new BoundingBox();
  polylines.forEach(polyline => {
    polyline.forEach(point => {
      bbox.expandByPoint(point[0], point[1]);
    });
  });

  const paths = [];
  polylines.forEach((polyline, i) => {
    const entity = entities[i];
    const layerTable = parsed.tables.layers[entity.layer];
    if (!layerTable) {
      throw new Error('no layer table for layer:' + entity.layer);
    }

    let rgb = colors[layerTable.colorNumber];
    if (rgb === undefined) {
      logger.warn("Color index", layerTable.colorNumber, "invalid, defaulting to black");
      rgb = [0, 0, 0];
    }

    const p2 = polyline.map(function(p) {
      return [p[0], bbox.maxY - p[1]];
    });
    paths.push(polylineToPath(rgb, p2));
  });

  let svgString = '<?xml version="1.0"?>';
  svgString += '<svg xmlns="http://www.w3.org/2000/svg"';
  svgString += ' xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"';
  svgString += ' preserveAspectRatio="xMinYMin meet"';
  svgString += ' viewBox="' +
    (-1 + bbox.minX) + ' ' +
    (-1) + ' ' +
    (bbox.width + 2) + ' ' +
    (bbox.height + 2) + '"';
  svgString += ' width="100%" height="100%">' + paths + '</svg>';
  return pd.xml(svgString);
};
<commit_msg>Use entity.colorNumber over layer.colorNumber if existing<commit_after>'use strict';

const pd = require('pretty-data').pd;

const BoundingBox = require('./BoundingBox');
const denormalise = require('./denormalise');
const entityToPolyline = require('./entityToPolyline');
const colors = require('./util/colors');
const logger = require('./util/logger');

function polylineToPath(rgb, polyline) {
  const color24bit = rgb[2] | (rgb[1] << 8) | (rgb[0] << 16);
  let prepad = color24bit.toString(16);
  for (let i = 0, il = 6 - prepad.length; i < il; ++i) {
    prepad = '0' + prepad;
  }
  let hex = '#' + prepad;

  // SVG is white by default, so make white lines black
  if (hex === '#ffffff') {
    hex = '#000000';
  }

  const d = polyline.reduce(function(acc, point, i) {
    acc += (i === 0) ?'M' : 'L';
    acc += point[0] + ',' + point[1];
    return acc;
  }, '');
  return '<path fill="none" stroke="' + hex + '" stroke-width="0.1%" d="' + d + '"/>';
}

/**
 * Convert the interpolate polylines to SVG
 */
module.exports = function(parsed) {

  const entities = denormalise(parsed);
  const polylines = entities.map(e => {
    return entityToPolyline(e);
  });

  const bbox = new BoundingBox();
  polylines.forEach(polyline => {
    polyline.forEach(point => {
      bbox.expandByPoint(point[0], point[1]);
    });
  });

  const paths = [];
  polylines.forEach((polyline, i) => {
    const entity = entities[i];
    const layerTable = parsed.tables.layers[entity.layer];
    if (!layerTable) {
      throw new Error('no layer table for layer:' + entity.layer);
    }

    // TODO: not sure if this prioritization is good (entity color first, layer color as fallback)
    let colorNumber = ('colorNumber' in entity) ? entity.colorNumber : layerTable.colorNumber;
    let rgb = colors[colorNumber];
    if (rgb === undefined) {
      logger.warn("Color index", colorNumber, "invalid, defaulting to black");
      rgb = [0, 0, 0];
    }

    const p2 = polyline.map(function(p) {
      return [p[0], bbox.maxY - p[1]];
    });
    paths.push(polylineToPath(rgb, p2));
  });

  let svgString = '<?xml version="1.0"?>';
  svgString += '<svg xmlns="http://www.w3.org/2000/svg"';
  svgString += ' xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"';
  svgString += ' preserveAspectRatio="xMinYMin meet"';
  svgString += ' viewBox="' +
    (-1 + bbox.minX) + ' ' +
    (-1) + ' ' +
    (bbox.width + 2) + ' ' +
    (bbox.height + 2) + '"';
  svgString += ' width="100%" height="100%">' + paths + '</svg>';
  return pd.xml(svgString);
};
<|endoftext|>


<commit_before>"use strict";

/**
 * Format of a todo:
 * * file:  String - Relative path
 * * sha:   String - Commit's sha
 * * line:  Number - File line number
 * * title: String - Issue's title
 * * label: String - Issue's label
 * * issue: Number - (optional) Issue's number
 **/

var path = require("path");
var _ = require("lodash");
var Promise = require("bluebird");

var ask = require("./ask");
var fs = require("./fs");
var config = require("./config");
var service = require("./issue-service");
var git = require("./git");

module.exports = {
  "fromDiff": fromDiff
};

var SKIP_FILE_NAME = ".github-todos-ignore";

function readIgnoreFile () {
  return git.dir(path.join("..", SKIP_FILE_NAME))
    .then(function (filename) {
      return fs.readFile(filename).then(function (content) {
        var ignored = _.filter(_.invoke((content || "").split("\n"), "trim"));
        return [ignored, filename];
      });
    });
}

function shouldSkip (title, caseSensitive) {
  title = String(title || "").trim();
  if (caseSensitive) {
    title = title.toLowerCase();
  }

  return readIgnoreFile().spread(function (ignores) {
    if (caseSensitive) {
      ignores = _.invoke(ignores, "toLowerCase");
    }

    return _.contains(ignores, title);
  });
}

function createOrCommentIssue (repo, todo, conf) {
  if (todo.issue) {
    return commentIssue(todo, conf);
  }

  // Create issue?
  return shouldSkip(todo.title, conf["case-sensitive"]).then(function (skip) {
    if (skip) {
      return null;
    }

    var Service = service(conf.service);

    return Service.findIssueByTitle(repo, todo.title).then(function (issue) {
      if (!issue) {
        return createIssue(repo, todo, conf);
      }

      // comment issue
      todo.issue = issue.number;

      var ops = [commentIssue(repo, todo, conf)];

      if (!_.contains(issue.labels, todo.label)) {
        ops.push(Service.tagIssue(repo, todo.issue, todo.label));
      }

      return Promise.all(ops).spread(function (comment /*, tagresult */) {
        return comment;
      });
    });
  });
}

// Add line to github-todos-ignore
function rememberSkip (title) {
  return readIgnoreFile().spread(function (ignores, skipFile) {
    if (!_.contains(ignores, title)) {
      return fs.writeFile(skipFile, ignores.concat([title]).join("\n"));
    }
  });
}

function createIssue (repo, todo, conf) {
  if (!conf["confirm-create"]) {
    return create();
  }

  return ask([{
    "type": "expand",
    "message": "Create new issue \"" + todo.title + "\" (" + todo.file + ":" + todo.line + ")",
    "name": "choice",
    "choices": [
      {"key": "y", "name": "Create issue", "value": "create"},
      {"key": "n", "name": "Do not create issue", "value": "skip"},
      {"key": "r", "name": "Do not create issue and remember for next times", "value": "skip_and_remember"},
      {"key": "q", "name": "Abort", "value": "abort"}
    ],
    "default": 0
  }]).choices("choice", {
    "create":             create,
    "skip_and_remember":  skipAndRemember,
    "abort":              abort,
    "skip":               null, // skip
    "default":            null  // skip
  });

  function abort () {
    var e = new Error("User aborted");
    e.code = "EINTERRUPT";
    throw e;
  }

  function skipAndRemember () {
    return rememberSkip(todo.title).then(null, function (err) {
      console.error("[Github-Todos] Failed adding info to '" + SKIP_FILE_NAME + "'");
      throw err;
    });
  }

  function create () {
    return getCommentText(repo, todo, conf).then(function (text) {
      return service(conf.service).createIssue(repo, todo.title, text, [todo.label]).then(function (issue) {
        return issue;
      });
    });
  }
}

function commentIssue (repo, todo, conf) {
  return getCommentText(repo, todo, conf).then(function (text) {
    return service(conf.service).commentIssue(repo, todo.issue, text);
  });
}

function getCommentText (repo, todo, conf) {
  var text = "";

  // Link to file
  text += "Ref. [" + todo.file + ":" + todo.line + "](" + service(conf.service).getFileUrl(repo, todo.file, todo.sha, todo.line) + ")";

  function generateCommentText (content) {
    var lines = content.split(/\r\n|\r|\n/);

    // Remove trailing new lines
    while (lines[lines.length - 1] === "") {
      lines.pop();
    }
    while (lines[0] === "") {
      lines.shift();
    }

    if (conf.context > 0) {
      // Extract: line to line + conf.context
      var extract = lines.slice(todo.line - 1, todo.line + conf.context).join("\n");
      if (todo.line + conf.context < lines.length) {
        extract += "\n…";
      }

      // TODO syntax highlighting?
      text += "\n\n```\n" + extract + "\n```\n";
    }

    if (conf.signature) {
      text += "\n" + conf.signature;
    }

    return text;
  }

  // Add code information
  return git.dir(path.join("..", todo.file))
    .then(fs.readFileStrict)
    .then(generateCommentText);
}

function fromDiff (repo, diff, sha, conf) {
  conf = _.merge({
    "onProgress": _.noop
  }, conf || {}, config.defaults);

  var todos = _.flatten(_.map(diff, function (file) {
    var addedLines = _.filter(file.lines, "add");
    var lineTodos = _.map(addedLines, lineToTodoMapper(file.to, sha, conf));
    // keep only those with required field
    return _.filter(lineTodos, "title");
  }));

  return todos.reduce(function (previous, todo) {
    return previous.then(function (results) {
      return createOrCommentIssue(repo, todo, conf)
        .then(function (result) {
          conf.onProgress(null, result, todo);
          return results.concat([result]);
        })
        .then(null, function (err) {
          conf.onProgress(err, null, todo);
          throw err;
        });
    });
  }, Promise.resolve([])).then(function (results) {
    return [results, todos];
  });
}

// String, Sha → String → {file, sha, line, title, label}
function lineToTodoMapper (filename, sha, conf) {
  return function lineToTodo (line) {
    return _.merge({
      "file":   filename,
      "sha":    sha,
      "line":   line.ln
    }, extractTodoTitle(line.content, conf));
  };
}

// String → {title, label}
function extractTodoTitle (content, conf) {
  var result = null;

  var labels = {};
  _.each(conf, function (value, key) {
    if (value && key.match(/^label\./)) {
      var trigger = key.substring(6);
      if (conf["label-whitespace"]) {
        trigger += " ";
      }
      labels[trigger] = value;
    }
  });

  if (_.isString(content)) {
    _.find(Object.keys(labels), function (trigger) {
      var index;
      if (conf["case-sensitive"]) {
        index = content.indexOf(trigger);
      } else {
        index = content.toUpperCase().indexOf(trigger.toUpperCase());
      }

      if (index !== -1) {
        var title = content.substring(index + trigger.length).trim();
        var issue = null;
        if (title && !isCode(title)) {
          var match = title.match(/^\s+#(\d+)\s+/);
          if (match) {
            issue = match[1];
            title = title.substring(match[0].length);
          }
          result = {
            "title":  title,
            "label":  labels[trigger],
            "issue":  Number(issue)
          };
        }
        return true; // break
      }
    });
  }

  return result;
}

// TODO Better heuristic for code vs words detection

// Simple heuristic to detect if a title is really a title or some valid code
// String → Boolean
function isCode (string) {
  // If symbols are more than 20% of the code, it may be code more than human text
  var symbols = _.filter(string, isSymbol);

  return symbols.length / string.length > 0.20;
}

var RE_SYMBOL = /[^\sa-z0-9\u00E0-\u00FC]/i;
// Matches a symbol: non alphanumeric character
// Character → Boolean
function isSymbol (character) {
  return RE_SYMBOL.test(character);
}
<commit_msg>Append detected language to code block (enable syntax highlighting, refs #2)<commit_after>"use strict";

/**
 * Format of a todo:
 * * file:  String - Relative path
 * * sha:   String - Commit's sha
 * * line:  Number - File line number
 * * title: String - Issue's title
 * * label: String - Issue's label
 * * issue: Number - (optional) Issue's number
 **/

var path = require("path");
var _ = require("lodash");
var Promise = require("bluebird");

var ask = require("./ask");
var fs = require("./fs");
var config = require("./config");
var service = require("./issue-service");
var git = require("./git");

module.exports = {
  "fromDiff": fromDiff
};

var SKIP_FILE_NAME = ".github-todos-ignore";

function readIgnoreFile () {
  return git.dir(path.join("..", SKIP_FILE_NAME))
    .then(function (filename) {
      return fs.readFile(filename).then(function (content) {
        var ignored = _.filter(_.invoke((content || "").split("\n"), "trim"));
        return [ignored, filename];
      });
    });
}

function shouldSkip (title, caseSensitive) {
  title = String(title || "").trim();
  if (caseSensitive) {
    title = title.toLowerCase();
  }

  return readIgnoreFile().spread(function (ignores) {
    if (caseSensitive) {
      ignores = _.invoke(ignores, "toLowerCase");
    }

    return _.contains(ignores, title);
  });
}

function createOrCommentIssue (repo, todo, conf) {
  if (todo.issue) {
    return commentIssue(todo, conf);
  }

  // Create issue?
  return shouldSkip(todo.title, conf["case-sensitive"]).then(function (skip) {
    if (skip) {
      return null;
    }

    var Service = service(conf.service);

    return Service.findIssueByTitle(repo, todo.title).then(function (issue) {
      if (!issue) {
        return createIssue(repo, todo, conf);
      }

      // comment issue
      todo.issue = issue.number;

      var ops = [commentIssue(repo, todo, conf)];

      if (!_.contains(issue.labels, todo.label)) {
        ops.push(Service.tagIssue(repo, todo.issue, todo.label));
      }

      return Promise.all(ops).spread(function (comment /*, tagresult */) {
        return comment;
      });
    });
  });
}

// Add line to github-todos-ignore
function rememberSkip (title) {
  return readIgnoreFile().spread(function (ignores, skipFile) {
    if (!_.contains(ignores, title)) {
      return fs.writeFile(skipFile, ignores.concat([title]).join("\n"));
    }
  });
}

function createIssue (repo, todo, conf) {
  if (!conf["confirm-create"]) {
    return create();
  }

  return ask([{
    "type": "expand",
    "message": "Create new issue \"" + todo.title + "\" (" + todo.file + ":" + todo.line + ")",
    "name": "choice",
    "choices": [
      {"key": "y", "name": "Create issue", "value": "create"},
      {"key": "n", "name": "Do not create issue", "value": "skip"},
      {"key": "r", "name": "Do not create issue and remember for next times", "value": "skip_and_remember"},
      {"key": "q", "name": "Abort", "value": "abort"}
    ],
    "default": 0
  }]).choices("choice", {
    "create":             create,
    "skip_and_remember":  skipAndRemember,
    "abort":              abort,
    "skip":               null, // skip
    "default":            null  // skip
  });

  function abort () {
    var e = new Error("User aborted");
    e.code = "EINTERRUPT";
    throw e;
  }

  function skipAndRemember () {
    return rememberSkip(todo.title).then(null, function (err) {
      console.error("[Github-Todos] Failed adding info to '" + SKIP_FILE_NAME + "'");
      throw err;
    });
  }

  function create () {
    return getCommentText(repo, todo, conf).then(function (text) {
      return service(conf.service).createIssue(repo, todo.title, text, [todo.label]).then(function (issue) {
        return issue;
      });
    });
  }
}

function commentIssue (repo, todo, conf) {
  return getCommentText(repo, todo, conf).then(function (text) {
    return service(conf.service).commentIssue(repo, todo.issue, text);
  });
}

function getCommentText (repo, todo, conf) {
  var text = "";

  // Link to file
  text += "Ref. [" + todo.file + ":" + todo.line + "](" + service(conf.service).getFileUrl(repo, todo.file, todo.sha, todo.line) + ")";

  function generateCommentText (content) {
    var lines = content.split(/\r\n|\r|\n/);

    // Remove trailing new lines
    while (lines[lines.length - 1] === "") {
      lines.pop();
    }
    while (lines[0] === "") {
      lines.shift();
    }

    if (conf.context > 0) {
      // Extract: line to line + conf.context
      var extract = lines.slice(todo.line - 1, todo.line + conf.context).join("\n");
      if (todo.line + conf.context < lines.length) {
        extract += "\n…";
      }

      text += "\n\n```" + getLanguage(todo.file, content) + "\n" + extract + "\n```\n";
    }

    if (conf.signature) {
      text += "\n" + conf.signature;
    }

    return text;
  }

  // Add code information
  return git.dir(path.join("..", todo.file))
    .then(fs.readFileStrict)
    .then(generateCommentText);
}

// Language detection: very naive only based on filename for now
function getLanguage (filename /*, content */) {
  var index = filename.lastIndexOf(".");
  if (index === -1) {
    return "";
  }

  return filename.substring(index + 1);
}

function fromDiff (repo, diff, sha, conf) {
  conf = _.merge({
    "onProgress": _.noop
  }, conf || {}, config.defaults);

  var todos = _.flatten(_.map(diff, function (file) {
    var addedLines = _.filter(file.lines, "add");
    var lineTodos = _.map(addedLines, lineToTodoMapper(file.to, sha, conf));
    // keep only those with required field
    return _.filter(lineTodos, "title");
  }));

  return todos.reduce(function (previous, todo) {
    return previous.then(function (results) {
      return createOrCommentIssue(repo, todo, conf)
        .then(function (result) {
          conf.onProgress(null, result, todo);
          return results.concat([result]);
        })
        .then(null, function (err) {
          conf.onProgress(err, null, todo);
          throw err;
        });
    });
  }, Promise.resolve([])).then(function (results) {
    return [results, todos];
  });
}

// String, Sha → String → {file, sha, line, title, label}
function lineToTodoMapper (filename, sha, conf) {
  return function lineToTodo (line) {
    return _.merge({
      "file":   filename,
      "sha":    sha,
      "line":   line.ln
    }, extractTodoTitle(line.content, conf));
  };
}

// String → {title, label}
function extractTodoTitle (content, conf) {
  var result = null;

  var labels = {};
  _.each(conf, function (value, key) {
    if (value && key.match(/^label\./)) {
      var trigger = key.substring(6);
      if (conf["label-whitespace"]) {
        trigger += " ";
      }
      labels[trigger] = value;
    }
  });

  if (_.isString(content)) {
    _.find(Object.keys(labels), function (trigger) {
      var index;
      if (conf["case-sensitive"]) {
        index = content.indexOf(trigger);
      } else {
        index = content.toUpperCase().indexOf(trigger.toUpperCase());
      }

      if (index !== -1) {
        var title = content.substring(index + trigger.length).trim();
        var issue = null;
        if (title && !isCode(title)) {
          var match = title.match(/^\s+#(\d+)\s+/);
          if (match) {
            issue = match[1];
            title = title.substring(match[0].length);
          }
          result = {
            "title":  title,
            "label":  labels[trigger],
            "issue":  Number(issue)
          };
        }
        return true; // break
      }
    });
  }

  return result;
}

// TODO Better heuristic for code vs words detection

// Simple heuristic to detect if a title is really a title or some valid code
// String → Boolean
function isCode (string) {
  // If symbols are more than 20% of the code, it may be code more than human text
  var symbols = _.filter(string, isSymbol);

  return symbols.length / string.length > 0.20;
}

var RE_SYMBOL = /[^\sa-z0-9\u00E0-\u00FC]/i;
// Matches a symbol: non alphanumeric character
// Character → Boolean
function isSymbol (character) {
  return RE_SYMBOL.test(character);
}
<|endoftext|>


<commit_before>'use strict'

var flatstr = require('flatstr')
var format = require('quick-format-unescaped')
var util = require('util')
var pid = process.pid
var os = require('os')
var hostname = os.hostname()
var baseLog = flatstr('{"pid":' + pid + ',"hostname":"' + hostname + '",')
var levels = require(require.resolve('./levels'))
var serializers = require(require.resolve('./serializers'))
var time = require(require.resolve('./time'))

function noop () {}

function copy (a, b) {
  for (var k in b) { a[k] = b[k] }
  return a
}

// Must be invoked via .call() to retain speed of inlining into the
// Pino constructor.
function applyOptions (opts) {
  this.serializers = opts.serializers
  this.stringify = opts.stringify
  this.end = opts.end
  this.name = opts.name
  this.timestamp = opts.timestamp
  this.slowtime = opts.slowtime
  this.chindings = opts.chindings
  this.cache = opts.cache
  this.formatOpts = opts.formatOpts
  this.onTerminated = opts.onTerminated

  if (opts.level && opts.levelVal) {
    var levelIsStandard = levels.isStandardLevel(opts.level)
    var valIsStandard = levels.isStandardLevelVal(opts.levelVal)
    if (valIsStandard) throw Error('level value is already used: ' + opts.levelVal)
    if (levelIsStandard === false && valIsStandard === false) this.addLevel(opts.level, opts.levelVal)
  }
  this._setLevel(opts.level)
  this._baseLog = flatstr(baseLog +
    (this.name === undefined ? '' : '"name":' + this.stringify(this.name) + ','))

  if (opts.timestamp === false) {
    this.time = time.getNoTime
  } else if (opts.slowtime) {
    this.time = time.getSlowTime
  } else {
    this.time = time.getTime
  }
}

function defineLevelsProperty (onObject) {
  Object.defineProperty(onObject, 'levels', {
    value: {
      values: copy({}, levels.levels),
      labels: copy({}, levels.nums)
    },
    enumerable: true
  })
  Object.defineProperty(onObject.levels.values, 'silent', {value: Infinity})
  Object.defineProperty(onObject.levels.labels, Infinity, {value: 'silent'})
}

function streamIsBlockable (s) {
  if (s.hasOwnProperty('_handle') && s._handle.hasOwnProperty('fd') && s._handle.fd) return true
  if (s.hasOwnProperty('fd') && s.fd) return true
  return false
}

function countInterp (s, i) {
  var n = 0
  var pos = 0
  while (true) {
    pos = s.indexOf(i, pos)
    if (pos >= 0) {
      ++n
      pos += 2
    } else break
  }
  return n
}

function genLog (z) {
  return function LOG (a, b, c, d, e, f, g, h, i, j, k) {
    var l = 0
    var m = null
    var n = null
    var o
    var p
    if (typeof a === 'object' && a !== null) {
      m = a
      n = [b, c, d, e, f, g, h, i, j, k]
      l = 1

      if (m.method && m.headers && m.socket) {
        m = serializers.mapHttpRequest(m)
      } else if (typeof m.setHeader === 'function') {
        m = serializers.mapHttpResponse(m)
      }
    } else {
      n = [a, b, c, d, e, f, g, h, i, j, k]
    }
    p = n.length = arguments.length - l
    if (p > 1) {
      l = typeof a === 'string' ? countInterp(a, '%j') : 0
      if (l) {
        n.length = l + countInterp(a, '%d') + countInterp(a, '%s') + 1
        o = `${util.format.apply(null, n)}`
      } else {
        o = format(n, this.formatOpts)
      }
    } else if (p) {
      o = n[0]
    }
    this.write(m, o, z)
  }
}

module.exports = {
  noop: noop,
  copy: copy,
  applyOptions: applyOptions,
  defineLevelsProperty: defineLevelsProperty,
  streamIsBlockable: streamIsBlockable,
  genLog: genLog
}
<commit_msg>remove unuseful `require.resolve` preventing easy webpack bundling of the node version<commit_after>'use strict'

var flatstr = require('flatstr')
var format = require('quick-format-unescaped')
var util = require('util')
var pid = process.pid
var os = require('os')
var hostname = os.hostname()
var baseLog = flatstr('{"pid":' + pid + ',"hostname":"' + hostname + '",')
var levels = require('./levels')
var serializers = require('./serializers')
var time = require('./time')

function noop () {}

function copy (a, b) {
  for (var k in b) { a[k] = b[k] }
  return a
}

// Must be invoked via .call() to retain speed of inlining into the
// Pino constructor.
function applyOptions (opts) {
  this.serializers = opts.serializers
  this.stringify = opts.stringify
  this.end = opts.end
  this.name = opts.name
  this.timestamp = opts.timestamp
  this.slowtime = opts.slowtime
  this.chindings = opts.chindings
  this.cache = opts.cache
  this.formatOpts = opts.formatOpts
  this.onTerminated = opts.onTerminated

  if (opts.level && opts.levelVal) {
    var levelIsStandard = levels.isStandardLevel(opts.level)
    var valIsStandard = levels.isStandardLevelVal(opts.levelVal)
    if (valIsStandard) throw Error('level value is already used: ' + opts.levelVal)
    if (levelIsStandard === false && valIsStandard === false) this.addLevel(opts.level, opts.levelVal)
  }
  this._setLevel(opts.level)
  this._baseLog = flatstr(baseLog +
    (this.name === undefined ? '' : '"name":' + this.stringify(this.name) + ','))

  if (opts.timestamp === false) {
    this.time = time.getNoTime
  } else if (opts.slowtime) {
    this.time = time.getSlowTime
  } else {
    this.time = time.getTime
  }
}

function defineLevelsProperty (onObject) {
  Object.defineProperty(onObject, 'levels', {
    value: {
      values: copy({}, levels.levels),
      labels: copy({}, levels.nums)
    },
    enumerable: true
  })
  Object.defineProperty(onObject.levels.values, 'silent', {value: Infinity})
  Object.defineProperty(onObject.levels.labels, Infinity, {value: 'silent'})
}

function streamIsBlockable (s) {
  if (s.hasOwnProperty('_handle') && s._handle.hasOwnProperty('fd') && s._handle.fd) return true
  if (s.hasOwnProperty('fd') && s.fd) return true
  return false
}

function countInterp (s, i) {
  var n = 0
  var pos = 0
  while (true) {
    pos = s.indexOf(i, pos)
    if (pos >= 0) {
      ++n
      pos += 2
    } else break
  }
  return n
}

function genLog (z) {
  return function LOG (a, b, c, d, e, f, g, h, i, j, k) {
    var l = 0
    var m = null
    var n = null
    var o
    var p
    if (typeof a === 'object' && a !== null) {
      m = a
      n = [b, c, d, e, f, g, h, i, j, k]
      l = 1

      if (m.method && m.headers && m.socket) {
        m = serializers.mapHttpRequest(m)
      } else if (typeof m.setHeader === 'function') {
        m = serializers.mapHttpResponse(m)
      }
    } else {
      n = [a, b, c, d, e, f, g, h, i, j, k]
    }
    p = n.length = arguments.length - l
    if (p > 1) {
      l = typeof a === 'string' ? countInterp(a, '%j') : 0
      if (l) {
        n.length = l + countInterp(a, '%d') + countInterp(a, '%s') + 1
        o = `${util.format.apply(null, n)}`
      } else {
        o = format(n, this.formatOpts)
      }
    } else if (p) {
      o = n[0]
    }
    this.write(m, o, z)
  }
}

module.exports = {
  noop: noop,
  copy: copy,
  applyOptions: applyOptions,
  defineLevelsProperty: defineLevelsProperty,
  streamIsBlockable: streamIsBlockable,
  genLog: genLog
}
<|endoftext|>


<commit_before>'use strict';

let EE = require('events').EventEmitter;
let util = require('util');
let stream = require('stream');
let Vlan = require('./vlan');

util.inherits(Trunk, EE);
function Trunk(){
	EE.call(this);
	this.vlans = {};
	this.last = 0;
	this.connected = false;
	Array.prototype.forEach.call(arguments, arg => {
		if(!isNaN(arg) && Number(arg) !== 0) this.vlans[arg] = null;
		else if(arg instanceof stream.Duplex) this.setTrunk(arg);
	});
};

Trunk.prototype.del = function(id){
	if(id !== 0 && this.vlans[id]) delete this.vlans[id];
	this.emit('remove', id);
};

Trunk.prototype.add = function(id){
	if(id >= this.last) this.last = id + 1;
	id = Number(isNaN(id) ? this.last : id);
	if(this.vlans[id] instanceof Vlan) return;
	this.vlans[id] = new Vlan({id: id, trunk: this.trunk});
	this.vlans[id].on('close', error => this.mvlan.json({run: 'del', id: id, err: error}));
	this.vlans[id].on('error', error => this.mvlan.json({run: 'del', id: id, err: error.message}));
	if(id !== 0) this.mvlan.json({run: 'add', id: id});
	this.emit('vlan', id);
	this.emit('vlan' + id);
	return this.vlans[id];
};

Trunk.prototype.setTrunk = function(trunk){

	this.trunk = trunk;

	let isChunk = false,
		chunkSize = 0,
		chunkId = 0,
		buffer = new Buffer(0);

	trunk.on('data', data => {
		let chunk;
		if(data.length) while(true) if(isChunk){
			if(data.length >= chunkSize - buffer.length){
				chunk = Buffer.concat([buffer, data.slice(0, chunkSize - buffer.length)], chunkSize);
				if(!this.vlans[chunkId].push(chunk)) {
					this.mvlan.json({run:'down', id: chunkId});
					this.vlans[chunkId].peerPaused = true;
				}
				data = data.slice(chunkSize - buffer.length);
				buffer = new Buffer(0)
				isChunk = false;
				continue;
			} else {
				buffer = Buffer.concat([buffer, data], buffer.length + data.length);
				break;
			};
		} else {
			if(data.length >= 8 - buffer.length){
				chunkId = data.readInt32LE(0);
				chunkSize = data.readInt32LE(4);
				data = data.slice(8);
				buffer = new Buffer(0);
				isChunk = true;
				continue;
			} else {
				buffer = Buffer.concat([buffer, data], buffer.length + data.length);
				break;
			};
		}
	});

	this.mvlan = this.add(0);

	this.mvlan.on('data', data => {
		data = JSON.parse(data.toString());
		({
			up   : data => {this.vlans[data.id] && this.vlans[data.id].up()},
			down : data => {this.vlans[data.id] && this.vlans[data.id].down()},
			add  : data => {this.add(data.id)},
			del  : data => {this.del(data.id)},
			hi   : data => {data.ids.forEach(id => this.add(id))}
		}[data.run] || (d => d))(data);
	});

	this.trunk.mvlan = this.mvlan;

	Object.keys(this.vlans).forEach(id => this.add(id));
	if(!this.connected){
		this.mvlan.json({run: 'hi', ids: Object.keys(this.vlans)});
		this.connected = true;
	}

}

module.exports = Trunk;
<commit_msg>codestyle fix<commit_after>'use strict';

let EE = require('events').EventEmitter;
let util = require('util');
let stream = require('stream');
let Vlan = require('./vlan');

util.inherits(Trunk, EE);
function Trunk(){
	EE.call(this);
	this.vlans = {};
	this.last = 0;
	this.connected = false;
	Array.prototype.forEach.call(arguments, arg => {
		if(!isNaN(arg) && Number(arg) !== 0) this.vlans[arg] = null;
		else if(arg instanceof stream.Duplex) this.setTrunk(arg);
	});
};

Trunk.prototype.del = function(id){
	if(id !== 0 && this.vlans[id]) delete this.vlans[id];
	this.emit('remove', id);
};

Trunk.prototype.add = function(id){
	if(id >= this.last) this.last = id + 1;
	id = Number(isNaN(id) ? this.last : id);
	if(this.vlans[id] instanceof Vlan) return;
	this.vlans[id] = new Vlan({id: id, trunk: this.trunk});
	this.vlans[id].on('close', error => this.mvlan.json({run: 'del', id: id, err: error}));
	this.vlans[id].on('error', error => this.mvlan.json({run: 'del', id: id, err: error.message}));
	if(id !== 0) this.mvlan.json({run: 'add', id: id});
	this.emit('vlan', id);
	this.emit('vlan' + id);
	return this.vlans[id];
};

Trunk.prototype.setTrunk = function(trunk){

	this.trunk = trunk;

	let isChunk = false,
		chunkSize = 0,
		chunkId = 0,
		buffer = new Buffer(0);

	trunk.on('data', data => {
		let chunk;
		if(data.length) while(true) {
			if(isChunk){
				if(data.length >= chunkSize - buffer.length){
					chunk = Buffer.concat([buffer, data.slice(0, chunkSize - buffer.length)], chunkSize);
					if(!this.vlans[chunkId].push(chunk)) {
						this.mvlan.json({run:'down', id: chunkId});
						this.vlans[chunkId].peerPaused = true;
					}
					data = data.slice(chunkSize - buffer.length);
					buffer = new Buffer(0)
					isChunk = false;
					continue;
				} else {
					buffer = Buffer.concat([buffer, data], buffer.length + data.length);
					break;
				};
			} else {
				if(data.length >= 8 - buffer.length){
					chunkId = data.readInt32LE(0);
					chunkSize = data.readInt32LE(4);
					data = data.slice(8);
					buffer = new Buffer(0);
					isChunk = true;
					continue;
				} else {
					buffer = Buffer.concat([buffer, data], buffer.length + data.length);
					break;
				};
			}
		}
	});

	this.mvlan = this.add(0);

	this.mvlan.on('data', data => {
		data = JSON.parse(data.toString());
		({
			up   : data => {this.vlans[data.id] && this.vlans[data.id].up()},
			down : data => {this.vlans[data.id] && this.vlans[data.id].down()},
			add  : data => {this.add(data.id)},
			del  : data => {this.del(data.id)},
			hi   : data => {data.ids.forEach(id => this.add(id))}
		}[data.run] || (d => d))(data);
	});

	this.trunk.mvlan = this.mvlan;

	Object.keys(this.vlans).forEach(id => this.add(id));
	if(!this.connected){
		this.mvlan.json({run: 'hi', ids: Object.keys(this.vlans)});
		this.connected = true;
	}

}

module.exports = Trunk;
<|endoftext|>


<commit_before>var config = require('config'),
    crypto = require('crypto'),
    fs     = require('fs'),
    Lazy   = require('lazy'),
    log    = require('./logger'),
    util   = require('util');

var users     = {},
    usersFile = (config.auth && config.auth.digestFile || ''),
    lastMtime = 0;

function usersFileChanged(done) {
    if (typeof done != 'function') {
        done = function() { };
    }
    fs.stat(usersFile, function(err, stats) {
        if (err) {
            return done(err);
        }
        if (!stats.isFile()) {
            return done(new Error(util.format(
                "File '%s' does not exist.", filename)));
        }
        if (stats.mtime != lastMtime) {
            lastMtime = stats.mtime;
            var newUsers = {};
            new Lazy(fs.createReadStream(usersFile))
                .lines
                .forEach(function(line) {
                    var pieces = line.toString().split(':');
                    if (pieces.length == 3) {
                        newUsers[pieces[0]] = {
                            username     : pieces[0],
                            digestRealm  : pieces[1],
                            passwordHash : pieces[2]
                        };
                    }
                }).join(function() {
                    users = newUsers;
                    var numUsers = Object.keys(users).length;
                    log.info(
                        'Loaded %d authorized user%s',
                        numUsers, (numUsers == 1 ? '' : 's'));
                    done();
                });
        }
    });
}

exports.init = function(done) {
    usersFileChanged(function(err) {
        if (err) {
            log.warn('Failed to read users file: ' + err.message);
        }
        done();
    });

    try {
        fs.watch(usersFile, { persistent: false }, function(event, filename) {
            if (event == 'change') {
                log.info('Users file changed, reloading');
                usersFileChanged();
            }
        });
    } catch (err) {
        log.warn('Failed to watch users file: ' + err.message);
    }
};

exports.test = function(username, password) {
    var user = users[username];
    if (user) {
        var md5 = crypto
            .createHash('md5')
            .update([username, user.digestRealm, password].join(':'))
            .digest('hex');
        if (md5 == user.passwordHash) {
            return user;
        } else {
            return false;
        }
    } else {
        return false;
    }
};

exports.get = function(username) {
    return users[username] || false;
};
<commit_msg>Be more helpful if users file is missing<commit_after>var config = require('config'),
    crypto = require('crypto'),
    fs     = require('fs'),
    Lazy   = require('lazy'),
    log    = require('./logger'),
    util   = require('util');

var users     = {},
    usersFile = (config.auth && config.auth.digestFile || '(filename missing)'),
    lastMtime = 0;

function usersFileChanged(done) {
    if (typeof done != 'function') {
        done = function() { };
    }
    fs.stat(usersFile, function(err, stats) {
        if (err) {
            return done(err);
        }
        if (!stats.isFile()) {
            return done(new Error(util.format(
                "File '%s' does not exist.", filename)));
        }
        if (stats.mtime != lastMtime) {
            lastMtime = stats.mtime;
            var newUsers = {};
            new Lazy(fs.createReadStream(usersFile))
                .lines
                .forEach(function(line) {
                    var pieces = line.toString().split(':');
                    if (pieces.length == 3) {
                        newUsers[pieces[0]] = {
                            username     : pieces[0],
                            digestRealm  : pieces[1],
                            passwordHash : pieces[2]
                        };
                    }
                }).join(function() {
                    users = newUsers;
                    var numUsers = Object.keys(users).length;
                    log.info(
                        'Loaded %d authorized user%s',
                        numUsers, (numUsers == 1 ? '' : 's'));
                    done();
                });
        }
    });
}

exports.init = function(done) {
    usersFileChanged(function(err) {
        if (err) {
            log.warn('Failed to read users file: ' + err.message);
        }
        done();
    });

    try {
        fs.watch(usersFile, { persistent: false }, function(event, filename) {
            if (event == 'change') {
                log.info('Users file changed, reloading');
                usersFileChanged();
            }
        });
    } catch (err) {
        log.warn('Failed to watch users file: ' + err.message);
    }
};

exports.test = function(username, password) {
    var user = users[username];
    if (user) {
        var md5 = crypto
            .createHash('md5')
            .update([username, user.digestRealm, password].join(':'))
            .digest('hex');
        if (md5 == user.passwordHash) {
            return user;
        } else {
            return false;
        }
    } else {
        return false;
    }
};

exports.get = function(username) {
    return users[username] || false;
};
<|endoftext|>


<commit_before>// --------------------
// utility functions
// --------------------

// exports
module.exports = function(Sequelize) {
	var Utils = Sequelize.Utils,
		_ = Utils._;

	return {
		// acts on object, inserts key/value pair at 1st position
		unshift: function(obj, key, value) {
			var temp = {};

			for (var thisKey in obj) {
				temp[thisKey] = obj[thisKey];
				delete obj[thisKey];
			}

			obj[key] = value;

			for (var thisKey in temp) {
				obj[thisKey] = temp[thisKey];
			}

			return obj;
		},

		// removes obj[key] and returns it
		pop: function(obj, key) {
			var value = obj[key];
			delete obj[key];
			return value;
		},

		// sets obj[key] = value, but deleting undefined values
		setNoUndef: function(obj, key, value) {
			if (value === undefined) {
				delete obj[key];
			} else {
				obj[key] = value;
			}
			return obj;
		},

		// sets obj[key] = value if obj[key] is undefined
		defaultNoUndef: function(obj, key, value) {
			if (obj[key] !== undefined || value === undefined) return obj;
			obj[key] = value;
			return obj;
		},

		// string format conversion
		camelToHuman: function(str) {
			return s[0].toUpperCase() + s.slice(1).replace(/([A-Z])/g, ' $1');
		},

		// checks if str ends with needle
		endsWith: function(str, needle) {
			return str.slice(str.length - needle.length) == needle;
		},

		// if value is function, run it with arguments and return result, otherwise return input
		functionValue: function(val) {
			if (!_.isFunction(val)) return val;

			var args = Array.prototype.slice.call(arguments, 1);
			return val.apply(args);
		}
	};
};
<commit_msg>extendNoUndef + defaultsNoUndef utility functions<commit_after>// --------------------
// utility functions
// --------------------

// exports
module.exports = function(Sequelize) {
	var Utils = Sequelize.Utils,
		_ = Utils._;

	return {
		// acts on object, inserts key/value pair at 1st position
		unshift: function(obj, key, value) {
			var temp = {};

			for (var thisKey in obj) {
				temp[thisKey] = obj[thisKey];
				delete obj[thisKey];
			}

			obj[key] = value;

			for (var thisKey in temp) {
				obj[thisKey] = temp[thisKey];
			}

			return obj;
		},

		// removes obj[key] and returns it
		pop: function(obj, key) {
			var value = obj[key];
			delete obj[key];
			return value;
		},

		// sets obj[key] = value, but deleting undefined values
		setNoUndef: function(obj, key, value) {
			if (value === undefined) {
				delete obj[key];
			} else {
				obj[key] = value;
			}
			return obj;
		},

		// sets obj[key] = value if obj[key] is undefined
		defaultNoUndef: function(obj, key, value) {
			if (obj[key] !== undefined || value === undefined) return obj;
			obj[key] = value;
			return obj;
		},

		// sets all keys from fromObj onto obj, deleting undefined values
		extendNoUndef: function(obj, fromObj) {
			_.forIn(fromObj, function(value, key) {
				if (value === undefined) {
					delete obj[key];
				} else {
					obj[key] = value;
				}
			});
			return obj;
		},

		// sets all keys from fromObj onto obj where obj[key] is undefined, ignoring undefined values
		defaultsNoUndef: function(obj, fromObj) {
			_.forIn(fromObj, function(value, key) {
				if (obj[key] === undefined && value !== undefined) obj[key] = value;
			});
			return obj;
		},

		// string format conversion
		camelToHuman: function(str) {
			return s[0].toUpperCase() + s.slice(1).replace(/([A-Z])/g, ' $1');
		},

		// checks if str ends with needle
		endsWith: function(str, needle) {
			return str.slice(str.length - needle.length) == needle;
		},

		// if value is function, run it with arguments and return result, otherwise return input
		functionValue: function(val) {
			if (!_.isFunction(val)) return val;

			var args = Array.prototype.slice.call(arguments, 1);
			return val.apply(args);
		}
	};
};
<|endoftext|>


<commit_before>var cp = require('child_process'),
    os = require('os'),
    fs = require('fs'),
    shellwords = require('shellwords'),
    semver = require('semver'),
    clone = require('clone');

var escapeQuotes = function (str) {
  if (typeof str === 'string') {
    return str.replace(/(["$`\\])/g, '\\$1');
  } else {
    return str;
  }
};

var inArray = function (arr, val) {
  for(var i = 0; i < arr.length; i++) {
    if (arr[i] === val) {
      return true;
    }
  }
  return false;
};

var notifySendFlags = {
  "u":            "urgency",
  "urgency":      "urgency",
  "t":            "expire-time",
  "e":            "expire-time",
  "expire":       "expire-time",
  "expire-time":  "expire-time",
  "i":            "icon",
  "icon":         "icon",
  "c":            "category",
  "category":     "category",
  "h":            "hint",
  "hint":         "hint"
};

module.exports.command = function (notifier, options, cb) {
  var notifier = shellwords.escape(notifier);
  return cp.exec(notifier + ' ' + options.join(' '), function (error, stdout, stderr) {
    if (error) return cb(error);
    cb(stderr, stdout);
  });
};

module.exports.fileCommand = function (notifier, options, cb) {
  return cp.execFile(notifier, options, function (error, stdout, stderr) {
    if (error) return cb(error, stdout);
    cb(stderr, stdout);
  });
};

module.exports.immediateFileCommand = function (notifier, options, cb) {
  notifierExists(notifier, function (exists) {
    if (!exists) return cb(new Error('Notifier (' + notifier + ') not found on system.'));
    cp.execFile(notifier, options);
    cb();
  });
};

function notifierExists (notifier, cb) {
  return fs.stat(notifier, function (err, stat) {
    if (err) return cb(false);
    cb(stat.isFile());
  });
}

var mapAppIcon = function (options) {
  if (options.appIcon) {
    options.icon = options.appIcon;
    delete options.appIcon;
  }

  return options;
};

var mapText = function (options) {
  if (options.text) {
    options.message = options.text;
    delete options.text;
  }

  return options;
};

var mapIconShorthand = function (options) {
  if (options.i) {
    options.icon = options.i;
    delete options.i;
  }

  return options;
};

module.exports.mapToNotifySend = function (options) {
  options = mapAppIcon(options);
  options = mapText(options);

  for (var key in options) {
    if (key === "message" || key === "title") continue;
    if (options.hasOwnProperty(key) && (notifySendFlags[key] != key)) {
      options[notifySendFlags[key]] = options[key];
      delete options[key];
    }
  }

  return options;
};

module.exports.mapToGrowl = function (options) {
  options = mapAppIcon(options);
  options = mapIconShorthand(options);

  if (options.text) {
    options.message = options.text;
    delete options.text;
  }

  if (options.icon && !Buffer.isBuffer(options.icon)) {
    options.icon = fs.readFileSync(options.icon);
  }

  return options;
};

module.exports.mapToMac = function (options) {
  options = mapIconShorthand(options);
  options = mapText(options);

  if (options.icon) {
    options.appIcon = options.icon;
    delete options.icon;
  }

  return options;
};

module.exports.actionJackerDecorator = function (emitter, options, fn, mapper) {
  options = clone(options);
  fn = fn || function (err, data) {};
  return function (err, data) {
    fn.apply(emitter, [err, data]);
    if (err || !mapper || !data) return;

    var key = mapper(data);
    if (!key) return;
    emitter.emit(key, emitter, options);
  };
};

module.exports.constructArgumentList = function (options, extra) {
  var args = [];
  extra = extra || {};

  // Massive ugly setup. Default args
  var initial = extra.initial || [];
  var keyExtra = extra.keyExtra || "";
  var allowedArguments = extra.allowedArguments || [];
  var noEscape = extra.noEscape !== void 0;
  var checkForAllowed = extra.allowedArguments !== void 0;
  var wrapper = extra.wrapper === void 0 ? '"' : extra.wrapper;

  var escapeFn = noEscape ? function (i) { return i; } : escapeQuotes;

  initial.forEach(function (val) {
    args.push(wrapper + escapeFn(val) + wrapper);
  });
  for(var key in options) {
    if (options.hasOwnProperty(key) && (!checkForAllowed || inArray(allowedArguments, key))) {
      args.push('-' + keyExtra + key, wrapper + escapeFn(options[key]) + wrapper);
    }
  }
  return args;
};

module.exports.mapToWin8 = function (options){

  options = mapAppIcon(options);
  options = mapText(options);

  if(options.icon){
    options.p = options.icon;
    delete options.icon;
  }

  if(options.message){
    options.m = options.message;
    delete options.message;
  }

  if (options.title) {
    options.t = options.title;
    delete options.title;
  }

  if (options.quiet || options.silent) {
    options.q = options.quiet || options.silent;
    delete options.quiet;
    delete options.silent;
  }

  if (options.q !== false) {
    options.q = true;
  } else {
    delete options.q;
  }

  if (options.sound) {
    delete options.q;
    delete options.sound;
  }

  if (options.wait) {
    options.w = options.wait;
    delete options.wait;
  }

  return options;
};

module.exports.mapToNotifu = function (options) {
  options = mapAppIcon(options);
  options = mapText(options);

  if(options.icon){
    options.i = options.icon;
    delete options.icon;
  }

  if(options.message){
    options.m = options.message;
    delete options.message;
  }

  if (options.title) {
    options.p = options.title;
    delete options.title;
  }

  if (options.time) {
    options.d = options.time;
    delete options.time;
  }

  if (options.t) {
    options.d = options.t;
    delete options.t;
  }

  return options;
};

module.exports.isMac = function() {
  return os.type() === 'Darwin';
};

module.exports.isMountainLion = function() {
  return os.type() === 'Darwin' && semver.satisfies(garanteeSemverFormat(os.release()), '>=12.0.0');
};

module.exports.isWin8 = function() {
  return os.type() === 'Windows_NT' && semver.satisfies(garanteeSemverFormat(os.release()), '>=6.2.9200');
};

module.exports.isLessThanWin8 = function() {
  return os.type() === 'Windows_NT' && semver.satisfies(garanteeSemverFormat(os.release()), '<6.2.9200');
};

function garanteeSemverFormat (version) {
  if (version.split('.').length === 2) {
    version += '.0';
  }
  return version;
}
<commit_msg>Adds default sound for notification center<commit_after>var cp = require('child_process'),
    os = require('os'),
    fs = require('fs'),
    shellwords = require('shellwords'),
    semver = require('semver'),
    clone = require('clone');

var escapeQuotes = function (str) {
  if (typeof str === 'string') {
    return str.replace(/(["$`\\])/g, '\\$1');
  } else {
    return str;
  }
};

var inArray = function (arr, val) {
  for(var i = 0; i < arr.length; i++) {
    if (arr[i] === val) {
      return true;
    }
  }
  return false;
};

var notifySendFlags = {
  "u":            "urgency",
  "urgency":      "urgency",
  "t":            "expire-time",
  "e":            "expire-time",
  "expire":       "expire-time",
  "expire-time":  "expire-time",
  "i":            "icon",
  "icon":         "icon",
  "c":            "category",
  "category":     "category",
  "h":            "hint",
  "hint":         "hint"
};

module.exports.command = function (notifier, options, cb) {
  var notifier = shellwords.escape(notifier);
  return cp.exec(notifier + ' ' + options.join(' '), function (error, stdout, stderr) {
    if (error) return cb(error);
    cb(stderr, stdout);
  });
};

module.exports.fileCommand = function (notifier, options, cb) {
  return cp.execFile(notifier, options, function (error, stdout, stderr) {
    if (error) return cb(error, stdout);
    cb(stderr, stdout);
  });
};

module.exports.immediateFileCommand = function (notifier, options, cb) {
  notifierExists(notifier, function (exists) {
    if (!exists) return cb(new Error('Notifier (' + notifier + ') not found on system.'));
    cp.execFile(notifier, options);
    cb();
  });
};

function notifierExists (notifier, cb) {
  return fs.stat(notifier, function (err, stat) {
    if (err) return cb(false);
    cb(stat.isFile());
  });
}

var mapAppIcon = function (options) {
  if (options.appIcon) {
    options.icon = options.appIcon;
    delete options.appIcon;
  }

  return options;
};

var mapText = function (options) {
  if (options.text) {
    options.message = options.text;
    delete options.text;
  }

  return options;
};

var mapIconShorthand = function (options) {
  if (options.i) {
    options.icon = options.i;
    delete options.i;
  }

  return options;
};

module.exports.mapToNotifySend = function (options) {
  options = mapAppIcon(options);
  options = mapText(options);

  for (var key in options) {
    if (key === "message" || key === "title") continue;
    if (options.hasOwnProperty(key) && (notifySendFlags[key] != key)) {
      options[notifySendFlags[key]] = options[key];
      delete options[key];
    }
  }

  return options;
};

module.exports.mapToGrowl = function (options) {
  options = mapAppIcon(options);
  options = mapIconShorthand(options);

  if (options.text) {
    options.message = options.text;
    delete options.text;
  }

  if (options.icon && !Buffer.isBuffer(options.icon)) {
    options.icon = fs.readFileSync(options.icon);
  }

  return options;
};

module.exports.mapToMac = function (options) {
  options = mapIconShorthand(options);
  options = mapText(options);

  if (options.icon) {
    options.appIcon = options.icon;
    delete options.icon;
  }

  if (options.sound === true) {
    options.sound = 'Bottle';
  }

  return options;
};

module.exports.actionJackerDecorator = function (emitter, options, fn, mapper) {
  options = clone(options);
  fn = fn || function (err, data) {};
  return function (err, data) {
    fn.apply(emitter, [err, data]);
    if (err || !mapper || !data) return;

    var key = mapper(data);
    if (!key) return;
    emitter.emit(key, emitter, options);
  };
};

module.exports.constructArgumentList = function (options, extra) {
  var args = [];
  extra = extra || {};

  // Massive ugly setup. Default args
  var initial = extra.initial || [];
  var keyExtra = extra.keyExtra || "";
  var allowedArguments = extra.allowedArguments || [];
  var noEscape = extra.noEscape !== void 0;
  var checkForAllowed = extra.allowedArguments !== void 0;
  var wrapper = extra.wrapper === void 0 ? '"' : extra.wrapper;

  var escapeFn = noEscape ? function (i) { return i; } : escapeQuotes;

  initial.forEach(function (val) {
    args.push(wrapper + escapeFn(val) + wrapper);
  });
  for(var key in options) {
    if (options.hasOwnProperty(key) && (!checkForAllowed || inArray(allowedArguments, key))) {
      args.push('-' + keyExtra + key, wrapper + escapeFn(options[key]) + wrapper);
    }
  }
  return args;
};

module.exports.mapToWin8 = function (options){

  options = mapAppIcon(options);
  options = mapText(options);

  if(options.icon){
    options.p = options.icon;
    delete options.icon;
  }

  if(options.message){
    options.m = options.message;
    delete options.message;
  }

  if (options.title) {
    options.t = options.title;
    delete options.title;
  }

  if (options.quiet || options.silent) {
    options.q = options.quiet || options.silent;
    delete options.quiet;
    delete options.silent;
  }

  if (options.q !== false) {
    options.q = true;
  } else {
    delete options.q;
  }

  if (options.sound) {
    delete options.q;
    delete options.sound;
  }

  if (options.wait) {
    options.w = options.wait;
    delete options.wait;
  }

  return options;
};

module.exports.mapToNotifu = function (options) {
  options = mapAppIcon(options);
  options = mapText(options);

  if(options.icon){
    options.i = options.icon;
    delete options.icon;
  }

  if(options.message){
    options.m = options.message;
    delete options.message;
  }

  if (options.title) {
    options.p = options.title;
    delete options.title;
  }

  if (options.time) {
    options.d = options.time;
    delete options.time;
  }

  if (options.t) {
    options.d = options.t;
    delete options.t;
  }

  return options;
};

module.exports.isMac = function() {
  return os.type() === 'Darwin';
};

module.exports.isMountainLion = function() {
  return os.type() === 'Darwin' && semver.satisfies(garanteeSemverFormat(os.release()), '>=12.0.0');
};

module.exports.isWin8 = function() {
  return os.type() === 'Windows_NT' && semver.satisfies(garanteeSemverFormat(os.release()), '>=6.2.9200');
};

module.exports.isLessThanWin8 = function() {
  return os.type() === 'Windows_NT' && semver.satisfies(garanteeSemverFormat(os.release()), '<6.2.9200');
};

function garanteeSemverFormat (version) {
  if (version.split('.').length === 2) {
    version += '.0';
  }
  return version;
}
<|endoftext|>


<commit_before>'use strict';
var Server = require('tiny-lr');
var path = require('path');
var url = require('url');

var utils = module.exports;

var port = 35729;

utils.startLRServer = function startLRServer(grunt, done) {
  var _ = grunt.util._;
  var _server;

  var options = _.defaults(grunt.config('livereload') || {}, {
    port: 35729
  });

  _server = new Server();
  grunt.log.writeln('... Starting Livereload server on ' + options.port + ' ...');
  port = options.port;

  _server.listen(options.port, done);
  return _server;
};

var getSnippet = function () {
  /*jshint quotmark:false */
  var snippet = [
          "<!-- livereload snippet -->",
          "<script>document.write('<script src=\"http://'",
          " + (location.host || 'localhost').split(':')[0]",
          " + ':" + port + "/livereload.js?snipver=1\"><\\/script>')",
          "</script>",
          ""
          ].join('\n');
  return snippet;
};

//
// This function returns a connect middleware that will insert a snippet
// of JavaScript needed to connect to the livereload server
//
// Usage:
// First require the needed module
// var lrSnippet = require('livereload/lib/utils').livereloadSnippet;
//
// Then in your grunt-contrib-connect config:
//
// server: {
//   dist: {
//     middleware: function() {
//       return [lrSnippet, folderMount('dist')]
//     }
//   },
//   test: {
//     middleware: function() {
//       return [lrSnippet(grunt), folderMount('dist')]
//     }
//   }
// }

utils.livereloadSnippet = function livereloadSnippet(req, res, next) {
  var write = res.write;

  var filepath = url.parse(req.url).pathname;
  filepath = filepath.slice(-1) === '/' ? filepath + 'index.html' : filepath;

  if (path.extname( filepath ) !== '.html') {
    return next();
  }

  res.write = function (string, encoding) {
    var body = string instanceof Buffer ? string.toString() : string;

    body = body.replace(/<\/body>/, function (w) {
      return getSnippet() + w;
    });

    if (string instanceof Buffer) {
      string = new Buffer(body);
    } else {
      string = body;
    }

    if (!this.headerSent) {
      this.setHeader('content-length', Buffer.byteLength(body, encoding));
      this._implicitHeader();
    }

    write.call(res, string, encoding);
  };

  next();
};
<commit_msg>Close GH-31: Public access to livereload script tag snippet.<commit_after>'use strict';
var Server = require('tiny-lr');
var path = require('path');
var url = require('url');

var utils = module.exports;

var port = 35729;

utils.startLRServer = function startLRServer(grunt, done) {
  var _ = grunt.util._;
  var _server;

  var options = _.defaults(grunt.config('livereload') || {}, {
    port: 35729
  });

  _server = new Server();
  grunt.log.writeln('... Starting Livereload server on ' + options.port + ' ...');
  port = options.port;

  _server.listen(options.port, done);
  return _server;
};

utils.getSnippet = function () {
  /*jshint quotmark:false */
  var snippet = [
          "<!-- livereload snippet -->",
          "<script>document.write('<script src=\"http://'",
          " + (location.host || 'localhost').split(':')[0]",
          " + ':" + port + "/livereload.js?snipver=1\"><\\/script>')",
          "</script>",
          ""
          ].join('\n');
  return snippet;
};

//
// This function returns a connect middleware that will insert a snippet
// of JavaScript needed to connect to the livereload server
//
// Usage:
// First require the needed module
// var lrSnippet = require('livereload/lib/utils').livereloadSnippet;
//
// Then in your grunt-contrib-connect config:
//
// server: {
//   dist: {
//     middleware: function() {
//       return [lrSnippet, folderMount('dist')]
//     }
//   },
//   test: {
//     middleware: function() {
//       return [lrSnippet(grunt), folderMount('dist')]
//     }
//   }
// }

utils.livereloadSnippet = function livereloadSnippet(req, res, next) {
  var write = res.write;

  var filepath = url.parse(req.url).pathname;
  filepath = filepath.slice(-1) === '/' ? filepath + 'index.html' : filepath;

  if (path.extname( filepath ) !== '.html') {
    return next();
  }

  res.write = function (string, encoding) {
    var body = string instanceof Buffer ? string.toString() : string;

    body = body.replace(/<\/body>/, function (w) {
      return utils.getSnippet() + w;
    });

    if (string instanceof Buffer) {
      string = new Buffer(body);
    } else {
      string = body;
    }

    if (!this.headerSent) {
      this.setHeader('content-length', Buffer.byteLength(body, encoding));
      this._implicitHeader();
    }

    write.call(res, string, encoding);
  };

  next();
};
<|endoftext|>


<commit_before>var crypto = require('crypto');

/*
 * blends two objects together, with second overriding the first
 * @param first {Object}
 * @param second {Object}
 */
function blend(first, second) {
    var mix = {};

    for(var key in first)
        mix[key] = first[key];
    for(var key in second)
        mix[key] = second[key];

    return mix;
}

/*
 * matches a criteria object with a message header
 * @param criteria {Object}
 * @param header {Object}
 * @return {Boolean}: true if they match, false otherwise
 */
function match(criteria, header) {
    var matches_source = (criteria.from === header.from || criteria.from === -1);
    var matches_subject = (criteria.subject === header.subject || criteria.subject === "-1");

    return matches_source && matches_subject;
}

/*
 * encrypts a message and signs it with HMAC
 * @param msg {Object}: the message to be secured
 * @param key {String}: the secret key to be used
 * @return {Object}: the secured message
 */
function secure(msg, key) {
    var cipher = crypto.createCipher('aes-256-ctr', key);
    var hmac = crypto.createHmac('sha256', key);
    var plaintext = (typeof msg === "object") ? JSON.stringify(msg) : msg.toString();

    var ciphertext = cipher.update(plaintext, 'utf8', 'base64') + cipher.final('base64');

    hmac.update(ciphertext);
    var mac = hmac.digest('base64');

    return {payload: ciphertext, mac: mac};
}

/* verifies an encrypted message and decryptes it if verified
 * @param msg {Object}: the encrypted message
 * @param key {String}: the secret key to be used
 * @return {Object|Boolean}: the decrypted message if verified, false otherwise
 */
function verify(msg, key) {
    var hmac = crypto.createHmac('sha256', key);

    hmac.update(msg.payload);
    var mac = hmac.digest('base64');

    if(mac === msg.mac) {
        var decipher = crypto.createDecipher('aes-256-ctr', key);
        var plaintext = decipher.update(msg.payload, 'base64', 'utf8') + decipher.final('utf8');

        // attempt to parse as json
        try {
            return JSON.parse(plaintext);
        }
        catch(err) {
            // if failed, return plaintext directly
            return plaintext;
        }
    }

    return false;
}

/*
 * returns a wrapper over crypto.DiffieHellman
 * @param prime {String}: a prime number to initialize with (optional)
 * @return {Object}
 */
function diffieHellman(prime) {
    var dhObj = null;
    var wrapper = {};

    if(!!prime)
        dhObj = crypto.createDiffieHellman(prime, 'base64');
    else
        dhObj = crypto.createDiffieHellman(512);

    wrapper.prime = dhObj.getPrime('base64');
    wrapper.publicKey = dhObj.generateKeys('base64');

    wrapper.computeSecret = function(remotePublicKey) {
        return dhObj.computeSecret(remotePublicKey, 'base64', 'base64');
    };

    return wrapper;
}

module.exports = {
    blend: blend,
    match: match,
    startTimeout: startTimeout,
    stopTimeout: stopTimeout,
    secure: secure,
    verify: verify,
    diffieHellman: diffieHellman
};
<commit_msg>Revert "deleted unused timeout methods"<commit_after>var crypto = require('crypto');

var _timer = null;  // holds the timeout timer

/*
 * blends two objects together, with second overriding the first
 * @param first {Object}
 * @param second {Object}
 */
function blend(first, second) {
    var mix = {};

    for(var key in first)
        mix[key] = first[key];
    for(var key in second)
        mix[key] = second[key];

    return mix;
}

/*
 * matches a criteria object with a message header
 * @param criteria {Object}
 * @param header {Object}
 * @return {Boolean}: true if they match, false otherwise
 */
function match(criteria, header) {
    var matches_source = (criteria.from === header.from || criteria.from === -1);
    var matches_subject = (criteria.subject === header.subject || criteria.subject === "-1");

    return matches_source && matches_subject;
}

/*
 * starts a timeout timer
 * @param callback {Function}
 */
function startTimeout(callback) {
    _timer = setTimeout(callback, 2000);
};

/*
 * stops a running timeout timer
 */
function stopTimeout() {
    clearTimeout(_timer);
}

/*
 * encrypts a message and signs it with HMAC
 * @param msg {Object}: the message to be secured
 * @param key {String}: the secret key to be used
 * @return {Object}: the secured message
 */
function secure(msg, key) {
    var cipher = crypto.createCipher('aes-256-ctr', key);
    var hmac = crypto.createHmac('sha256', key);
    var plaintext = (typeof msg === "object") ? JSON.stringify(msg) : msg.toString();

    var ciphertext = cipher.update(plaintext, 'utf8', 'base64') + cipher.final('base64');

    hmac.update(ciphertext);
    var mac = hmac.digest('base64');

    return {payload: ciphertext, mac: mac};
}

/* verifies an encrypted message and decryptes it if verified
 * @param msg {Object}: the encrypted message
 * @param key {String}: the secret key to be used
 * @return {Object|Boolean}: the decrypted message if verified, false otherwise
 */
function verify(msg, key) {
    var hmac = crypto.createHmac('sha256', key);

    hmac.update(msg.payload);
    var mac = hmac.digest('base64');

    if(mac === msg.mac) {
        var decipher = crypto.createDecipher('aes-256-ctr', key);
        var plaintext = decipher.update(msg.payload, 'base64', 'utf8') + decipher.final('utf8');

        // attempt to parse as json
        try {
            return JSON.parse(plaintext);
        }
        catch(err) {
            // if failed, return plaintext directly
            return plaintext;
        }
    }

    return false;
}

/*
 * returns a wrapper over crypto.DiffieHellman
 * @param prime {String}: a prime number to initialize with (optional)
 * @return {Object}
 */
function diffieHellman(prime) {
    var dhObj = null;
    var wrapper = {};

    if(!!prime)
        dhObj = crypto.createDiffieHellman(prime, 'base64');
    else
        dhObj = crypto.createDiffieHellman(512);

    wrapper.prime = dhObj.getPrime('base64');
    wrapper.publicKey = dhObj.generateKeys('base64');

    wrapper.computeSecret = function(remotePublicKey) {
        return dhObj.computeSecret(remotePublicKey, 'base64', 'base64');
    };

    return wrapper;
}

module.exports = {
    blend: blend,
    match: match,
    startTimeout: startTimeout,
    stopTimeout: stopTimeout,
    secure: secure,
    verify: verify,
    diffieHellman: diffieHellman
};
<|endoftext|>