<commit_before>var request = require('request-promise-native'),
    langs   = require('langs'),
    helpers = require('./helpers');

function search (show, season, episode, languages) {
    var headers = {
        'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36'
    };

    return request({
        uri:     helpers.addic7edURL + '/srch.php',
        qs:      {
            search: show.trim() + ' ' + helpers.formatShowNumber(season) + 'x' + helpers.formatShowNumber(episode)
        },
        headers: headers
    }).then(function (body) {
        if (/<b>\d+ results found<\/b>/.test(body)) {
            if (~body.indexOf('<b>0 results found<\/b>')) {
                // No result
                // =========
                console.log('[Search] Addic7ed.com error: No result.');
                return [];
            }

            // Multiple results
            // ================

            // Find result with proper season and episode in url
            // -------------------------------------------------
            var regexp   = new RegExp('href="(serie/[^/]+/' + parseInt(season) + '/' + parseInt(episode) + '/.+?)"'),
                urlMatch = body.match(regexp),
                url      = urlMatch && urlMatch[1];

            if (!url) {
                console.log('[Search] Addic7ed.com error: subtitles not found in a multiple result set.');
                return [];
            }

            return request({
                uri:     helpers.addic7edURL + '/' + url,
                headers: headers
            })
                .then(function (body) {
                    return findSubtitles(body, languages);
                })
                .catch(searchError);
        }

        return findSubtitles(body, languages);
    }).catch(searchError);
}

function findSubtitles (body, languages) {
    var subs          = [],
        refererMatch  = body.match(/\/show\/\d+/),
        referer       = refererMatch ? refererMatch[0] : '/show/1',
        versionRegExp = /Version (.+?),([^]+?)<\/table/g,
        versionMatch,
        version,
        subInfoRegExp = /class="language">([^]+?)<a[^]+?(% )?Completed[^]+?href="([^"]+?)"><strong>(?:most updated|Download)/g,
        subInfoMatch,
        lang,
        langId,
        notCompleted,
        link,
        distributionMatch,
        distribution,
        team;

    // Find subtitles HTML block parts
    // ===============================
    while ((versionMatch = versionRegExp.exec(body)) !== null) {
        version = versionMatch[1].toUpperCase();

        while ((subInfoMatch = subInfoRegExp.exec(versionMatch[2])) !== null) {
            notCompleted = subInfoMatch[2];
            if (notCompleted) {
                continue;
            }

            lang = subInfoMatch[1];
            // Find lang iso code 2B
            // ---------------------
            langId = langs.where('name', lang.replace(/\(.+\)/g, '').trim());
            langId = langId && langId['2B'] || lang.substr(0, 3).toLowerCase();

            link = subInfoMatch[3];

            if (languages && !~languages.indexOf(langId)) {
                continue;
            }

            distributionMatch = version.match(/HDTV|WEB(.DL|.?RIP)?|WR|BRRIP|BDRIP|BLURAY/i);

            distribution = distributionMatch
                ? distributionMatch[0].toUpperCase()
                .replace(/WEB(.DL|.?RIP)?|WR/, 'WEB-DL')
                .replace(/BRRIP|BDRIP|BLURAY/, 'BLURAY')
                : 'UNKNOWN';

            team = version.replace(/.?(REPACK|PROPER|[XH].?264|HDTV|480P|720P|1080P|2160P|AMZN|WEB(.DL|.?RIP)?|WR|BRRIP|BDRIP|BLURAY)+.?/g, '')
                    .trim().toUpperCase() || 'UNKNOWN';

            subs.push({
                lang:         lang,
                langId:       langId,
                distribution: distribution,
                team:         team,
                version:      version,
                link:         link,
                referer:      referer
            });
        }
    }

    return subs;
}

function searchError (err) {
    return console.log('[Search] Addic7ed.com error', err.statusCode, err.options && err.options.qs.search);
}

module.exports = search;
<commit_msg>add hearingi mpaired indicator to subInfo<commit_after>var request = require('request-promise-native'),
    langs   = require('langs'),
    helpers = require('./helpers');

function search (show, season, episode, languages) {
    var headers = {
        'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36'
    };

    return request({
        uri:     helpers.addic7edURL + '/srch.php',
        qs:      {
            search: show.trim() + ' ' + helpers.formatShowNumber(season) + 'x' + helpers.formatShowNumber(episode)
        },
        headers: headers
    }).then(function (body) {
        if (/<b>\d+ results found<\/b>/.test(body)) {
            if (~body.indexOf('<b>0 results found<\/b>')) {
                // No result
                // =========
                console.log('[Search] Addic7ed.com error: No result.');
                return [];
            }

            // Multiple results
            // ================

            // Find result with proper season and episode in url
            // -------------------------------------------------
            var regexp   = new RegExp('href="(serie/[^/]+/' + parseInt(season) + '/' + parseInt(episode) + '/.+?)"'),
                urlMatch = body.match(regexp),
                url      = urlMatch && urlMatch[1];

            if (!url) {
                console.log('[Search] Addic7ed.com error: subtitles not found in a multiple result set.');
                return [];
            }

            return request({
                uri:     helpers.addic7edURL + '/' + url,
                headers: headers
            })
                .then(function (body) {
                    return findSubtitles(body, languages);
                })
                .catch(searchError);
        }

        return findSubtitles(body, languages);
    }).catch(searchError);
}

function findSubtitles (body, languages) {
    var subs          = [],
        refererMatch  = body.match(/\/show\/\d+/),
        referer       = refererMatch ? refererMatch[0] : '/show/1',
        versionRegExp = /Version (.+?),([^]+?)<\/table/g,
        versionMatch,
        version,
        subInfoRegExp = /class="language">([^]+?)<a[^]+?(% )?Completed[^]+?href="([^"]+?)"><strong>(?:most updated|Download)/g,
        subInfoMatch,
        lang,
        langId,
        notCompleted,
        link,
        distributionMatch,
        distribution,
        team;

    // Find subtitles HTML block parts
    // ===============================
    while ((versionMatch = versionRegExp.exec(body)) !== null) {
        version = versionMatch[1].toUpperCase();

        while ((subInfoMatch = subInfoRegExp.exec(versionMatch[2])) !== null) {
            notCompleted = subInfoMatch[2];
            if (notCompleted) {
                continue;
            }

            lang = subInfoMatch[1];
            // Find lang iso code 2B
            // ---------------------
            langId = langs.where('name', lang.replace(/\(.+\)/g, '').trim());
            langId = langId && langId['2B'] || lang.substr(0, 3).toLowerCase();

            link = subInfoMatch[3];

            if (languages && !~languages.indexOf(langId)) {
                continue;
            }

            distributionMatch = version.match(/HDTV|WEB(.DL|.?RIP)?|WR|BRRIP|BDRIP|BLURAY/i);

            distribution = distributionMatch
                ? distributionMatch[0].toUpperCase()
                .replace(/WEB(.DL|.?RIP)?|WR/, 'WEB-DL')
                .replace(/BRRIP|BDRIP|BLURAY/, 'BLURAY')
                : 'UNKNOWN';

            team = version.replace(/.?(REPACK|PROPER|[XH].?264|HDTV|480P|720P|1080P|2160P|AMZN|WEB(.DL|.?RIP)?|WR|BRRIP|BDRIP|BLURAY)+.?/g, '')
                    .trim().toUpperCase() || 'UNKNOWN';

            subs.push({
                lang:            lang,
                langId:          langId,
                distribution:    distribution,
                team:            team,
                version:         version,
                link:            link,
                referer:         referer,
                hearingImpaired: versionMatch[2].includes("Hearing Impaired")
            });
        }
    }

    return subs;
}

function searchError (err) {
    return console.log('[Search] Addic7ed.com error', err.statusCode, err.options && err.options.qs.search);
}

module.exports = search;
<|endoftext|>


<commit_before>angular.module('app')

// Service for dealing with the creation of new spots and editing of existing spots
.service('NewSpot', function($filter) {
  var newSpot;

  // Initialize a new Spot
  var setNewSpot = function(geojsonObj) {
    if (!newSpot)
      newSpot = {};

    if (geojsonObj) {
      if (geojsonObj.geometry)
        newSpot.geometry = geojsonObj.geometry;
      if (geojsonObj.type)
        newSpot.type = geojsonObj.type
      if (geojsonObj.properties)
        newSpot.properties = geojsonObj.properties
      else {
        if (!newSpot.properties) {
          newSpot.properties = {
            date: $filter("date")(Date.now(), 'yyyy-MM-dd'),
            time: $filter("date")(Date.now(), 'HH:mm'),
            strike: 0,
            dip: 0
          };
        }
      }
    }
  }

  var getNewSpot = function() {
    return newSpot;
  }

  var clearNewSpot = function() {
    newSpot = null;
  }

  return {
    setNewSpot: setNewSpot,
    getNewSpot: getNewSpot,
    clearNewSpot: clearNewSpot
  };
})
  <commit_msg>removed default value of 0 for strike and dip<commit_after>angular.module('app')

// Service for dealing with the creation of new spots and editing of existing spots
.service('NewSpot', function($filter) {
  var newSpot;

  // Initialize a new Spot
  var setNewSpot = function(geojsonObj) {
    if (!newSpot)
      newSpot = {};

    if (geojsonObj) {
      if (geojsonObj.geometry)
        newSpot.geometry = geojsonObj.geometry;
      if (geojsonObj.type)
        newSpot.type = geojsonObj.type
      if (geojsonObj.properties)
        newSpot.properties = geojsonObj.properties
      else {
        if (!newSpot.properties) {
          newSpot.properties = {
            date: $filter("date")(Date.now(), 'yyyy-MM-dd'),
            time: $filter("date")(Date.now(), 'HH:mm')
          };
        }
      }
    }
  }

  var getNewSpot = function() {
    return newSpot;
  }

  var clearNewSpot = function() {
    newSpot = null;
  }

  return {
    setNewSpot: setNewSpot,
    getNewSpot: getNewSpot,
    clearNewSpot: clearNewSpot
  };
})
<|endoftext|>


<commit_before>/* vim: set ts=2 sw=2: */
/*
 * grunt-patternlibrary
 * https://github.com/sambowler/grunt-patternlibrary
 *
 * Copyright (c) 2014 Sam Bowler
 * Licensed under the MIT license.
 *
 * TODO: YAML front matter for each pattern
 * TODO: Class to each pattern wrapper
 * TODO: One pattern visible at a time (separate URLs for each)
 * TODO: HAML
 */
module.exports = function(grunt) {
  'use strict';

  var yamlFrontMatter = require('yaml-front-matter');
  var _ = require('lodash');

  grunt.registerMultiTask('patternlibrary', 'Create a pattern library with a set of HTML files.', function() {
    var moduleRoot = (function() {
      var dirArr = __dirname.split('/');

      dirArr.pop();

      return dirArr.join('/');
    })();
    var wrapperTemplate = moduleRoot + '/templates/wrapper.html';
    var patternTemplate = moduleRoot + '/templates/pattern.html';
    var options = this.options({
      cssFiles: [],
      wrapperTemplate: wrapperTemplate,
      patternTemplate: patternTemplate
    });

    function getPatternSlug(path, data) {
      if(data.hasOwnProperty('slug')) {
        return data.slug;
      } else {
        var fileName = path.split('/').pop();

        return fileName.split('.')[0];
      }
    }

    function processPattern(path, templatePath) {
        var fileContents = grunt.file.read(path);
        var frontMatter = yamlFrontMatter.loadFront(fileContents);
        var template = grunt.file.read(templatePath);
        var data = {
          content: frontMatter.__content,
          slug: getPatternSlug(path, frontMatter),
        };

        delete frontMatter.slug;
        delete frontMatter.__content;

        // Carry the rest of the front matter data to the object
        data = _.defaults(data, frontMatter);

        return grunt.template.process(template, { data: data });
    }

    function getWrapperMarkup(template, patternsArray) {
      var data = {
        data: {
          patterns: patternsArray
        }
      };

      return grunt.template.process(grunt.file.read(template), data);
    }

    var patterns = [];

    // Iterate over all specified file groups.
    this.files.forEach(function(f) {
      // Concat specified files.
      f.src.filter(function(filepath) {
        // Warn on and remove invalid source files (if nonull was set).
        if (!grunt.file.exists(filepath)) {
          grunt.log.warn('Source file "' + filepath + '" not found.');
          return false;
        } else {
          return true;
        }
      }).map(function(path) {
        patterns.push(processPattern(path, options.patternTemplate));
      });

      var src = getWrapperMarkup(options.wrapperTemplate, patterns);

      // Write the destination file.
      grunt.file.write(f.dest, src);

      getCss(options.additionalCss);

      // Print a success message.
      grunt.log.writeln('File "' + f.dest + '" created.');
    });
  });

};
<commit_msg>Temporarily removed useless function call<commit_after>/* vim: set ts=2 sw=2: */
/*
 * grunt-patternlibrary
 * https://github.com/sambowler/grunt-patternlibrary
 *
 * Copyright (c) 2014 Sam Bowler
 * Licensed under the MIT license.
 *
 * TODO: YAML front matter for each pattern
 * TODO: Class to each pattern wrapper
 * TODO: One pattern visible at a time (separate URLs for each)
 * TODO: HAML
 */
module.exports = function(grunt) {
  'use strict';

  var yamlFrontMatter = require('yaml-front-matter');
  var _ = require('lodash');

  grunt.registerMultiTask('patternlibrary', 'Create a pattern library with a set of HTML files.', function() {
    var moduleRoot = (function() {
      var dirArr = __dirname.split('/');

      dirArr.pop();

      return dirArr.join('/');
    })();
    var wrapperTemplate = moduleRoot + '/templates/wrapper.html';
    var patternTemplate = moduleRoot + '/templates/pattern.html';
    var options = this.options({
      cssFiles: [],
      wrapperTemplate: wrapperTemplate,
      patternTemplate: patternTemplate
    });

    function getPatternSlug(path, data) {
      if(data.hasOwnProperty('slug')) {
        return data.slug;
      } else {
        var fileName = path.split('/').pop();

        return fileName.split('.')[0];
      }
    }

    function processPattern(path, templatePath) {
        var fileContents = grunt.file.read(path);
        var frontMatter = yamlFrontMatter.loadFront(fileContents);
        var template = grunt.file.read(templatePath);
        var data = {
          content: frontMatter.__content,
          slug: getPatternSlug(path, frontMatter),
        };

        delete frontMatter.slug;
        delete frontMatter.__content;

        // Carry the rest of the front matter data to the object
        data = _.defaults(data, frontMatter);

        return grunt.template.process(template, { data: data });
    }

    function getWrapperMarkup(template, patternsArray) {
      var data = {
        data: {
          patterns: patternsArray
        }
      };

      return grunt.template.process(grunt.file.read(template), data);
    }

    var patterns = [];

    // Iterate over all specified file groups.
    this.files.forEach(function(f) {
      // Concat specified files.
      f.src.filter(function(filepath) {
        // Warn on and remove invalid source files (if nonull was set).
        if (!grunt.file.exists(filepath)) {
          grunt.log.warn('Source file "' + filepath + '" not found.');
          return false;
        } else {
          return true;
        }
      }).map(function(path) {
        patterns.push(processPattern(path, options.patternTemplate));
      });

      var src = getWrapperMarkup(options.wrapperTemplate, patterns);

      // Write the destination file.
      grunt.file.write(f.dest, src);

      // Print a success message.
      grunt.log.writeln('File "' + f.dest + '" created.');
    });
  });

};
<|endoftext|>


<commit_before>'use strict';
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var msgpack = require('msgpack-lite');
var net = require('net');
var stream = require('stream');
var crypto = require('crypto');
var FluentLoggerError = require('./logger-error');
var EventTime = require('./event-time').EventTime;

var codec = msgpack.createCodec();
codec.addExtPacker(0x00, EventTime, EventTime.pack);
codec.addExtUnpacker(0x00, EventTime.unpack);

function FluentSender(tag_prefix, options){
  options = options || {};
  this.tag_prefix = tag_prefix;
  this.host = options.host || 'localhost';
  this.port = options.port || 24224;
  this.path = options.path;
  this.timeout = options.timeout || 3.0;
  this.reconnectInterval = options.reconnectInterval || 600000; // Default is 10 minutes
  this.requireAckResponse = options.requireAckResponse;
  this.ackResponseTimeout = options.ackResponseTimeout || 190000; // Default is 190 seconds
  this.internalLogger = options.internalLogger || console;
  this._timeResolution = options.milliseconds ? 1 : 1000;
  this._socket = null;
  this._sendQueue = []; // queue for items waiting for being sent.
  this._eventEmitter = new EventEmitter();
  // options.security = { clientHostname: "client.localdomain", sharedKey: "very-secret-shared-key" }
  this.security = options.security || {
    clientHostname: null,
    sharedKey: null,
    username: '',
    passwort: ''
  };
  this.sharedKeySalt = crypto.randomBytes(16).toString('hex');
  // helo, pingpong, established
  this._status = null;
  this._connecting = false;
}

FluentSender.prototype.emit = function(/*[label] <data>, [timestamp], [callback] */){
  var label, data, timestamp, callback;
  var args = Array.prototype.slice.call(arguments);
  // Label must be string always
  if (typeof args[0] === 'string') label = args.shift();

  // Data can be almost anything
  data = args.shift();

  // Date can be either timestamp number or Date object
  if (typeof args[0] !== 'function') timestamp = args.shift();

  // Last argument is an optional callback
  if (typeof args[0] === 'function') callback = args.shift();

  var item = this._makePacketItem(label, data, timestamp);

  var error;
  var options;
  if (item.tag === null) {
    options = {
      tag_prefix: this.tag_prefix,
      label: label
    };
    error = new FluentLoggerError.MissingTag('tag is missing', options);
    this._handleEvent('error', error, callback);
    return;
  }
  if (typeof item.data !== 'object') {
    options = {
      tag_prefix: this.tag_prefix,
      label: label,
      record: item.data
    };
    error = new FluentLoggerError.DataTypeError('data must be an object', options);
    this._handleEvent('error', error, callback);
    return;
  }

  item.callback = callback;

  this._sendQueue.push(item);
  this._connect(() => {
    this._flushSendQueue();
  });
};

['addListener', 'on', 'once', 'removeListener', 'removeAllListeners', 'setMaxListeners', 'getMaxListeners'].forEach(function(attr, i){
  FluentSender.prototype[attr] = function(){
    return this._eventEmitter[attr].apply(this._eventEmitter, Array.prototype.slice.call(arguments));
  };
});

FluentSender.prototype.end = function(label, data, callback){
  if ((label != null && data != null)) {
    this.emit(label, data, (err) => {
      this._close();
      if (err) {
        this._handleEvent('error', err, callback);
      } else {
        callback && callback();
      }
    });
  } else {
    process.nextTick(() => {
      this._close();
      callback && callback();
    });
  }
};

FluentSender.prototype._close = function() {
  if (this._socket) {
    this._socket.end();
    this._socket = null;
    this._status = null;
  }
};

FluentSender.prototype._makePacketItem = function(label, data, time){
  var tag = null;
  if (this.tag_prefix && label) {
    tag = [this.tag_prefix, label].join('.');
  } else if (this.tag_prefix) {
    tag = this.tag_prefix;
  } else if (label) {
    tag = label;
  }

  if (typeof time !== 'number' && !(time instanceof EventTime)) {
    time = Math.floor((time ? time.getTime() : Date.now()) / this._timeResolution);
  }

  var packet = [tag, time, data];
  var options = {};
  if (this.requireAckResponse) {
    options = {
      chunk: crypto.randomBytes(16).toString('base64')
    };
    packet.push(options);
  }
  return {
    packet: msgpack.encode(packet, { codec: codec }),
    tag: tag,
    time: time,
    data: data,
    options: options
  };
};

FluentSender.prototype._connect = function(callback){
  if (this._connecting) {
    return;
  }

  this._connecting = true;
  process.nextTick(() => {
    if (this._socket === null) {
      this._connecting = false;
      this._doConnect(() => {
        callback();
      });
    } else {
      if (!this._socket.writable) {
        this._disconnect();
        this._connecting = false;
        process.nextTick(() => {
          this._connect(callback);
        });
      } else {
        this._connecting = false;
        process.nextTick(callback);
      }
    }
  });
};

FluentSender.prototype._doConnect = function(callback) {
  this._socket = new net.Socket();
  this._socket.setTimeout(this.timeout);
  this._socket.on('error', (err) => {
    if (this._socket) {
      this._disconnect();
      this._handleEvent('error', err);
    }
  });
  this._socket.on('connect', () => {
    this._handleEvent('connect');
  });
  if (this.path) {
    this._socket.connect(this.path, () => {
      callback();
    });
  } else {
    this._socket.connect(this.port, this.host, () => {
      if (this.security.clientHostname && this.security.sharedKey) {
        this._handshake(callback);
      } else {
        this._status = 'established';
        callback();
      }
    });
  }
};

FluentSender.prototype._disconnect = function() {
  this._socket && this._socket.destroy();
  this._socket = null;
  this._status = null;
};

FluentSender.prototype._handshake = function(callback) {
  if (this._status === 'established') {
    return;
  }
  this._status = 'helo';
  this._socket.once('data', (data) => {
    this._socket.pause();
    let heloStatus = this._checkHelo(data);
    if (!heloStatus.succeeded) {
      this.internalLogger.error("Received invalid HELO message from " + this._socket.remoteAddress);
      this._disconnect();
      return;
    }
    this._status = 'pingpong';
    this._socket.write(new Buffer(this._generatePing()), () => {
      this._socket.resume();
      this._socket.once('data', (data) => {
        let pongStatus = this._checkPong(data);
        if (!pongStatus.succeeded) {
          this.internalLogger.error(pongStatus.message);
          this._disconnect();
          return;
        }
        this._status = 'established';
        this.internalLogger.info('Established');
        callback();
      });
    });
  });
};

FluentSender.prototype._flushSendQueue = function() {
  if (this._flushingSendQueue)
    return;

  this._flushingSendQueue = true;
  process.nextTick(() => {
    if (!this._socket) {
      this._flushingSendQueue = false;
      return;
    }

    if (this._socket.writable) {
      this._doFlushSendQueue();
    } else {
      process.nextTick(waitToWrite);
    }
  });
};

FluentSender.prototype._doFlushSendQueue = function() {
  var item = this._sendQueue.shift();
  var timeoutId = null;
  if (item === undefined) {
    this._flushingSendQueue = false;
    // nothing written;
  } else {
    this._socket.write(new Buffer(item.packet), () => {
      if (this.requireAckResponse) {
        this._socket.once('data', (data) => {
          timeoutId && clearTimeout(timeoutId);
          var response = msgpack.decode(data, { codec: codec });
          if (response.ack !== item.options.chunk) {
            var error = new FluentLoggerError.ResponseError('ack in response and chunk id in sent data are different',
                                                            { ack: response.ack, chunk: item.options.chunk });
            this._handleEvent('error', error, item.callback);
          }
          item.callback && item.callback();
          process.nextTick(() => {
            this._doFlushSendQueue(); // if socket is still available
          });
        });
        timeoutId = setTimeout(() => {
          var error = new FluentLoggerError.ResponseTimeout('ack response timeout');
          this._handleEvent('error', error, item.callback);
        }, this.ackResponseTimeout);
      } else {
        item.callback && item.callback();
        process.nextTick(() => {
          this._doFlushSendQueue(); // if socket is still available
        });
      }
    });
    // TODO: how should we recorver if dequeued items are not sent.
  }
};

FluentSender.prototype._handleEvent = function _handleEvent(signal, data, callback) {
  callback && callback(data);
  if (this._eventEmitter.listenerCount(signal) > 0) {
    this._eventEmitter.emit(signal, data);
  }
};

FluentSender.prototype._setupErrorHandler = function _setupErrorHandler() {
  if (!this.reconnectInterval) {
    return;
  }
  this.on('error', (error) => {
    this._flushingSendQueue = false;
    this._status = null;
    this.internalLogger.error('Fluentd error', error);
    this.internalLogger.info('Fluentd will reconnect after ' + this.reconnectInterval / 1000 + ' seconds');
    setTimeout(() => {
      this.internalLogger.info('Fluentd is reconnecting...');
      this._connect(() => {
        this.internalLogger.info('Fluentd reconnection finished!!');
      });
    }, this.reconnectInterval);
  });
};

FluentSender.prototype._checkHelo = function _checkHelo(data) {
  // ['HELO', options(hash)]
  this.internalLogger.info('Checking HELO...');
  var message = msgpack.decode(data);
  if (message.length !== 2) {
    return { succeeded: false, message: 'Invalid format for HELO message' };
  }
  if (message[0] !== 'HELO') {
    return { succeeded: false, message: 'Invalid format for HELO message' };
  }
  var options = message[1] || {};
  this.sharedKeyNonce = options['nonce'] || '';
  this.authentication = options['auth'] || '';
  return { succeeded: true };
};

FluentSender.prototype._generatePing = function _generatePing() {
  // [
  //   'PING',
  //   client_hostname,
  //   shared_key_salt,
  //   sha512_hex(sharedkey_salt + client_hostname + nonce + shared_key),
  //   username || '',
  //   sha512_hex(auth_salt + username + password) || ''
  // ]
  var sharedKeyHexdigest = crypto.createHash('sha512')
      .update(this.sharedKeySalt)
      .update(this.security.clientHostname)
      .update(this.sharedKeyNonce)
      .update(this.security.sharedKey)
      .digest('hex');
  var ping = ['PING', this.security.clientHostname, this.sharedKeySalt, sharedKeyHexdigest];
  if (Buffer.isBuffer(this.authentication) && Buffer.byteLength(this.authentication) !== 0) {
    var passwordHexDigest = crypto.createHash('sha512')
        .update(this.authentication)
        .update(this.security.username || '')
        .update(this.security.password || '')
        .digest('hex');
    ping.push(this.username, passwordHexDigest);
  } else {
    ping.push('', '');
  }
  return msgpack.encode(ping);
};

FluentSender.prototype._checkPong = function _checkPong(data) {
  // [
  //   'PONG',
  //   bool(authentication result),
  //   'reason if authentication failed',
  //   server_hostname,
  //   sha512_hex(salt + server_hostname + nonce + sharedkey)
  // ]
  this.internalLogger.info('Checking PONG...');
  var message = msgpack.decode(data);
  if (message.length !== 5) {
    return false;
  }
  if (message[0] !== 'PONG') {
    return { succeeded: false, message: 'Invalid format for PONG message' };
  }
  var _pong = message[0];
  var authResult = message[1];
  var reason = message[2];
  var hostname = message[3];
  var sharedKeyHexdigest = message[4];
  if (!authResult) {
    return { succeeded: false, message: 'Authentication failed: ' + reason };
  }
  if (hostname === this.security.clientHostname) {
    return { succeeded: false, message: 'Same hostname between input and output: invalid configuration' };
  }
  var clientsideHexdigest = crypto.createHash('sha512')
      .update(this.sharedKeySalt)
      .update(hostname)
      .update(this.sharedKeyNonce)
      .update(this.security.sharedKey)
      .digest('hex');
  if (sharedKeyHexdigest !== clientsideHexdigest) {
    return { succeeded: false, message: 'Sharedkey mismatch' };
  }
  return { succeeded: true };
};

FluentSender.prototype.toStream = function(options) {
  if (typeof options === 'string') {
    options = {label: options};
  } else {
    options = options || {};
  }
  var label = options.label;
  if (!label) {
    throw new Error('label is needed');
  }
  var defaultEncoding = options.encoding || 'UTF-8';
  var writable = new stream.Writable();
  var dataString = '';
  writable._write = (chunk, encoding, callback) => {
    var dataArray = chunk.toString(defaultEncoding).split(/\n/);
    var next = () => {
      if (dataArray.length) {
        dataString += dataArray.shift();
      }
      if (!dataArray.length) {
        process.nextTick(callback);
        return;
      }
      this.emit(label, { message: dataString }, (err) => {
        if (err) {
          this._handleEvent('error', err, callback);
          return;
        }
        dataString = '';
        next();
      });
    };
    next();
  };
  return writable;
};

module.exports = exports = {};
exports.FluentSender = FluentSender;
<commit_msg>Handle _connecting properly<commit_after>'use strict';
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var msgpack = require('msgpack-lite');
var net = require('net');
var stream = require('stream');
var crypto = require('crypto');
var FluentLoggerError = require('./logger-error');
var EventTime = require('./event-time').EventTime;

var codec = msgpack.createCodec();
codec.addExtPacker(0x00, EventTime, EventTime.pack);
codec.addExtUnpacker(0x00, EventTime.unpack);

function FluentSender(tag_prefix, options){
  options = options || {};
  this.tag_prefix = tag_prefix;
  this.host = options.host || 'localhost';
  this.port = options.port || 24224;
  this.path = options.path;
  this.timeout = options.timeout || 3.0;
  this.reconnectInterval = options.reconnectInterval || 600000; // Default is 10 minutes
  this.requireAckResponse = options.requireAckResponse;
  this.ackResponseTimeout = options.ackResponseTimeout || 190000; // Default is 190 seconds
  this.internalLogger = options.internalLogger || console;
  this._timeResolution = options.milliseconds ? 1 : 1000;
  this._socket = null;
  this._sendQueue = []; // queue for items waiting for being sent.
  this._eventEmitter = new EventEmitter();
  // options.security = { clientHostname: "client.localdomain", sharedKey: "very-secret-shared-key" }
  this.security = options.security || {
    clientHostname: null,
    sharedKey: null,
    username: '',
    passwort: ''
  };
  this.sharedKeySalt = crypto.randomBytes(16).toString('hex');
  // helo, pingpong, established
  this._status = null;
  this._connecting = false;
}

FluentSender.prototype.emit = function(/*[label] <data>, [timestamp], [callback] */){
  var label, data, timestamp, callback;
  var args = Array.prototype.slice.call(arguments);
  // Label must be string always
  if (typeof args[0] === 'string') label = args.shift();

  // Data can be almost anything
  data = args.shift();

  // Date can be either timestamp number or Date object
  if (typeof args[0] !== 'function') timestamp = args.shift();

  // Last argument is an optional callback
  if (typeof args[0] === 'function') callback = args.shift();

  var item = this._makePacketItem(label, data, timestamp);

  var error;
  var options;
  if (item.tag === null) {
    options = {
      tag_prefix: this.tag_prefix,
      label: label
    };
    error = new FluentLoggerError.MissingTag('tag is missing', options);
    this._handleEvent('error', error, callback);
    return;
  }
  if (typeof item.data !== 'object') {
    options = {
      tag_prefix: this.tag_prefix,
      label: label,
      record: item.data
    };
    error = new FluentLoggerError.DataTypeError('data must be an object', options);
    this._handleEvent('error', error, callback);
    return;
  }

  item.callback = callback;

  this._sendQueue.push(item);
  this._connect(() => {
    this._flushSendQueue();
  });
};

['addListener', 'on', 'once', 'removeListener', 'removeAllListeners', 'setMaxListeners', 'getMaxListeners'].forEach(function(attr, i){
  FluentSender.prototype[attr] = function(){
    return this._eventEmitter[attr].apply(this._eventEmitter, Array.prototype.slice.call(arguments));
  };
});

FluentSender.prototype.end = function(label, data, callback){
  if ((label != null && data != null)) {
    this.emit(label, data, (err) => {
      this._close();
      if (err) {
        this._handleEvent('error', err, callback);
      } else {
        callback && callback();
      }
    });
  } else {
    process.nextTick(() => {
      this._close();
      callback && callback();
    });
  }
};

FluentSender.prototype._close = function() {
  if (this._socket) {
    this._socket.end();
    this._socket = null;
    this._status = null;
  }
};

FluentSender.prototype._makePacketItem = function(label, data, time){
  var tag = null;
  if (this.tag_prefix && label) {
    tag = [this.tag_prefix, label].join('.');
  } else if (this.tag_prefix) {
    tag = this.tag_prefix;
  } else if (label) {
    tag = label;
  }

  if (typeof time !== 'number' && !(time instanceof EventTime)) {
    time = Math.floor((time ? time.getTime() : Date.now()) / this._timeResolution);
  }

  var packet = [tag, time, data];
  var options = {};
  if (this.requireAckResponse) {
    options = {
      chunk: crypto.randomBytes(16).toString('base64')
    };
    packet.push(options);
  }
  return {
    packet: msgpack.encode(packet, { codec: codec }),
    tag: tag,
    time: time,
    data: data,
    options: options
  };
};

FluentSender.prototype._connect = function(callback){
  if (this._connecting) {
    return;
  }

  this._connecting = true;
  process.nextTick(() => {
    if (this._socket === null) {
      this._doConnect(() => {
        this._connecting = false;
        callback();
      });
    } else {
      if (!this._socket.writable) {
        this._disconnect();
        process.nextTick(() => {
          this._connecting = false;
          this._connect(callback);
        });
      } else {
        process.nextTick(() => {
          this._connecting = false;
          callback();
        });
      }
    }
  });
};

FluentSender.prototype._doConnect = function(callback) {
  this._socket = new net.Socket();
  this._socket.setTimeout(this.timeout);
  this._socket.on('error', (err) => {
    if (this._socket) {
      this._disconnect();
      this._handleEvent('error', err);
    }
  });
  this._socket.on('connect', () => {
    this._handleEvent('connect');
  });
  if (this.path) {
    this._socket.connect(this.path, () => {
      callback();
    });
  } else {
    this._socket.connect(this.port, this.host, () => {
      if (this.security.clientHostname && this.security.sharedKey) {
        this._handshake(callback);
      } else {
        this._status = 'established';
        callback();
      }
    });
  }
};

FluentSender.prototype._disconnect = function() {
  this._socket && this._socket.destroy();
  this._socket = null;
  this._status = null;
  this._connecting = false;
};

FluentSender.prototype._handshake = function(callback) {
  if (this._status === 'established') {
    return;
  }
  this._status = 'helo';
  this._socket.once('data', (data) => {
    this._socket.pause();
    let heloStatus = this._checkHelo(data);
    if (!heloStatus.succeeded) {
      this.internalLogger.error("Received invalid HELO message from " + this._socket.remoteAddress);
      this._disconnect();
      return;
    }
    this._status = 'pingpong';
    this._socket.write(new Buffer(this._generatePing()), () => {
      this._socket.resume();
      this._socket.once('data', (data) => {
        let pongStatus = this._checkPong(data);
        if (!pongStatus.succeeded) {
          this.internalLogger.error(pongStatus.message);
          this._disconnect();
          return;
        }
        this._status = 'established';
        this.internalLogger.info('Established');
        callback();
      });
    });
  });
};

FluentSender.prototype._flushSendQueue = function() {
  if (this._flushingSendQueue)
    return;

  this._flushingSendQueue = true;
  process.nextTick(() => {
    if (!this._socket) {
      this._flushingSendQueue = false;
      return;
    }

    if (this._socket.writable) {
      this._doFlushSendQueue();
    } else {
      process.nextTick(waitToWrite);
    }
  });
};

FluentSender.prototype._doFlushSendQueue = function() {
  var item = this._sendQueue.shift();
  var timeoutId = null;
  if (item === undefined) {
    this._flushingSendQueue = false;
    // nothing written;
  } else {
    this._socket.write(new Buffer(item.packet), () => {
      if (this.requireAckResponse) {
        this._socket.once('data', (data) => {
          timeoutId && clearTimeout(timeoutId);
          var response = msgpack.decode(data, { codec: codec });
          if (response.ack !== item.options.chunk) {
            var error = new FluentLoggerError.ResponseError('ack in response and chunk id in sent data are different',
                                                            { ack: response.ack, chunk: item.options.chunk });
            this._handleEvent('error', error, item.callback);
          }
          item.callback && item.callback();
          process.nextTick(() => {
            this._doFlushSendQueue(); // if socket is still available
          });
        });
        timeoutId = setTimeout(() => {
          var error = new FluentLoggerError.ResponseTimeout('ack response timeout');
          this._handleEvent('error', error, item.callback);
        }, this.ackResponseTimeout);
      } else {
        item.callback && item.callback();
        process.nextTick(() => {
          this._doFlushSendQueue(); // if socket is still available
        });
      }
    });
    // TODO: how should we recorver if dequeued items are not sent.
  }
};

FluentSender.prototype._handleEvent = function _handleEvent(signal, data, callback) {
  callback && callback(data);
  if (this._eventEmitter.listenerCount(signal) > 0) {
    this._eventEmitter.emit(signal, data);
  }
};

FluentSender.prototype._setupErrorHandler = function _setupErrorHandler() {
  if (!this.reconnectInterval) {
    return;
  }
  this.on('error', (error) => {
    this._flushingSendQueue = false;
    this._status = null;
    this.internalLogger.error('Fluentd error', error);
    this.internalLogger.info('Fluentd will reconnect after ' + this.reconnectInterval / 1000 + ' seconds');
    setTimeout(() => {
      this.internalLogger.info('Fluentd is reconnecting...');
      this._connect(() => {
        this.internalLogger.info('Fluentd reconnection finished!!');
      });
    }, this.reconnectInterval);
  });
};

FluentSender.prototype._checkHelo = function _checkHelo(data) {
  // ['HELO', options(hash)]
  this.internalLogger.info('Checking HELO...');
  var message = msgpack.decode(data);
  if (message.length !== 2) {
    return { succeeded: false, message: 'Invalid format for HELO message' };
  }
  if (message[0] !== 'HELO') {
    return { succeeded: false, message: 'Invalid format for HELO message' };
  }
  var options = message[1] || {};
  this.sharedKeyNonce = options['nonce'] || '';
  this.authentication = options['auth'] || '';
  return { succeeded: true };
};

FluentSender.prototype._generatePing = function _generatePing() {
  // [
  //   'PING',
  //   client_hostname,
  //   shared_key_salt,
  //   sha512_hex(sharedkey_salt + client_hostname + nonce + shared_key),
  //   username || '',
  //   sha512_hex(auth_salt + username + password) || ''
  // ]
  var sharedKeyHexdigest = crypto.createHash('sha512')
      .update(this.sharedKeySalt)
      .update(this.security.clientHostname)
      .update(this.sharedKeyNonce)
      .update(this.security.sharedKey)
      .digest('hex');
  var ping = ['PING', this.security.clientHostname, this.sharedKeySalt, sharedKeyHexdigest];
  if (Buffer.isBuffer(this.authentication) && Buffer.byteLength(this.authentication) !== 0) {
    var passwordHexDigest = crypto.createHash('sha512')
        .update(this.authentication)
        .update(this.security.username || '')
        .update(this.security.password || '')
        .digest('hex');
    ping.push(this.username, passwordHexDigest);
  } else {
    ping.push('', '');
  }
  return msgpack.encode(ping);
};

FluentSender.prototype._checkPong = function _checkPong(data) {
  // [
  //   'PONG',
  //   bool(authentication result),
  //   'reason if authentication failed',
  //   server_hostname,
  //   sha512_hex(salt + server_hostname + nonce + sharedkey)
  // ]
  this.internalLogger.info('Checking PONG...');
  var message = msgpack.decode(data);
  if (message.length !== 5) {
    return false;
  }
  if (message[0] !== 'PONG') {
    return { succeeded: false, message: 'Invalid format for PONG message' };
  }
  var _pong = message[0];
  var authResult = message[1];
  var reason = message[2];
  var hostname = message[3];
  var sharedKeyHexdigest = message[4];
  if (!authResult) {
    return { succeeded: false, message: 'Authentication failed: ' + reason };
  }
  if (hostname === this.security.clientHostname) {
    return { succeeded: false, message: 'Same hostname between input and output: invalid configuration' };
  }
  var clientsideHexdigest = crypto.createHash('sha512')
      .update(this.sharedKeySalt)
      .update(hostname)
      .update(this.sharedKeyNonce)
      .update(this.security.sharedKey)
      .digest('hex');
  if (sharedKeyHexdigest !== clientsideHexdigest) {
    return { succeeded: false, message: 'Sharedkey mismatch' };
  }
  return { succeeded: true };
};

FluentSender.prototype.toStream = function(options) {
  if (typeof options === 'string') {
    options = {label: options};
  } else {
    options = options || {};
  }
  var label = options.label;
  if (!label) {
    throw new Error('label is needed');
  }
  var defaultEncoding = options.encoding || 'UTF-8';
  var writable = new stream.Writable();
  var dataString = '';
  writable._write = (chunk, encoding, callback) => {
    var dataArray = chunk.toString(defaultEncoding).split(/\n/);
    var next = () => {
      if (dataArray.length) {
        dataString += dataArray.shift();
      }
      if (!dataArray.length) {
        process.nextTick(callback);
        return;
      }
      this.emit(label, { message: dataString }, (err) => {
        if (err) {
          this._handleEvent('error', err, callback);
          return;
        }
        dataString = '';
        next();
      });
    };
    next();
  };
  return writable;
};

module.exports = exports = {};
exports.FluentSender = FluentSender;
<|endoftext|>


<commit_before>var services = angular.module('services.request', ['ionic']);

services.factory('RequestService', function (AccountsService, AlertService, $q, $window, $http) {

    var service = {

        token: false,

        request: function (method, url, data) {

            var deferred = $q.defer();

            var pro = AccountsService.getPro();

                // Get token wheather Pro or not
                var domain, host;

                if (pro === true || pro === "true") {
                    domain = "https://api.travis-ci.com";
                    host = "api.travis-ci.com";
                    console.log("REQUEST: IS PRO");
                } else if (pro === false || pro === "false") {
                    console.log("REQUEST: IS NOT PRO");
                    domain = "https://api.travis-ci.org";
                    host = "api.travis-ci.org";
                } else {
                    AlertService.raiseAlert("Oops! Something went wrong and we couldn't make your request. Please try again.");
                }

                var headers = {
                    'Accept': 'application/vnd.travis-ci.2+json',
                    // 'User-Agent': 'MyClient/1.0.0',
                    // 'Host': host,
                    // 'Content-Type': 'application/json',
                    // 'Content-Length': 37
                };

                if (url != "/auth/github") {
                    headers.Authorization = "token " + service.token;
                }

                if (url.indexOf("logs") > -1) {
                    headers.Accept = "text/plain";
                }

                console.log("headers: " + headers);
                console.log(headers);

                $http({
                    url: domain + url,
                    method: method,
                    headers: headers,
                    data : data })
                    .success(function (data) {
                        // Success
                        deferred.resolve(data);
                    }).error(function (data){
                        // Failure
                        deferred.reject(data);
                    });

            return deferred.promise;

        }

    };

    return service;

});<commit_msg>Remove logs<commit_after>var services = angular.module('services.request', ['ionic']);

services.factory('RequestService', function (AccountsService, AlertService, $q, $window, $http) {

    var service = {

        token: false,

        request: function (method, url, data) {

            var deferred = $q.defer();

            var pro = AccountsService.getPro();

                // Get token wheather Pro or not
                var domain, host;

                if (pro === true || pro === "true") {
                    domain = "https://api.travis-ci.com";
                    host = "api.travis-ci.com";
                    console.log("REQUEST: IS PRO");
                } else if (pro === false || pro === "false") {
                    console.log("REQUEST: IS NOT PRO");
                    domain = "https://api.travis-ci.org";
                    host = "api.travis-ci.org";
                } else {
                    AlertService.raiseAlert("Oops! Something went wrong and we couldn't make your request. Please try again.");
                }

                var headers = {
                    'Accept': 'application/vnd.travis-ci.2+json',
                    // 'User-Agent': 'MyClient/1.0.0',
                    // 'Host': host,
                    // 'Content-Type': 'application/json',
                    // 'Content-Length': 37
                };

                if (url != "/auth/github") {
                    headers.Authorization = "token " + service.token;
                }

                if (url.indexOf("logs") > -1) {
                    headers.Accept = "text/plain";
                }

                $http({
                    url: domain + url,
                    method: method,
                    headers: headers,
                    data : data })
                    .success(function (data) {
                        // Success
                        deferred.resolve(data);
                    }).error(function (data){
                        // Failure
                        deferred.reject(data);
                    });

            return deferred.promise;

        }

    };

    return service;

});<|endoftext|>


<commit_before>var path = require('path');
var koa = require('koa');
var mount = require('koa-mount');
var serve = require('koa-static');
var auth = require('basic-auth');
var request = require('./request');
var terminal = require('../lib/terminal');
var kongSchema = require('../lib/kong-schemas');
var bodyParser = require('koa-bodyparser');

var Server = function() {
  this.start = function(backendConfig, angularConfig) {
    terminal.info('Starting Kong Dashboard on port ' + backendConfig.port);
    var webapp = serveStaticApp();
    var backend = serveProxy(backendConfig.kongUrl, backendConfig.kongRequestOpts);
    var config = serveConfigEndpoint(angularConfig);

    var app = new koa();
    if (Object.keys(backendConfig.basicAuth).length > 0) {
      terminal.debug('Protecting Kong Dashboard with Basic authentication');
      addBasicAuthMiddleware(app, backendConfig.basicAuth);
    }
    app
      .use(mount('/', webapp))
      .use(mount('/config', config))
      .use(mount('/proxy', backend));
    app.listen(backendConfig.port, () => {
      terminal.success('Kong Dashboard has started on port ' + backendConfig.port);
    });
  }
};

module.exports = Server;

function serveStaticApp() {
  return new koa()

    // Middleware adding response headers
    .use((ctx, next) => {
      // defense against clickjacking - https://www.owasp.org/index.php/Clickjacking
      ctx.set('X-Frame-Options', 'Deny');
      return next();
    })

    // Serving angular app.
    .use(serve(path.join(__dirname, '../public')));
}

function serveConfigEndpoint(config) {
  config.schemas = kongSchema.get(config.kong_version);
  return new koa()
    .use((ctx, next) => {
      ctx.set('content-type', 'text/javascript; charset=UTF-8');
      ctx.body = 'var __env = ' + JSON.stringify(config) + ';';
    })
}

function serveProxy(kongUrl, defaultOpts) {

  return new koa()
    // parse request body
    .use(bodyParser())

    // proxy requests
    .use((ctx, next) => {
      ctx.set('content-type', 'application/json; charset=utf-8');
      debugRequest(ctx.request);
      var opts = Object.assign({}, defaultOpts);
      Object.assign(opts, {
        method: ctx.req.method,
        url: kongUrl + ctx.req.url,
        json: true,
        body: ctx.request.body
      });
      return request.send(opts).then((response) => {
        debugResponse(response);
        ctx.body = response.body;
        ctx.status = response.statusCode;
      });
    });
}

function debugRequest(request) {
  terminal.debug({
    event: 'forwards request',
    method: request.method,
    path: request.url,
    headers: request.headers,
    body: request.body
  });
}

function debugResponse(response) {
  var body;
  try {
    body = JSON.parse(response.body);
  } catch(e) {
    body = response.body;
  }
  terminal.debug({
    event: 'receives response',
    headers: response.headers,
    status: response.statusCode,
    body: body
  });
}

function addBasicAuthMiddleware(app, credentials) {
  app.use((ctx, next) => {
    if (ctx.request.method == 'OPTIONS') {
      return next();
    }
    var user = auth(ctx);
    if (!user || !credentials[user.name] || credentials[user.name] != user.pass) {
      ctx.set('WWW-Authenticate', 'Basic');
      ctx.body = 'You must authenticate to access this dashboard';
      ctx.status = 401;
      return;
    }
    return next();
  });
}
<commit_msg>Add anonymous health check endpoint<commit_after>var path = require('path');
var koa = require('koa');
var mount = require('koa-mount');
var serve = require('koa-static');
var auth = require('basic-auth');
var request = require('./request');
var terminal = require('../lib/terminal');
var kongSchema = require('../lib/kong-schemas');
var bodyParser = require('koa-bodyparser');

var Server = function() {
    this.start = function(backendConfig, angularConfig) {
        terminal.info('Starting Kong Dashboard on port ' + backendConfig.port);
        var webapp = serveStaticApp();
        var backend = serveProxy(backendConfig.kongUrl, backendConfig.kongRequestOpts);
        var config = serveConfigEndpoint(angularConfig);
        var healthz = serveHealthz();

        var app = new koa();

        // Health check endpoint, mounted before the basic auth middleware
        app.use(mount('/healthz', healthz));

        if (Object.keys(backendConfig.basicAuth).length > 0) {
            terminal.debug('Protecting Kong Dashboard with Basic authentication');
            addBasicAuthMiddleware(app, backendConfig.basicAuth);
        }
        app
            .use(mount('/', webapp))
            .use(mount('/config', config))
            .use(mount('/proxy', backend));
        app.listen(backendConfig.port, () => {
            terminal.success('Kong Dashboard has started on port ' + backendConfig.port);
        });
    }
};

module.exports = Server;

function serveStaticApp() {
    return new koa()

    // Middleware adding response headers
        .use((ctx, next) => {
            // defense against clickjacking - https://www.owasp.org/index.php/Clickjacking
            ctx.set('X-Frame-Options', 'Deny');
            return next();
        })

        // Serving angular app.
        .use(serve(path.join(__dirname, '../public')));
}

function serveConfigEndpoint(config) {
    config.schemas = kongSchema.get(config.kong_version);
    return new koa()
        .use((ctx, next) => {
            ctx.set('content-type', 'text/javascript; charset=UTF-8');
            ctx.body = 'var __env = ' + JSON.stringify(config) + ';';
        })
}

function serveProxy(kongUrl, defaultOpts) {

    return new koa()
    // parse request body
        .use(bodyParser())

        // proxy requests
        .use((ctx, next) => {
            ctx.set('content-type', 'application/json; charset=utf-8');
            debugRequest(ctx.request);
            var opts = Object.assign({}, defaultOpts);
            Object.assign(opts, {
                method: ctx.req.method,
                url: kongUrl + ctx.req.url,
                json: true,
                body: ctx.request.body
            });
            return request.send(opts).then((response) => {
                debugResponse(response);
                ctx.body = response.body;
                ctx.status = response.statusCode;
            });
        });
}

function debugRequest(request) {
    terminal.debug({
        event: 'forwards request',
        method: request.method,
        path: request.url,
        headers: request.headers,
        body: request.body
    });
}

function debugResponse(response) {
    var body;
    try {
        body = JSON.parse(response.body);
    } catch(e) {
        body = response.body;
    }
    terminal.debug({
        event: 'receives response',
        headers: response.headers,
        status: response.statusCode,
        body: body
    });
}

function addBasicAuthMiddleware(app, credentials) {
    app.use((ctx, next) => {
        if (ctx.request.method == 'OPTIONS') {
            return next();
        }
        var user = auth(ctx);
        if (!user || !credentials[user.name] || credentials[user.name] != user.pass) {
            ctx.set('WWW-Authenticate', 'Basic');
            ctx.body = 'You must authenticate to access this dashboard';
            ctx.status = 401;
            return;
        }
        return next();
    });
}

function serveHealthz() {
    return new koa().use(ctx => {
        ctx.body = '';
    });
}
<|endoftext|>


<commit_before>require.config({
	baseUrl: "resources/js",
	paths: {
		"text": "requirejs/text",

		"jqueryui": "jquery/jquery-ui-1.10.4.min",
		"bootstrap": "jquery/bootstrap",
		"rajo.dom": "rajo/rajo.dom",
		"rajo.identity.persona": "rajo/rajo.identity.persona",
		"rajo.service": "rajo/rajo.service",
		"rajo.singlepage": "rajo/rajo.singlepage",
		"rajo.ui.bootstrapmodal": "rajo/rajo.ui.bootstrapmodal",
		"rajo.util": "rajo/rajo.util",
		"jquery.blockUI": "jquery/jquery.blockUI",
		"Ractive": "jquery/Ractive",
		"daterangepicker": "jquery/daterangepicker",
		"moment": "jquery/moment",

		"layout": "jquery/jquery.layout"
	},
	shim: {
		"jqueryui": { deps: ["jquery"] },
		"jquery.blockUI": { deps: ["jquery"] },
		"bootstrap": { deps: ["jquery"] },
		"daterangepicker": { deps: ["moment", "bootstrap"] },
		"layout": { deps: ["jqueryui"] }
	}
});
<commit_msg>Removed RAJO references from Require config. Should have done that in the last ticket. Ooops. refs #8<commit_after>require.config({
	baseUrl: "resources/js",
	paths: {
		"text": "requirejs/text",

		"jqueryui": "jquery/jquery-ui-1.10.4.min",
		"bootstrap": "jquery/bootstrap",
		"jquery.blockUI": "jquery/jquery.blockUI",
		"Ractive": "jquery/Ractive",
		"daterangepicker": "jquery/daterangepicker",
		"moment": "jquery/moment",
		"layout": "jquery/jquery.layout"
	},
	shim: {
		"jqueryui": { deps: ["jquery"] },
		"jquery.blockUI": { deps: ["jquery"] },
		"bootstrap": { deps: ["jquery"] },
		"daterangepicker": { deps: ["moment", "bootstrap"] },
		"layout": { deps: ["jqueryui"] }
	}
});
<|endoftext|>


<commit_before>var express = require('express')
, fs = require('fs')
, http  = require('http')
, logStream = openLog('app.log')
, path    = require('path')
, request = require('request')
, stops   = require('../data/stops')
, xml     = require('xml2js').parseString

var app     = express()

function openLog (logfile) {
  return fs.createWriteStream(logfile, {
    flags: 'a', encoding: 'utf8', mode: 0644
  })
}

function log (msg) {
  logStream.write(msg + '\n')
}

var extract_data = function (data, cb) {
  xml(data, function (err, res) {
    var result    = {}
    , data_body   = res['soap:Envelope']['soap:Body'][0]

    if (data_body === undefined || data_body.getUserRealTimeForecastExByStopResponse === undefined) {
      cb({message:'no data', name:'', lat:'', lon:'', next:[]})
      return
    }

    var data_response = data_body.getUserRealTimeForecastExByStopResponse[0]
    , data_result     = data_response.getUserRealTimeForecastExByStopResult[0]

    if (data_result == 'WsAuthenticationError') {
      cb({error: 'WsAuthenticationError'})
      return
    }

    var data          = JSON.parse(data_result)
    , info            = data.InfoNodo[0]

    result.name       = info.descrNodo
    result.lat        = info.coordLon
    result.lon        = info.coordLat

    result.next       = []

    data.Orari.forEach(function (departure) {
      result.next.push({
        l:   departure.codAzLinea,
        t:   departure.orario,
        ts:  departure.orarioSched,
        rt:  departure.statoPrevisione == 'Prev' ? 1 : 0,
        d:   departure.capDest
      })
    })

    cb(result)
  })
}

/* Routes
----------------------------------------------------------------------------- */

module.exports = function (options) {
  log('Starting...')

  app.set('port', process.env.PORT || options.port)

  process.on('uncaughtException', function (err) {
    log(err.stack)
  })

  process.once('SIGTERM', function () {
    log('Stopping...')

    app.on('close', function () {
      log('Stopped.')

      logStream.on('close', function () {
        process.exit(0)
      }).end()
    })
  })

  // development only
  if ('development' == app.get('env')) {
    app.use(express.errorHandler())
  }

  app.get('/oracle/:query', function (req, res) {
    request('http://m.atb.no/xmlhttprequest.php?service=routeplannerOracle.getOracleAnswer&question=' + req.params.query, function (error, response, body) {
      if (!error && response.statusCode == 200) {
        body = body.replace(/\n/g, '')
        body = body.replace(/([a-zA-Z])\.([a-zA-Z])/g, '$1.
$2')
        res.send(body)
      }
    })
  })

  app.get('/:var(rt|bybussen/5.0/Departure/Route)/:stopid/:api?', function (req, res){
    if (options.user === '' || options.pass === '') {
      res.json({error:'Webservice username and password missing in config file'})
      return
    }

    if (/\D/.test(req.params.stopid)) {
      res.json({error:'Not a valid stopid'})
      return
    }

    var env = '<?xml version="1.0" encoding="utf-8"?><soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/soap/envelope/"><soap12:Body><getUserRealTimeForecastExByStop xmlns="http://miz.it/infotransit"><auth><user>'+ options.user +'</user><password>'+ options.pass +'</password></auth><busStopId>' + req.params.stopid + '</busStopId><nForecast>20</nForecast></getUserRealTimeForecastExByStop></soap12:Body></soap12:Envelope>'

    var post_request = {
      host: 'st.atb.no',
      path: '/InfoTransit/userservices.asmx',
      port: 80,
      method: 'POST',
      headers: {
        'Cookie': 'cookie',
        'Content-Type': 'text/xml;charset="utf-8"',
        'SOAPAction': 'http://miz.it/infotransit/getUserRealTimeForecastExByStop',
        'Content-Length': Buffer.byteLength(env)
      }
    }

    var request = http.request( post_request, function (r) {
      var buffer = ''

      r.on( "data", function( data ) {
        buffer = buffer + data
      })

      r.on( "end", function( data ) {
        extract_data(buffer, function (d) {
          res.json(d)
        })
      })
    })

    request.write( env )
    request.end()
  })

  app.get('/stops', function (req, res) {
    res.json(stops.stops)
  })

  http.createServer(app).listen(app.get('port'), function(){
    log('Express server listening on port ' + app.get('port'))
  })
}
<commit_msg>Cleanup server code<commit_after>var express = require('express')
, fs = require('fs')
, http  = require('http')
, log_stream = openLog('app.log')
, path    = require('path')
, request = require('request')
, xml     = require('xml2js').parseString

var app     = express()
var stops   = require('../data/stops')

var extract_data = function (data, cb) {
  xml(data, function (err, res) {
    if (err) {
      cb(err, null)
    }

    var result    = {}
    , data_body   = res['soap:Envelope']['soap:Body'][0]

    if (data_body === undefined || data_body.getUserRealTimeForecastExByStopResponse === undefined) {
      cb({message:'no data', name:'', lat:'', lon:'', next:[]})
      return
    }

    var data_response = data_body.getUserRealTimeForecastExByStopResponse[0]
    , data_result     = data_response.getUserRealTimeForecastExByStopResult[0]

    if (data_result == 'WsAuthenticationError') {
      cb({error: 'WsAuthenticationError'})
      return
    }

    var data          = JSON.parse(data_result)
    , info            = data.InfoNodo[0]

    result.name       = info.descrNodo
    result.lat        = info.coordLon
    result.lon        = info.coordLat

    result.next       = []

    data.Orari.forEach(function (departure) {
      result.next.push({
        l:   departure.codAzLinea,
        t:   departure.orario,
        ts:  departure.orarioSched,
        rt:  departure.statoPrevisione == 'Prev' ? 1 : 0,
        d:   departure.capDest
      })
    })

    cb(null, result)
  })
}

/* Routes
----------------------------------------------------------------------------- */

module.exports = function (options) {
  log('Starting...')

  app.set('port', options.port || process.env.PORT)

  app.get('/oracle/:query', function (req, res) {
    request('http://m.atb.no/xmlhttprequest.php?service=routeplannerOracle.getOracleAnswer&question=' + req.params.query, function (error, response, body) {
      if (!error && response.statusCode == 200) {
        body = body.replace(/\n/g, '')
        body = body.replace(/([a-zA-Z])\.([a-zA-Z])/g, '$1.
$2')
        res.send(body)
      }
    })
  })

  app.get('/rt/:stopid', function (req, res){
    if (options.user === '' || options.pass === '') {
      res.json({error:'Webservice username and password missing in config file'})
      return
    }

    if (/\D/.test(req.params.stopid)) {
      res.json({error:'Not a valid stopid'})
      return
    }

    var env = '<?xml version="1.0" encoding="utf-8"?><soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/soap/envelope/"><soap12:Body><getUserRealTimeForecastExByStop xmlns="http://miz.it/infotransit"><auth><user>'+ options.user +'</user><password>'+ options.pass +'</password></auth><busStopId>' + req.params.stopid + '</busStopId><nForecast>20</nForecast></getUserRealTimeForecastExByStop></soap12:Body></soap12:Envelope>'

    var post_request = {
      host: 'st.atb.no',
      path: '/InfoTransit/userservices.asmx',
      port: 80,
      method: 'POST',
      headers: {
        'Cookie': 'cookie',
        'Content-Type': 'text/xml;charset="utf-8"',
        'SOAPAction': 'http://miz.it/infotransit/getUserRealTimeForecastExByStop',
        'Content-Length': Buffer.byteLength(env)
      }
    }

    var request = http.request( post_request, function (r) {
      var buffer = ''

      r.on( "data", function( data ) {
        buffer = buffer + data
      })

      r.on( "end", function( data ) {
        extract_data(buffer, function (err, data) {
          if (err) {
            res.json({error: 'Something went wrong'})
          }

          res.json(data)
        })
      })
    })

    request.write( env )
    request.end()
  })

  app.get('/stops', function (req, res) {
    res.json(stops.stops)
  })

  return app;
}

function openLog (logfile) {
  return fs.createWriteStream(logfile, {
    flags: 'a', encoding: 'utf8', mode: 0644
  })
}

function log (msg) {
  log_stream.write(msg + '\n')
}

process.on('uncaughtException', function (err) {
  log(err.stack)
})

process.once('SIGTERM', function () {
  log('Stopping...')

  app.on('close', function () {
    log('Stopped.')

    log_stream.on('close', function () {
      process.exit(0)
    }).end()
  })
})
<|endoftext|>


<commit_before>var io = require('socket.io');
var net = require('net');
var cfg = require('./config');
var ws = require('./web-server');
var logger = require('./logger');
var browser = require('./browser');
var reporter = require('./reporter');
var events = require('./events');
var util = require('./util');
var constant = require('./constants');
var Launcher = require('./launcher').Launcher;
var FileList = require('./file-list').List;
var watcher = require('./watcher');

// TODO(vojta): get this whole mess under test
exports.start = function(cliOptions) {
  var config = cfg.parseConfig(cliOptions.configFile, cliOptions);

  logger.setLevel(config.logLevel);
  logger.useColors(config.colors);

  var log = logger.create();
  var globalEmitter = new events.EventEmitter();
  var launcher = new Launcher();

  var fileList = new FileList(config.files, config.exclude, globalEmitter);
  // TODO(vojta): wait for fileList resolving before serving first request...
  fileList.refresh(function() {
    if (config.autoWatch) {
      watcher.watch(config.files, fileList);
    }
  });

  var webServer = ws.createWebServer(fileList, config.basePath, config.proxies, config.urlRoot);
  var socketServer = io.listen(webServer, {
    logger: logger.create('socket.io', 0),
    resource: config.urlRoot + 'socket.io',
    transports: ['websocket', 'xhr-polling', 'jsonp-polling']
  });

  webServer.on('error', function(e) {
    if (e.code === 'EADDRINUSE') {
      log.warn('Port %d in use', config.port);
      config.port++;
      webServer.listen(config.port);
    } else {
      throw e;
    }
  });

  webServer.listen(config.port, function() {
    log.info('Web server started at http://localhost:' + config.port + config.urlRoot);

    if (config.browsers && config.browsers.length) {
      launcher.launch(config.browsers, config.port, config.urlRoot);
    }
  });

  var resultReporter = reporter.createReporter(config.reporter, config.colors, config.basePath, config.urlRoot, config.reportSlowerThan);
  globalEmitter.bind(resultReporter);

  var capturedBrowsers = new browser.Collection(globalEmitter);
  var executionScheduled = false;
  var pendingCount = 0;
  var runningBrowsers;

  globalEmitter.on('browsers_change', function() {
    // TODO(vojta): send only to interested browsers
    socketServer.sockets.emit('info', capturedBrowsers.serialize());
  });

  globalEmitter.on('browser_register', function(browser) {
    if (browser.launchId) {
      launcher.markCaptured(browser.launchId);
    }

    if (config.singleRun && launcher.areAllCaptured()) {
      tryExecution();
    }
  });

  var tryExecution = function() {
    var nonReady = [];

    if (!capturedBrowsers.length) {
      log.warn('No captured browser, open http://localhost:' + config.port + config.urlRoot);
      return false;
    } else if (capturedBrowsers.areAllReady(nonReady)) {
      log.debug('All browsers are ready, executing');
      executionScheduled = false;
      capturedBrowsers.setAllIsReadyTo(false);
      capturedBrowsers.clearResults();
      pendingCount = capturedBrowsers.length;
      runningBrowsers = capturedBrowsers.toArray();
      globalEmitter.emit('run_start', runningBrowsers);
      socketServer.sockets.emit('execute', {});
      return true;
    } else {
      log.info('Delaying execution, these browsers are not ready: ' + nonReady.join(', '));
      executionScheduled = true;
      return false;
    }
  };

  globalEmitter.on('browser_complete', function(browser) {
    pendingCount--;

    if (!pendingCount) {
      // TODO(vojta): change runningBrowsers to collection and put getResults() there
      globalEmitter.emit('run_complete', runningBrowsers, capturedBrowsers.getResults());
    }
  });

  globalEmitter.on('run_complete', function(browsers) {
    if (config.singleRun) {
        // get the exit code
        // 0 - success (all executed tests passed, no disconnected browser, no error)
        // 1 - otherwise
        // TODO(vojta): move this logic into getResults()
        var code = browsers.reduce(function(code, browser) {
          var lastResults = browser.lastResult;
          return (lastResults.failed || lastResults.disconnected || lastResults.error) ? 1 : code;
        }, 0);

        disconnectBrowsers(code);
    } else if (executionScheduled) {
      tryExecution();
    }
  });

  socketServer.sockets.on('connection', function (socket) {
    log.debug('New browser has connected on socket ' + socket.id);
    browser.createBrowser(socket, capturedBrowsers, globalEmitter);
  });

  globalEmitter.on('file_list_modified', function() {
    log.debug('Execution (fired by autoWatch)');
    tryExecution();
  });

  // listen on port, waiting for runner
  var runnerServer = net.createServer(function (socket) {
    log.debug('Execution (fired by runner)');

    if (!capturedBrowsers.length) {
      log.warn('No captured browser, open http://localhost:' + config.port + config.urlRoot);
      socket.end('No captured browser, open http://localhost:' + config.port + config.urlRoot + '\n');
      return;
    }

    // TODO(vojta): we should immediately fire run, but delay serving the context.html
    log.debug('Refreshing all the files / patterns');
    fileList.refresh(function() {
      if (!tryExecution()) {
        socket.write('Waiting for previous execution...\n');
      }
    });

    globalEmitter.once('run_start', function() {
      var socketWrite = socket.write.bind(socket);

      resultReporter.adapters.push(socketWrite);

      // clean up, close runner socket
      globalEmitter.once('run_complete', function(browsers, results) {
        // get the exit code
        // 0 - success (all executed tests passed, no disconnected browser, no error)
        // 1 - otherwise
        // TODO(vojta): move this logic into getResults()
        var code = browsers.reduce(function(code, browser) {
          var lastResults = browser.lastResult;
          return (lastResults.failed || lastResults.disconnected || lastResults.error) ? 1 : code;
        }, 0);

        util.arrayRemove(resultReporter.adapters, socketWrite);
        socket.end(!code && constant.EXIT_CODE_0);
      });
    });
  });

  runnerServer.on('error', function(e) {
    if (e.code === 'EADDRINUSE') {
      log.warn('Port %d in use', config.runnerPort);
      config.runnerPort++;
      runnerServer.listen(config.runnerPort);
    } else {
      throw e;
    }
  });

  runnerServer.listen(config.runnerPort);

  runnerServer.on('listening', function() {
    if (config.runnerPort !== constant.DEFAULT_RUNNER_PORT) {
      log.info('To run via this server, use "testacular run --runner-port %d"', config.runnerPort);
    }
  });

  var disconnectBrowsers = function(code) {
    log.info('Disconnecting all browsers');
    socketServer.sockets.emit('server_disconnect');

    // Slightly hacky way of removing disconnect listeners
    // to suppress "browser disconnect" warnings
    // TODO(vojta): change the client to not send the event (if disconnected by purpose)
    var sockets = socketServer.sockets.sockets;
    Object.getOwnPropertyNames(sockets).forEach(function(key) {
      sockets[key].removeAllListeners('disconnect');
    });

    log.debug('Waiting for child processes to finish');
    launcher.kill(function() {
      process.exit(code || 0);
    });

    // TODO(vojta): remove this travis-ci hack
    if (process.env.TRAVIS) {
      process.exit(code || 0);
    }
  };

  try {
    process.on('SIGINT', disconnectBrowsers);
    process.on('SIGTERM', disconnectBrowsers);
  } catch (e) {
    // Windows doesn't support signals yet, so they simply don't get this handling.
    // https://github.com/joyent/node/issues/1553
  }
};
<commit_msg>Run tests on start if file watching is enabled<commit_after>fvar io = require('socket.io');
var net = require('net');
var cfg = require('./config');
var ws = require('./web-server');
var logger = require('./logger');
var browser = require('./browser');
var reporter = require('./reporter');
var events = require('./events');
var util = require('./util');
var constant = require('./constants');
var Launcher = require('./launcher').Launcher;
var FileList = require('./file-list').List;
var watcher = require('./watcher');

// TODO(vojta): get this whole mess under test
exports.start = function(cliOptions) {
  var config = cfg.parseConfig(cliOptions.configFile, cliOptions);

  logger.setLevel(config.logLevel);
  logger.useColors(config.colors);

  var log = logger.create();
  var globalEmitter = new events.EventEmitter();
  var launcher = new Launcher();

  var fileList = new FileList(config.files, config.exclude, globalEmitter);
  // TODO(vojta): wait for fileList resolving before serving first request...
  fileList.refresh(function() {
    if (config.autoWatch) {
      watcher.watch(config.files, fileList);
    }
  });

  var webServer = ws.createWebServer(fileList, config.basePath, config.proxies, config.urlRoot);
  var socketServer = io.listen(webServer, {
    logger: logger.create('socket.io', 0),
    resource: config.urlRoot + 'socket.io',
    transports: ['websocket', 'xhr-polling', 'jsonp-polling']
  });

  webServer.on('error', function(e) {
    if (e.code === 'EADDRINUSE') {
      log.warn('Port %d in use', config.port);
      config.port++;
      webServer.listen(config.port);
    } else {
      throw e;
    }
  });

  webServer.listen(config.port, function() {
    log.info('Web server started at http://localhost:' + config.port + config.urlRoot);

    if (config.browsers && config.browsers.length) {
      launcher.launch(config.browsers, config.port, config.urlRoot);
    }
  });

  var resultReporter = reporter.createReporter(config.reporter, config.colors, config.basePath, config.urlRoot, config.reportSlowerThan);
  globalEmitter.bind(resultReporter);

  var capturedBrowsers = new browser.Collection(globalEmitter);
  var executionScheduled = false;
  var pendingCount = 0;
  var runningBrowsers;

  globalEmitter.on('browsers_change', function() {
    // TODO(vojta): send only to interested browsers
    socketServer.sockets.emit('info', capturedBrowsers.serialize());
  });

  globalEmitter.on('browser_register', function(browser) {
    if (browser.launchId) {
      launcher.markCaptured(browser.launchId);
    }

    if ((config.autoWatch || config.singleRun) && launcher.areAllCaptured()) {
      tryExecution();
    }
  });

  var tryExecution = function() {
    var nonReady = [];

    if (!capturedBrowsers.length) {
      log.warn('No captured browser, open http://localhost:' + config.port + config.urlRoot);
      return false;
    } else if (capturedBrowsers.areAllReady(nonReady)) {
      log.debug('All browsers are ready, executing');
      executionScheduled = false;
      capturedBrowsers.setAllIsReadyTo(false);
      capturedBrowsers.clearResults();
      pendingCount = capturedBrowsers.length;
      runningBrowsers = capturedBrowsers.toArray();
      globalEmitter.emit('run_start', runningBrowsers);
      socketServer.sockets.emit('execute', {});
      return true;
    } else {
      log.info('Delaying execution, these browsers are not ready: ' + nonReady.join(', '));
      executionScheduled = true;
      return false;
    }
  };

  globalEmitter.on('browser_complete', function(browser) {
    pendingCount--;

    if (!pendingCount) {
      // TODO(vojta): change runningBrowsers to collection and put getResults() there
      globalEmitter.emit('run_complete', runningBrowsers, capturedBrowsers.getResults());
    }
  });

  globalEmitter.on('run_complete', function(browsers) {
    if (config.singleRun) {
        // get the exit code
        // 0 - success (all executed tests passed, no disconnected browser, no error)
        // 1 - otherwise
        // TODO(vojta): move this logic into getResults()
        var code = browsers.reduce(function(code, browser) {
          var lastResults = browser.lastResult;
          return (lastResults.failed || lastResults.disconnected || lastResults.error) ? 1 : code;
        }, 0);

        disconnectBrowsers(code);
    } else if (executionScheduled) {
      tryExecution();
    }
  });

  socketServer.sockets.on('connection', function (socket) {
    log.debug('New browser has connected on socket ' + socket.id);
    browser.createBrowser(socket, capturedBrowsers, globalEmitter);
  });

  globalEmitter.on('file_list_modified', function() {
    log.debug('Execution (fired by autoWatch)');
    tryExecution();
  });

  // listen on port, waiting for runner
  var runnerServer = net.createServer(function (socket) {
    log.debug('Execution (fired by runner)');

    if (!capturedBrowsers.length) {
      log.warn('No captured browser, open http://localhost:' + config.port + config.urlRoot);
      socket.end('No captured browser, open http://localhost:' + config.port + config.urlRoot + '\n');
      return;
    }

    // TODO(vojta): we should immediately fire run, but delay serving the context.html
    log.debug('Refreshing all the files / patterns');
    fileList.refresh(function() {
      if (!tryExecution()) {
        socket.write('Waiting for previous execution...\n');
      }
    });

    globalEmitter.once('run_start', function() {
      var socketWrite = socket.write.bind(socket);

      resultReporter.adapters.push(socketWrite);

      // clean up, close runner socket
      globalEmitter.once('run_complete', function(browsers, results) {
        // get the exit code
        // 0 - success (all executed tests passed, no disconnected browser, no error)
        // 1 - otherwise
        // TODO(vojta): move this logic into getResults()
        var code = browsers.reduce(function(code, browser) {
          var lastResults = browser.lastResult;
          return (lastResults.failed || lastResults.disconnected || lastResults.error) ? 1 : code;
        }, 0);

        util.arrayRemove(resultReporter.adapters, socketWrite);
        socket.end(!code && constant.EXIT_CODE_0);
      });
    });
  });

  runnerServer.on('error', function(e) {
    if (e.code === 'EADDRINUSE') {
      log.warn('Port %d in use', config.runnerPort);
      config.runnerPort++;
      runnerServer.listen(config.runnerPort);
    } else {
      throw e;
    }
  });

  runnerServer.listen(config.runnerPort);

  runnerServer.on('listening', function() {
    if (config.runnerPort !== constant.DEFAULT_RUNNER_PORT) {
      log.info('To run via this server, use "testacular run --runner-port %d"', config.runnerPort);
    }
  });

  var disconnectBrowsers = function(code) {
    log.info('Disconnecting all browsers');
    socketServer.sockets.emit('server_disconnect');

    // Slightly hacky way of removing disconnect listeners
    // to suppress "browser disconnect" warnings
    // TODO(vojta): change the client to not send the event (if disconnected by purpose)
    var sockets = socketServer.sockets.sockets;
    Object.getOwnPropertyNames(sockets).forEach(function(key) {
      sockets[key].removeAllListeners('disconnect');
    });

    log.debug('Waiting for child processes to finish');
    launcher.kill(function() {
      process.exit(code || 0);
    });

    // TODO(vojta): remove this travis-ci hack
    if (process.env.TRAVIS) {
      process.exit(code || 0);
    }
  };

  try {
    process.on('SIGINT', disconnectBrowsers);
    process.on('SIGTERM', disconnectBrowsers);
  } catch (e) {
    // Windows doesn't support signals yet, so they simply don't get this handling.
    // https://github.com/joyent/node/issues/1553
  }
};
<|endoftext|>


<commit_before>'use strict';

var path = require('path')
, basename = path.basename(__filename, '.js')
, debug = require('debug')('mill:server')
, formatik = require('formatik')
, fs = require('fs')
;

module.exports.load = function (packagename) {
  var names = [ packagename, 'mill-' + packagename ];
  var m = function (name) {
    try {
      return { manifest : require.resolve(name + '/manifest.json'), name : name };
    }
    catch (e) {
      return;
    }
  };
  var r = function (prev, cur) {
    return prev === undefined ? cur : prev;
  };
  var plugin = names.map(m).reduce(r, undefined);

  if (!plugin) {
    return;
  }

  var manifest = require(plugin.manifest);
  var stat = fs.statSync(plugin.manifest);
  manifest.packagename = plugin.name;
  manifest.url =  '/' + manifest.id;
  manifest.accessed = stat.atime;
  manifest.updated = stat.mtime;
  manifest.published = stat.ctime;

  return manifest;
}

module.exports.command = function (manifest, lang) {

  if (!manifest.packagename) {
    return;
  }

  return function (req, res, next) {
    var form = formatik.parse(req.query || {}, manifest.parameters || {},  req.lang || lang || 'en'),
        options = form.mget('value');

    req.manifest = manifest;
    req.options = options;

    if (!Object.keys(manifest.parameters).reduce(function (state, key) {
          if (state && manifest.parameters[key].require && !options[key]) {
            res.send(400, '`' + key + '` parameter is missing.');
            return false;
          }
          else {
            return state;
          }
        }, true)
    ) {
      return next();
    }

    var Transform = require("stream").Transform;
    var StreamIN = require('./StreamIN.js');
    var out, inp = new StreamIN();
    inp.on('begin', function () {
        res.statusCode = 200;
        res.setHeader('Content-Type', manifest.output || req.headers['content-type'] || 'text/plain');
      }
    );
    req.pipe(inp);
    out = require(manifest.packagename)(options, inp, manifest);
    if (! out instanceof Transform) {
      res.send(500, 'Invalid command.');
    }
    else {
      out.pipe(res);
      req.resume(); // ! req. sould be in pause
    }
  }
}
/*
module.exports.xxx = function (server, plugins) {
  if (Array.isArray(plugins)) {
    plugins.forEach(function(plugin) {
      }
    );
  }
}
*/

<commit_msg>english<commit_after>'use strict';

var path = require('path')
, basename = path.basename(__filename, '.js')
, debug = require('debug')('mill:server')
, formatik = require('formatik')
, fs = require('fs')
;

module.exports.load = function (packagename) {
  var names = [ packagename, 'mill-' + packagename ];
  var m = function (name) {
    try {
      return { manifest : require.resolve(name + '/manifest.json'), name : name };
    }
    catch (e) {
      return;
    }
  };
  var r = function (prev, cur) {
    return prev === undefined ? cur : prev;
  };
  var plugin = names.map(m).reduce(r, undefined);

  if (!plugin) {
    return;
  }

  var manifest = require(plugin.manifest);
  var stat = fs.statSync(plugin.manifest);
  manifest.packagename = plugin.name;
  manifest.url =  '/' + manifest.id;
  manifest.accessed = stat.atime;
  manifest.updated = stat.mtime;
  manifest.published = stat.ctime;

  return manifest;
}

module.exports.command = function (manifest, lang) {

  if (!manifest.packagename) {
    return;
  }

  return function (req, res, next) {
    var form = formatik.parse(req.query || {}, manifest.parameters || {},  req.lang || lang || 'en'),
        options = form.mget('value');

    req.manifest = manifest;
    req.options = options;

    if (!Object.keys(manifest.parameters).reduce(function (state, key) {
          if (state && manifest.parameters[key].require && !options[key]) {
            res.send(400, '`' + key + '` parameter is missing.');
            return false;
          }
          else {
            return state;
          }
        }, true)
    ) {
      return next();
    }

    var Transform = require("stream").Transform;
    var StreamIN = require('./StreamIN.js');
    var out, inp = new StreamIN();
    inp.on('begin', function () {
        res.statusCode = 200;
        res.setHeader('Content-Type', manifest.output || req.headers['content-type'] || 'text/plain');
      }
    );
    req.pipe(inp);
    out = require(manifest.packagename)(options, inp, manifest);
    if (! out instanceof Transform) {
      res.send(500, 'Invalid command.');
    }
    else {
      out.pipe(res);
      req.resume(); // ! req. must be paused
    }
  }
}
/*
module.exports.xxx = function (server, plugins) {
  if (Array.isArray(plugins)) {
    plugins.forEach(function(plugin) {
      }
    );
  }
}
*/

<|endoftext|>