<commit_before>'use strict';

const Transformer   = require('shark-transformer');
const zopfli        = require('node-zopfli');
const extend        = require('node.extend');
const co            = require('co');
const VError        = require('verror');
const path          = require('path');
const Tree          = require('shark-tree');

const loggerOpName = 'zopfli';

module.exports = Transformer.extend({
	init: function() {
		this.options = extend({}, this.optionsDefault, this.options);
		this.zopfliResults = {};
	},

	parseBless: function(content, destPath, options) {
		var time = this.logger.time();
		var sizeBefore = content.length;
		try {
			if (!this.logger.inPipe()) {
				this.logger.info({
					opName: loggerOpName,
					opType: this.logger.OP_TYPE.STARTED
				}, path.basename(destPath));
			}

			var result = zopfli.gzipSync(new Buffer(content), options);

			this.logger.info({
				opName: loggerOpName,
				opType: this.logger.OP_TYPE.FINISHED_SUCCESS,
				duration: time.delta(),
				size: {before: sizeBefore, after: result.toString('utf8').length}
			}, this.logger.inPipe() ? '' : path.basename(destPath));

			return result;
		}
		catch (error) {
			this.logger.warn({
				opName: loggerOpName,
				opType: this.logger.OP_TYPE.FINISHED_ERROR,
				duration: time.delta()
			}, path.basename(destPath), error.message);
			throw new VError(error, 'Zopfli error');
		}
	},

	transformTree: function *() {
		try {
			var _tree = this.tree.getTree();
			for (var destPath in _tree) {
				if (_tree.hasOwnProperty(destPath)) {
					yield this.transformTreeConcreteDest(destPath, _tree[destPath]);
				}
			}
		}
		catch (error) {
			throw new VError(error, 'TransformerZopfli#transformTree');
		}
	},

	transformTreeConcreteDest: function *(destPath, srcCollection) {
		return srcCollection.forEachSeries(co.wrap(function *(srcFile, index, done) {
			try {
				var options = extend({}, this.options, srcCollection.getOptions().zopfli);

				if (options.enabled === false) {
					this.logger.info('%s disabled, passing...', loggerOpName);
					done();
					return;
				}

				var data = this.parseBless(
					srcFile.getContent(),
					destPath,
					options
				);

				this.zopfliResults[destPath] = data;
				done();
			}
			catch (error) {
				done(new VError(error, 'Bless#transformTreeConcreteDest error'));
			}
		}.bind(this)));
	},

	transformTreeWithZopfliResults: function *() {
		var zopfliResults = this.zopfliResults;
		if (Object.keys(zopfliResults).length === 0) {
			return;
		}

		for (var destPath in zopfliResults) {
			if (!zopfliResults.hasOwnProperty(destPath)) {
				continue;
			}

			var ext = path.extname(destPath);

			if (ext === '.gz') {
				continue;
			}

			var basename = path.basename(destPath, ext);
			var dirname = path.dirname(destPath);

			var newDestPath = path.join(dirname, basename + ext + '.gz');
			var newFiles = {};
			newFiles[newDestPath] = {
				files: [],
				options: this.tree.getSrcCollectionByDest(destPath).getOptions()
			};

			var newTree = yield Tree(newFiles, this.logger);

			var zopfliResult = zopfliResults[destPath];
			newTree.getSrcCollectionByDest(newDestPath).setContent(zopfliResult);

			this.tree.merge(newTree);
		}
	},

	treeToTree: function *() {
		try {
			yield this.tree.fillContent();

			yield this.transformTree();
			yield this.transformTreeWithZopfliResults();

			return this.tree;
		}
		catch (error) {
			throw new VError(error, 'TransformerZopfli#treeToTree');
		}
	}
});<commit_msg>Add encoding param<commit_after>'use strict';

const Transformer   = require('shark-transformer');
const zopfli        = require('node-zopfli');
const extend        = require('node.extend');
const co            = require('co');
const VError        = require('verror');
const path          = require('path');
const Tree          = require('shark-tree');

const loggerOpName = 'zopfli';

module.exports = Transformer.extend({
	init: function() {
		this.options = extend({}, this.optionsDefault, this.options);
		this.zopfliResults = {};
	},

	compress: function(content, destPath, options) {
		var encoding = options.encoding ? options.encoding.read : null;
		var time = this.logger.time();
		var sizeBefore = content.length;
		try {
			if (!this.logger.inPipe()) {
				this.logger.info({
					opName: loggerOpName,
					opType: this.logger.OP_TYPE.STARTED
				}, path.basename(destPath));
			}

			var result = zopfli.gzipSync(new Buffer(content, encoding), options);

			this.logger.info({
				opName: loggerOpName,
				opType: this.logger.OP_TYPE.FINISHED_SUCCESS,
				duration: time.delta(),
				size: {before: sizeBefore, after: result.toString('utf8').length}
			}, this.logger.inPipe() ? '' : path.basename(destPath));

			return result;
		}
		catch (error) {
			this.logger.warn({
				opName: loggerOpName,
				opType: this.logger.OP_TYPE.FINISHED_ERROR,
				duration: time.delta()
			}, path.basename(destPath), error.message);
			throw new VError(error, 'Zopfli error');
		}
	},

	transformTree: function *() {
		try {
			var _tree = this.tree.getTree();
			for (var destPath in _tree) {
				if (_tree.hasOwnProperty(destPath)) {
					yield this.transformTreeConcreteDest(destPath, _tree[destPath]);
				}
			}
		}
		catch (error) {
			throw new VError(error, 'TransformerZopfli#transformTree');
		}
	},

	transformTreeConcreteDest: function *(destPath, srcCollection) {
		return srcCollection.forEachSeries(co.wrap(function *(srcFile, index, done) {
			try {
				var options = extend({}, this.options, srcCollection.getOptions().zopfli);
				options = extend(options, {
					encoding: srcCollection.getOptions().encoding
				});

				if (options.enabled === false) {
					this.logger.info('%s disabled, passing...', loggerOpName);
					done();
					return;
				}

				var data = this.compress(
					srcFile.getContent(),
					destPath,
					options
				);

				this.zopfliResults[destPath] = data;
				done();
			}
			catch (error) {
				done(new VError(error, 'Bless#transformTreeConcreteDest error'));
			}
		}.bind(this)));
	},

	transformTreeWithZopfliResults: function *() {
		var zopfliResults = this.zopfliResults;
		if (Object.keys(zopfliResults).length === 0) {
			return;
		}

		for (var destPath in zopfliResults) {
			if (!zopfliResults.hasOwnProperty(destPath)) {
				continue;
			}

			var ext = path.extname(destPath);

			if (ext === '.gz') {
				continue;
			}

			var basename = path.basename(destPath, ext);
			var dirname = path.dirname(destPath);

			var newDestPath = path.join(dirname, basename + ext + '.gz');
			var newFiles = {};
			newFiles[newDestPath] = {
				files: [],
				options: this.tree.getSrcCollectionByDest(destPath).getOptions()
			};

			var newTree = yield Tree(newFiles, this.logger);

			var zopfliResult = zopfliResults[destPath];
			newTree.getSrcCollectionByDest(newDestPath).setContent(zopfliResult);

			this.tree.merge(newTree);
		}
	},

	treeToTree: function *() {
		try {
			yield this.tree.fillContent();

			yield this.transformTree();
			yield this.transformTreeWithZopfliResults();

			return this.tree;
		}
		catch (error) {
			throw new VError(error, 'TransformerZopfli#treeToTree');
		}
	}
});<|endoftext|>


<commit_before>// Slovak

jQuery.extend( jQuery.fn.pickadate.defaults, {
    monthsFull: [ 'január', 'február', 'marec', 'apríl', 'máj', 'jún', 'júl', 'august', 'september', 'október', 'november', 'december' ],
    monthsShort: [ 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X', 'XI', 'XII' ],
    weekdaysFull: [ 'nedeľa', 'pondelok', 'utorok', 'streda', 'štvrtok', 'piatok', 'sobota' ],
    weekdaysShort: [ 'Ne', 'Po', 'Ut', 'St', 'Št', 'Pi', 'So' ],
    today: 'dnes',
    clear: 'vymazať',
    firstDay: 1,
    format: 'd. mmmm yyyy',
    formatSubmit: 'yyyy/mm/dd'
});<commit_msg>Correct short month names<commit_after>// Slovak

jQuery.extend( jQuery.fn.pickadate.defaults, {
    monthsFull: [ 'január', 'február', 'marec', 'apríl', 'máj', 'jún', 'júl', 'august', 'september', 'október', 'november', 'december' ],
    monthsShort: [ 'jan', 'feb', 'mar', 'apr', 'máj', 'jún', 'júl', 'aug', 'sep', 'okt', 'nov', 'dec' ],
    weekdaysFull: [ 'nedeľa', 'pondelok', 'utorok', 'streda', 'štvrtok', 'piatok', 'sobota' ],
    weekdaysShort: [ 'Ne', 'Po', 'Ut', 'St', 'Št', 'Pi', 'So' ],
    today: 'dnes',
    clear: 'vymazať',
    firstDay: 1,
    format: 'd. mmmm yyyy',
    formatSubmit: 'yyyy/mm/dd'
});<|endoftext|>


<commit_before>goog.provide('app.SimpleSearchController');
goog.provide('app.simpleSearchDirective');

goog.require('app');
goog.require('app.utils');
goog.require('app.Document');
/** @suppress {extraRequire} */
goog.require('ngeo.searchDirective');

/**
 * The directive for the auto-complete search field shown in the header
 * of every page.
 * @return {angular.Directive} Directive Definition Object.
 */
app.simpleSearchDirective = function() {
  return {
    restrict: 'E',
    controller: 'AppSimpleSearchController',
    bindToController: {
      selectHandler: '&appSelect'
    },
    controllerAs: 'searchCtrl',
    templateUrl: '/static/partials/simplesearch.html',
    link:
        /**
         * @param {angular.Scope} $scope Scope.
         * @param {angular.JQLite} element Element.
         */
        function($scope, element, attrs, ctrl) {

          var phoneScreen = app.constants.SCREEN.SMARTPHONE;

          if ($(element).closest('app-add-association').length) {
            ctrl.associationContext_ = true;
          }

          // Empty the search field on focus and blur.
          $('.page-header').find('input').on('focus blur', function() {
            $(this).typeahead('val', '');
          });

          //Remove the class 'show-search' when screen width > @phone (defined in LESS)
          $(window).resize(function resize() {
            if ($(window).width() > phoneScreen) {
              $('.show-search').removeClass('show-search');
              $('.logo.header, .menu-open-close.header').removeClass('no-opacity');
            }
          });

          element.on('click', function(e) {

            // collapse suggestions
            if ($('app-simple-search .header').is(e.target)) {
              $(e.target).siblings('.tt-suggestion').slideToggle();
            }

            // Trigger focus on search-icon click for .search
            if (window.innerWidth < phoneScreen) {
              if ($('.page-header .search-icon').is(e.target)) {
                $('.page-header').find('.quick-search').toggleClass('show-search');
                $('.page-header').find('.search').focus();
                $('.logo.header, .menu-open-close.header').toggleClass('no-opacity');
              }
            }
          });

          // hide the menu when click outside (smartphone)
          $('main').click(function(e) {
            if (window.innerWidth < phoneScreen) {
              $('.show-search').removeClass('show-search');
              $('.logo.header, .menu-open-close.header').removeClass('no-opacity');
            }
          });

          //show spinning gif while waiting for the results
          element.on('typeahead:asyncrequest', function() {
            element.find('input').addClass('loading-gif-typehead');
          });
          element.on('typeahead:asynccancel typeahead:asyncreceive', function() {
            element.find('input').removeClass('loading-gif-typehead');
          });

        }

  };
};

app.module.directive('appSimpleSearch', app.simpleSearchDirective);

/**
 * @constructor
 * @param {!angular.Scope} $scope Angular scope.
 * @param {angular.$compile} $compile Angular compile service.
 * @param {angular.$templateCache} $templateCache service
 * @param {app.Document} appDocument service
 * @param {app.Authentication} appAuthentication service
 * @param {angular.Attributes} $attrs Angular attributes.
 * @param {string} apiUrl Base URL of the API.
 * @param {angularGettext.Catalog} gettextCatalog Gettext catalog.
 * @ngInject
 */
app.SimpleSearchController = function(appDocument, $scope, $compile, $attrs, apiUrl,
    gettextCatalog, $templateCache, appAuthentication) {

  /**
   * @type {app.Document}
   * @private
   */
  this.documentService_ = appDocument;

  /**
   * Bound from directive.
   * @type {function({doc: appx.SimpleSearchDocument})|undefined}
   * @export
   */
  this.selectHandler;

  /**
   * @type {angular.$compile}
   * @private
   */
  this.compile_ = $compile;

  if (!$attrs['appSelect']) {
    // Angular puts a noop function when mapping an attribute to a
    // different local name. Hacking it out.
    // See https://docs.angularjs.org/api/ng/service/$compile#-scope-
    this.selectHandler = undefined;
  }

  /**
   * @type  {app.Authentication} appAuthentication
   * @private
   */
  this.auth_ = appAuthentication;

  /**
   * @type {angular.$templateCache}
   * @private
   */
  this.templatecache_ = $templateCache;

  /**
   * @type {string}
   * @private
   */
  this.apiUrl_ = apiUrl;

  /**
   * @type {!angular.Scope}
   * @private
   */
  this.scope_ = $scope;

  /**
   * @type {angularGettext.Catalog}
   * @private
   */
  this.gettextCatalog_ = gettextCatalog;

  /**
   * @type {TypeaheadOptions}
   * @export
   */
  this.options = /** @type {TypeaheadOptions} */ ({
    highlight: true,
    hint: true,
    minLength: 3
  });

  /**
   * @type {Array.<TypeaheadDataset>}
   * @export
   */
  this.datasets = [];

  /**
   * @type {string}
   * @private
   */
  this.datasetLimit_ = $attrs['dataset'];

  // create only given datasets
  for (var i = 0; i < this.datasetLimit_.length; i++) {
    switch (this.datasetLimit_[i]) {
      case 'u':
        this.datasets.push(this.createDataset_('users'));
        break;
      case 'o':
        this.datasets.push(this.createDataset_('outings'));
        break;
      case 'w':
        this.datasets.push(this.createDataset_('waypoints'));
        break;
      case 'r':
        this.datasets.push(this.createDataset_('routes'));
        break;
      default:
        break;
    }
  }

  /**
   * @type {boolean}
   * @private
   */
  this.associationContext_ = false;

  /**
   * @type {ngeox.SearchDirectiveListeners}
   * @export
   */
  this.listeners = /** @type {ngeox.SearchDirectiveListeners} */ ({
    select: app.SimpleSearchController.select_.bind(this)
  });
};

/**
 * @param {string} type The document type.
 * @return {TypeaheadDataset} A data set.
 * @private
 */
app.SimpleSearchController.prototype.createDataset_ = function(type) {
  var bloodhoundEngine = this.createAndInitBloodhound_(type);
  return /** @type {TypeaheadDataset} */({
    contents : type,
    source: bloodhoundEngine.ttAdapter(),
    display: function(doc) {
      if (doc) {
        return doc.label;
      }
    },
    limit: 20,
    templates: {
      header: (function() {
        return '
' + this.gettextCatalog_.getString(type) + '
';
      }).bind(this),
      footer: function(doc) {
        return '
More results
';
      },
      suggestion: function(doc) {
        if (doc) {
          this.scope_['doc'] = doc;
          return this.compile_('<app-suggestion class="tt-suggestion"></app-suggestion>')(this.scope_);
        } else {
          return '

';
        }
      }.bind(this),
      empty: function(res) {
        if ($('.header.empty').length === 0) {
          return this.compile_(this.templatecache_.get('/static/partials/suggestion_empty.html'))(this.scope_);
        }
      }.bind(this)
    }
  });
};

/**
 * @param {string} type The document type.
 * @return {Bloodhound} The bloodhound engine.
 * @private
 */
app.SimpleSearchController.prototype.createAndInitBloodhound_ = function(type) {
  var url = this.apiUrl_ + '/search?q=%QUERY';

  var bloodhound = new Bloodhound(/** @type {BloodhoundOptions} */({
    limit: 7,
    queryTokenizer: Bloodhound.tokenizers.whitespace,
    datumTokenizer: Bloodhound.tokenizers.obj.whitespace('label'),
    remote: {
      url: url,
      wildcard: '%QUERY',
      rateLimitWait: 50,
      prepare: (function(query, settings) {

        var url = settings['url'] + '&pl=' + this.gettextCatalog_.currentLanguage;

        if (this.datasetLimit_) {
          // add the Auth header if searching for users
          if (this.datasetLimit_.indexOf('u') > -1 && this.auth_.isAuthenticated()) {
            settings['headers'] = {
              'Authorization': 'JWT token="' + this.auth_.userData.token + '"'
            };
          }
          url = url + '&t=' + this.datasetLimit_.split('').join(',');
        }
        settings['url'] = url.replace('%QUERY', encodeURIComponent(query));
        return settings;
      }).bind(this),

      filter: (function(/** appx.SimpleSearchResponse */ resp) {
        var documentResponse =
                /** @type {appx.SimpleSearchDocumentResponse} */ (resp[type]);
        if (documentResponse) {
          var documents = documentResponse.documents;
          var currentLang = this.gettextCatalog_.currentLanguage;
          var hasAssociation;

          return documents.map(function(/** appx.SimpleSearchDocument */ doc) {
            hasAssociation = this.documentService_.hasAssociation(type,  doc.document_id);

            var locale = doc.locales[0];
            doc.label = type === ('routes' && locale.title_prefix) ? locale.title_prefix + ' : ' : '';
            doc.label += locale.title;

            if (currentLang !== locale.lang) {
              doc.label += ' (' + locale.lang + ')';
            }
            doc.documentType = type;

            // don't show already associated docs in the results, but only in the app-add-association
            // -> everything should be shown in the main simple-search.
            if (!this.associationContext_ || (this.associationContext_ && !hasAssociation)) {
              return doc;
            }
          }.bind(this));
        }
      }).bind(this)
    }
  }));
  bloodhound.initialize();
  return bloodhound;
};

/**
 * @param {jQuery.Event} event Event.
 * @param {!appx.SimpleSearchDocument} doc Suggested document.
 * @param {TypeaheadDataset} dataset Dataset.
 * @this {app.SimpleSearchController}
 * @private
 */
app.SimpleSearchController.select_ = function(event, doc, dataset) {
  if (this.selectHandler) {
    this.selectHandler({'doc': doc});
  } else {
    var lang = doc.locales[0].lang;
    var type = doc.documentType;
    var url = app.utils.buildDocumentUrl(type, doc.document_id, lang);
    window.location.href = url;
  }
};

app.module.controller('AppSimpleSearchController', app.SimpleSearchController);
<commit_msg>don't show 'more results' if typing in an association-tool<commit_after>goog.provide('app.SimpleSearchController');
goog.provide('app.simpleSearchDirective');

goog.require('app');
goog.require('app.utils');
goog.require('app.Document');
/** @suppress {extraRequire} */
goog.require('ngeo.searchDirective');

/**
 * The directive for the auto-complete search field shown in the header
 * of every page.
 * @return {angular.Directive} Directive Definition Object.
 */
app.simpleSearchDirective = function() {
  return {
    restrict: 'E',
    controller: 'AppSimpleSearchController',
    bindToController: {
      selectHandler: '&appSelect'
    },
    controllerAs: 'searchCtrl',
    templateUrl: '/static/partials/simplesearch.html',
    link:
        /**
         * @param {angular.Scope} $scope Scope.
         * @param {angular.JQLite} element Element.
         */
        function($scope, element, attrs, ctrl) {

          var phoneScreen = app.constants.SCREEN.SMARTPHONE;

          if ($(element).closest('app-add-association').length) {
            ctrl.associationContext_ = true;
          }

          // Empty the search field on focus and blur.
          $('.page-header').find('input').on('focus blur', function() {
            $(this).typeahead('val', '');
          });

          //Remove the class 'show-search' when screen width > @phone (defined in LESS)
          $(window).resize(function resize() {
            if ($(window).width() > phoneScreen) {
              $('.show-search').removeClass('show-search');
              $('.logo.header, .menu-open-close.header').removeClass('no-opacity');
            }
          });
          element.on('click', function(e) {

            // collapse suggestions
            if ($('app-simple-search .header').is(e.target)) {
              $(e.target).siblings('.tt-suggestion').slideToggle();
            }

            // Trigger focus on search-icon click for .search
            if (window.innerWidth < phoneScreen) {
              if ($('.page-header .search-icon').is(e.target)) {
                $('.page-header').find('.quick-search').toggleClass('show-search');
                $('.page-header').find('.search').focus();
                $('.logo.header, .menu-open-close.header').toggleClass('no-opacity');
              }
            }
          });

          // hide the menu when click outside (smartphone)
          $('main').click(function(e) {
            if (window.innerWidth < phoneScreen) {
              $('.show-search').removeClass('show-search');
              $('.logo.header, .menu-open-close.header').removeClass('no-opacity');
            }
          });

          //show spinning gif while waiting for the results
          element.on('typeahead:asyncrequest', function() {
            element.find('input').addClass('loading-gif-typehead');
          });
          element.on('typeahead:asynccancel typeahead:asyncreceive', function() {
            element.find('input').removeClass('loading-gif-typehead');
          });

        }

  };
};

app.module.directive('appSimpleSearch', app.simpleSearchDirective);

/**
 * @constructor
 * @param {!angular.Scope} $scope Angular scope.
 * @param {angular.$compile} $compile Angular compile service.
 * @param {angular.$templateCache} $templateCache service
 * @param {app.Document} appDocument service
 * @param {app.Authentication} appAuthentication service
 * @param {angular.Attributes} $attrs Angular attributes.
 * @param {string} apiUrl Base URL of the API.
 * @param {angularGettext.Catalog} gettextCatalog Gettext catalog.
 * @ngInject
 */
app.SimpleSearchController = function(appDocument, $scope, $compile, $attrs, apiUrl,
    gettextCatalog, $templateCache, appAuthentication) {

  /**
   * @type {app.Document}
   * @private
   */
  this.documentService_ = appDocument;

  /**
   * Bound from directive.
   * @type {function({doc: appx.SimpleSearchDocument})|undefined}
   * @export
   */
  this.selectHandler;

  /**
   * @type {angular.$compile}
   * @private
   */
  this.compile_ = $compile;

  if (!$attrs['appSelect']) {
    // Angular puts a noop function when mapping an attribute to a
    // different local name. Hacking it out.
    // See https://docs.angularjs.org/api/ng/service/$compile#-scope-
    this.selectHandler = undefined;
  }

  /**
   * @type  {app.Authentication} appAuthentication
   * @private
   */
  this.auth_ = appAuthentication;

  /**
   * @type {angular.$templateCache}
   * @private
   */
  this.templatecache_ = $templateCache;

  /**
   * @type {string}
   * @private
   */
  this.apiUrl_ = apiUrl;

  /**
   * @type {!angular.Scope}
   * @private
   */
  this.scope_ = $scope;

  /**
   * @type {angularGettext.Catalog}
   * @private
   */
  this.gettextCatalog_ = gettextCatalog;

  /**
   * @type {TypeaheadOptions}
   * @export
   */
  this.options = /** @type {TypeaheadOptions} */ ({
    highlight: true,
    hint: true,
    minLength: 3
  });

  /**
   * @type {Array.<TypeaheadDataset>}
   * @export
   */
  this.datasets = [];

  /**
   * @type {string}
   * @private
   */
  this.datasetLimit_ = $attrs['dataset'];

  // create only given datasets
  for (var i = 0; i < this.datasetLimit_.length; i++) {
    switch (this.datasetLimit_[i]) {
      case 'u':
        this.datasets.push(this.createDataset_('users'));
        break;
      case 'o':
        this.datasets.push(this.createDataset_('outings'));
        break;
      case 'w':
        this.datasets.push(this.createDataset_('waypoints'));
        break;
      case 'r':
        this.datasets.push(this.createDataset_('routes'));
        break;
      default:
        break;
    }
  }

  /**
   * @type {boolean}
   * @private
   */
  this.associationContext_ = false;

  /**
   * @type {ngeox.SearchDirectiveListeners}
   * @export
   */
  this.listeners = /** @type {ngeox.SearchDirectiveListeners} */ ({
    select: app.SimpleSearchController.select_.bind(this)
  });
};

/**
 * @param {string} type The document type.
 * @return {TypeaheadDataset} A data set.
 * @private
 */
app.SimpleSearchController.prototype.createDataset_ = function(type) {
  var bloodhoundEngine = this.createAndInitBloodhound_(type);
  return /** @type {TypeaheadDataset} */({
    contents : type,
    source: bloodhoundEngine.ttAdapter(),
    display: function(doc) {
      if (doc) {
        return doc.label;
      }
    },
    limit: 20,
    templates: {
      header: (function() {
        return '
' + this.gettextCatalog_.getString(type) + '
';
      }).bind(this),
      footer: function(doc) {
        if (!this.associationContext_) { // don't add this if you're typing in an add-association-tool
          return '
+ see more results
';
        } else {
          return '';
        }
      }.bind(this),
      suggestion: function(doc) {
        if (doc) {
          this.scope_['doc'] = doc;
          return this.compile_('<app-suggestion class="tt-suggestion"></app-suggestion>')(this.scope_);
        } else {
          return '

';
        }
      }.bind(this),
      empty: function(res) {
        if ($('.header.empty').length === 0) {
          return this.compile_(this.templatecache_.get('/static/partials/suggestion_empty.html'))(this.scope_);
        }
      }.bind(this)
    }
  });
};

/**
 * @param {string} type The document type.
 * @return {Bloodhound} The bloodhound engine.
 * @private
 */
app.SimpleSearchController.prototype.createAndInitBloodhound_ = function(type) {
  var url = this.apiUrl_ + '/search?q=%QUERY';

  var bloodhound = new Bloodhound(/** @type {BloodhoundOptions} */({
    limit: 7,
    queryTokenizer: Bloodhound.tokenizers.whitespace,
    datumTokenizer: Bloodhound.tokenizers.obj.whitespace('label'),
    remote: {
      url: url,
      wildcard: '%QUERY',
      rateLimitWait: 50,
      prepare: (function(query, settings) {

        var url = settings['url'] + '&pl=' + this.gettextCatalog_.currentLanguage;

        if (this.datasetLimit_) {
          // add the Auth header if searching for users
          if (this.datasetLimit_.indexOf('u') > -1 && this.auth_.isAuthenticated()) {
            settings['headers'] = {
              'Authorization': 'JWT token="' + this.auth_.userData.token + '"'
            };
          }
          url = url + '&t=' + this.datasetLimit_.split('').join(',');
        }
        settings['url'] = url.replace('%QUERY', encodeURIComponent(query));
        return settings;
      }).bind(this),

      filter: (function(/** appx.SimpleSearchResponse */ resp) {
        var documentResponse =
                /** @type {appx.SimpleSearchDocumentResponse} */ (resp[type]);
        if (documentResponse) {
          var documents = documentResponse.documents;
          var currentLang = this.gettextCatalog_.currentLanguage;
          var hasAssociation;

          return documents.map(function(/** appx.SimpleSearchDocument */ doc) {
            hasAssociation = this.documentService_.hasAssociation(type,  doc.document_id);

            var locale = doc.locales[0];
            doc.label = type === ('routes' && locale.title_prefix) ? locale.title_prefix + ' : ' : '';
            doc.label += locale.title;

            if (currentLang !== locale.lang) {
              doc.label += ' (' + locale.lang + ')';
            }
            doc.documentType = type;

            // don't show already associated docs in the results, but only in the app-add-association
            // -> everything should be shown in the main simple-search.
            if (!this.associationContext_ || (this.associationContext_ && !hasAssociation)) {
              return doc;
            }
          }.bind(this));
        }
      }).bind(this)
    }
  }));
  bloodhound.initialize();
  return bloodhound;
};

/**
 * @param {jQuery.Event} event Event.
 * @param {!appx.SimpleSearchDocument} doc Suggested document.
 * @param {TypeaheadDataset} dataset Dataset.
 * @this {app.SimpleSearchController}
 * @private
 */
app.SimpleSearchController.select_ = function(event, doc, dataset) {
  if (this.selectHandler) {
    this.selectHandler({'doc': doc});
  } else {
    var lang = doc.locales[0].lang;
    var type = doc.documentType;
    var url = app.utils.buildDocumentUrl(type, doc.document_id, lang);
    window.location.href = url;
  }
};

app.module.controller('AppSimpleSearchController', app.SimpleSearchController);
<|endoftext|>


<commit_before>var fs = require('fs');
var express = require('express');
var multer = require('multer');
var moment = require('moment');
var http   = require('http');
var sp = require('serialport');
var compile = require('./compile');
var uploader = require('./uploader');
var websocket = require('nodejs-websocket');
var path = require('path');

var settings = require('./settings.js');
var sketches = require('./sketches.js');
var serial = require('./serial.js');
var platform = require('./platform');

//load up standard boards
var BOARDS = require('./boards').loadBoards();
var LIBS   = require('./libraries').loadLibraries();
//standard options
var OPTIONS = {
    userlibs: settings.userlibs,
    root: settings.root,
    hardware: settings.root + '/hardware',
    avrbase: settings.root + '/hardware/tools/avr/bin'
}

console.log('settings',settings);
console.log("options",OPTIONS);

var wslist = [];
function publishEvent(evt) {
    wslist.forEach(function(conn) {
        console.log('sending event',evt);
        conn.sendText(JSON.stringify(evt));
    });
}

var app = express();
//parse post bodies
app.use(multer({dest:'./uploads'}));

//public is the dir for static files
app.use(express.static(__dirname+'/public'));

app.get('/ports',function(req,res) {
    sp.list(function(err,list) {
        res.send(JSON.stringify(list));
        res.end();
    });
});

app.get('/boards',function(req,res) {
    res.send(JSON.stringify(BOARDS));
    res.end();
})

function makeCleanDir(outpath) {
    if(fs.existsSync(outpath)) {
        fs.readdirSync(outpath).forEach(function(file) {
            fs.unlinkSync(outpath+'/'+file);
        })
        fs.rmdirSync(outpath);
    }
    fs.mkdirSync(outpath);
    return outpath;
}

function doCompile(code,board,sketch) {
    //create output dir
    if(!fs.existsSync('build')) {
        fs.mkdirSync('build');
    }
    var outpath = makeCleanDir('build/out');
    var sketchpath = makeCleanDir("build/tmp");
    var inoFile = path.join(sketchpath, sketch + '.ino');
    fs.writeFileSync(inoFile, code);

    publishEvent({ type:'compile', message:'writing to ' + inoFile });

    var foundBoard = null;
    BOARDS.forEach(function(bd) {
        if(bd.id == board) foundBoard = bd;
    })
    OPTIONS.device = foundBoard;
    OPTIONS.platform = platform.getDefaultPlatform();
    OPTIONS.name = sketch;
    compile.compile(sketchpath,outpath,OPTIONS, publishEvent, path.join(settings.usersketches, sketch));
}

app.post('/compile',function(req,res) {
    console.log("code = ",req.body.code);
    if(!req.body.board) {
        res.send(JSON.stringify({status:'missing board name'}));
        res.end();
        return;
    }
    try {
        doCompile(req.body.code,req.body.board,req.body.sketch);
        res.send(JSON.stringify({status:'okay'}));
        res.end();

    } catch(e) {
        console.log("compilation error",e);
        console.log(e.output);
        res.send(JSON.stringify({status:'error',output:e.output}));
        res.end();
    }
});

app.post('/run',function(req,res) {
    console.log("body = ",req.body.code);
    if(!req.body.board) {
        res.send(JSON.stringify({status:'missing board name'}));
        res.end();
        return;
    }
    if(!req.body.port) {
        res.send(JSON.stringify({status:'missing port name'}));
        res.end();
        return;
    }

    doCompile(req.body.code,req.body.board,req.body.sketch);
    uploader.upload(path.join('build', 'out', req.body.sketch+'.hex'),req.body.port,OPTIONS);
    res.send(JSON.stringify({status:'okay'}));
    res.end();
});

app.post('/new',function(req,res) {
    console.log(req.body.name);
    if(!req.body.name) {
        res.send(JSON.stringify({status:'missing sketch name'}));
        res.end();
        return;
    }
    try {
        var sketch = req.body.name;
        sketches.makeNewSketch(sketch, function(name,content) {
            res.send(JSON.stringify({status:'okay',content:content, name:sketch}));
            res.end();
        });
    } catch(err) {
        console.log(err);
        err.printStackTrace();
        res.end(JSON.stringify({status:'error',output:err.toString()}));
    }
});

app.post('/sketches/delete', function(req,res){
    console.log(req.body.name);
    if(!req.body.name) {
        res.send(JSON.stringify({status:'missing sketch name'}));
        res.end();
        return;
    }

    try {
        sketches.deleteSketch(req.body.name,function(name) {
            res.send(JSON.stringify({status:'okay', name:name}));
            res.end();
        });
    } catch (err) {
        console.log(err);
        res.end(JSON.stringify({status:'error',output:err.toString()}));
    }
});

app.get('/sketches',function(req,res) {
    sketches.listSketches(function(list) {
        res.send(JSON.stringify(list));
        res.end();
    });
});

app.post('/save',function(req,res) {
    sketches.saveSketch(req.body.name,req.body.code,function(results) {
        res.send(JSON.stringify({status:'okay', name:req.body.name}));
        res.end();
    });
});

app.get('/sketch/:name',function(req,res) {
    sketches.getSketch(req.params.name, function(sketch) {
        res.send(sketch);
        res.end();
    });
});

app.get('/search',function(req,res){
    LIBS.search(req.query.query,function(results) {
        res.send(results);
        res.end();
    })
})

function serialOutput(data) {
    var msg = {
        type:'serial',
        data:data.toString(),
    };
    wslist.forEach(function(conn) {
        conn.sendText(JSON.stringify(msg));
    });
}

app.post('/serial/open', function(req,res) {
    if(!req.body.port) {
        res.send(JSON.stringify({status:'error', message:'missing serial port'}));
        res.end();
        return;
    }
    serial.open(req.body.port,serialOutput);
    res.end(JSON.stringify({status:'okay',message:'opened'}));
});

app.post('/serial/close', function(req,res) {
    if(!req.body.port) {
        res.send(JSON.stringify({status:'error', message:'missing serial port'}));
        res.end();
        return;
    }
    serial.close(req.body.port);
    res.end(JSON.stringify({status:'okay',message:'closed'}));
});

var server = app.listen(54329,function() {
    console.log('open your browser to http://localhost:'+server.address().port+'/');
});

var wss = websocket.createServer(function(conn) {
    console.log('web socket connected');
    wslist.push(conn);
    conn.on('message',function(message) {
        console.log("got a request");
    });
    conn.on('error',function(err){
        console.log('websocket got an error',err);
    });
    conn.on('close',function(code,reason) {
        console.log("websocket closed",code,reason);
    });
}).listen(4203);
<commit_msg>Remove options reinstated by merge<commit_after>var fs = require('fs');
var express = require('express');
var multer = require('multer');
var moment = require('moment');
var http   = require('http');
var sp = require('serialport');
var compile = require('./compile');
var uploader = require('./uploader');
var websocket = require('nodejs-websocket');
var path = require('path');

var settings = require('./settings.js');
var sketches = require('./sketches.js');
var serial = require('./serial.js');
var platform = require('./platform');

//load up standard boards
var BOARDS = require('./boards').loadBoards();
var LIBS   = require('./libraries').loadLibraries();
//standard options
var OPTIONS = {
    userlibs: settings.userlibs
}

console.log('settings',settings);
console.log("options",OPTIONS);

var wslist = [];
function publishEvent(evt) {
    wslist.forEach(function(conn) {
        console.log('sending event',evt);
        conn.sendText(JSON.stringify(evt));
    });
}

var app = express();
//parse post bodies
app.use(multer({dest:'./uploads'}));

//public is the dir for static files
app.use(express.static(__dirname+'/public'));

app.get('/ports',function(req,res) {
    sp.list(function(err,list) {
        res.send(JSON.stringify(list));
        res.end();
    });
});

app.get('/boards',function(req,res) {
    res.send(JSON.stringify(BOARDS));
    res.end();
})

function makeCleanDir(outpath) {
    if(fs.existsSync(outpath)) {
        fs.readdirSync(outpath).forEach(function(file) {
            fs.unlinkSync(outpath+'/'+file);
        })
        fs.rmdirSync(outpath);
    }
    fs.mkdirSync(outpath);
    return outpath;
}

function doCompile(code,board,sketch) {
    //create output dir
    if(!fs.existsSync('build')) {
        fs.mkdirSync('build');
    }
    var outpath = makeCleanDir('build/out');
    var sketchpath = makeCleanDir("build/tmp");
    var inoFile = path.join(sketchpath, sketch + '.ino');
    fs.writeFileSync(inoFile, code);

    publishEvent({ type:'compile', message:'writing to ' + inoFile });

    var foundBoard = null;
    BOARDS.forEach(function(bd) {
        if(bd.id == board) foundBoard = bd;
    })
    OPTIONS.device = foundBoard;
    OPTIONS.platform = platform.getDefaultPlatform();
    OPTIONS.name = sketch;
    compile.compile(sketchpath,outpath,OPTIONS, publishEvent, path.join(settings.usersketches, sketch));
}

app.post('/compile',function(req,res) {
    console.log("code = ",req.body.code);
    if(!req.body.board) {
        res.send(JSON.stringify({status:'missing board name'}));
        res.end();
        return;
    }
    try {
        doCompile(req.body.code,req.body.board,req.body.sketch);
        res.send(JSON.stringify({status:'okay'}));
        res.end();

    } catch(e) {
        console.log("compilation error",e);
        console.log(e.output);
        res.send(JSON.stringify({status:'error',output:e.output}));
        res.end();
    }
});

app.post('/run',function(req,res) {
    console.log("body = ",req.body.code);
    if(!req.body.board) {
        res.send(JSON.stringify({status:'missing board name'}));
        res.end();
        return;
    }
    if(!req.body.port) {
        res.send(JSON.stringify({status:'missing port name'}));
        res.end();
        return;
    }

    doCompile(req.body.code,req.body.board,req.body.sketch);
    uploader.upload(path.join('build', 'out', req.body.sketch+'.hex'),req.body.port,OPTIONS);
    res.send(JSON.stringify({status:'okay'}));
    res.end();
});

app.post('/new',function(req,res) {
    console.log(req.body.name);
    if(!req.body.name) {
        res.send(JSON.stringify({status:'missing sketch name'}));
        res.end();
        return;
    }
    try {
        var sketch = req.body.name;
        sketches.makeNewSketch(sketch, function(name,content) {
            res.send(JSON.stringify({status:'okay',content:content, name:sketch}));
            res.end();
        });
    } catch(err) {
        console.log(err);
        err.printStackTrace();
        res.end(JSON.stringify({status:'error',output:err.toString()}));
    }
});

app.post('/sketches/delete', function(req,res){
    console.log(req.body.name);
    if(!req.body.name) {
        res.send(JSON.stringify({status:'missing sketch name'}));
        res.end();
        return;
    }

    try {
        sketches.deleteSketch(req.body.name,function(name) {
            res.send(JSON.stringify({status:'okay', name:name}));
            res.end();
        });
    } catch (err) {
        console.log(err);
        res.end(JSON.stringify({status:'error',output:err.toString()}));
    }
});

app.get('/sketches',function(req,res) {
    sketches.listSketches(function(list) {
        res.send(JSON.stringify(list));
        res.end();
    });
});

app.post('/save',function(req,res) {
    sketches.saveSketch(req.body.name,req.body.code,function(results) {
        res.send(JSON.stringify({status:'okay', name:req.body.name}));
        res.end();
    });
});

app.get('/sketch/:name',function(req,res) {
    sketches.getSketch(req.params.name, function(sketch) {
        res.send(sketch);
        res.end();
    });
});

app.get('/search',function(req,res){
    LIBS.search(req.query.query,function(results) {
        res.send(results);
        res.end();
    })
})

function serialOutput(data) {
    var msg = {
        type:'serial',
        data:data.toString(),
    };
    wslist.forEach(function(conn) {
        conn.sendText(JSON.stringify(msg));
    });
}

app.post('/serial/open', function(req,res) {
    if(!req.body.port) {
        res.send(JSON.stringify({status:'error', message:'missing serial port'}));
        res.end();
        return;
    }
    serial.open(req.body.port,serialOutput);
    res.end(JSON.stringify({status:'okay',message:'opened'}));
});

app.post('/serial/close', function(req,res) {
    if(!req.body.port) {
        res.send(JSON.stringify({status:'error', message:'missing serial port'}));
        res.end();
        return;
    }
    serial.close(req.body.port);
    res.end(JSON.stringify({status:'okay',message:'closed'}));
});

var server = app.listen(54329,function() {
    console.log('open your browser to http://localhost:'+server.address().port+'/');
});

var wss = websocket.createServer(function(conn) {
    console.log('web socket connected');
    wslist.push(conn);
    conn.on('message',function(message) {
        console.log("got a request");
    });
    conn.on('error',function(err){
        console.log('websocket got an error',err);
    });
    conn.on('close',function(code,reason) {
        console.log("websocket closed",code,reason);
    });
}).listen(4203);
<|endoftext|>


<commit_before>import React from 'react'
import {map} from 'lodash'
import {ComboBox, Option} from 'belle'

import Component from '../Component'
import styles from './AutoFillInput.css'

class AutoFillInput extends Component {

  onUpdate (event) {
    var {identifier} = event // others keys are: value isOptionSelection isMatchingOption
    if (identifier) {
      this.props.onOptionChange(identifier)
    }
  }

  render () {
    var defaultValue = this.props.currentOption ? this.props.currentOption.toString() : null
    return (

        <ComboBox
          placeholder = {'Choose a system'}
          onUpdate={this.onUpdate.bind(this)}
          maxOptions = {5}
          defaultValue={defaultValue}
          enableHint={true}
        >{
          map(this.props.options, (option, index) => {
            return (
              <Option value={option.toString()} identifier={option} key={index}>
                {option.toString()}
              </Option>
            )
          })
          }
        </ComboBox>

    )
  }
}

AutoFillInput.propTypes = {
  onOptionChange: React.PropTypes.func.isRequired,
  currentOption: React.PropTypes.object.isRequired,
  options: React.PropTypes.array.isRequired
}

export default AutoFillInput
<commit_msg>caido: text fix<commit_after>import React from 'react'
import {map} from 'lodash'
import {ComboBox, Option} from 'belle'

import Component from '../Component'
import styles from './AutoFillInput.css'

class AutoFillInput extends Component {

  onUpdate (event) {
    var {identifier} = event // others keys are: value isOptionSelection isMatchingOption
    if (identifier) {
      this.props.onOptionChange(identifier)
    }
  }

  render () {
    var defaultValue = this.props.currentOption ? this.props.currentOption.toString() : null
    return (

        <ComboBox
          placeholder = {'Add a system'}
          onUpdate={this.onUpdate.bind(this)}
          maxOptions = {5}
          defaultValue={defaultValue}
          enableHint={true}
        >{
          map(this.props.options, (option, index) => {
            return (
              <Option value={option.toString()} identifier={option} key={index}>
                {option.toString()}
              </Option>
            )
          })
          }
        </ComboBox>

    )
  }
}

AutoFillInput.propTypes = {
  onOptionChange: React.PropTypes.func.isRequired,
  currentOption: React.PropTypes.object.isRequired,
  options: React.PropTypes.array.isRequired
}

export default AutoFillInput
<|endoftext|>


<commit_before>// Solution for elevator saga
{
    init: function (elevators, floors) {
        var direction = {
            UP: "up",
            DOWN: "down",
        };
        Object.freeze(direction);

        var elevatorState = {
            GOING_UP: "goingUp",
            GOING_DOWN: "goingDown",
            IDLE: "idle"
        };
        Object.freeze(elevatorState);

        // TODO: Implement a sortedSet. For now I'll just make sure to call _.uniq and sort()
        var upFloors = [];
        var downFloors = [];

        var updateFloorButtonState = function (dir, floorNum){
            if (dir === direction.UP){
                upFloors.push(floorNum);
                upFloors = _.uniq(upFloors);
                upFloors.sort();
            } else if (dir === direction.DOWN){
                downFloors.push(floorNum)
                downFloors = _.uniq(downFloors);
                downFloors.sort();
                downFloors.reverse();
            }
        }

        var distanceTo = function (from, to) {
            return Math.abs(from - to);
        }

        elevators.forEach(function (elevator, index) {
            elevator.state = elevatorState.IDLE;
            elevator.id = index;

            elevator.setState = function (state) {
                console.log("Setting elevator " + elevator.id + " state: " + state);
                if (state === elevatorState.GOING_UP) {
                    elevator.goingUpIndicator(true);
                    elevator.goingDownIndicator(false);
                    elevator.state = elevatorState.GOING_UP;
                } else if (state === elevatorState.GOING_DOWN) {
                    elevator.goingUpIndicator(false);
                    elevator.goingDownIndicator(true);
                    elevator.state = elevatorState.GOING_DOWN;
                } else {
                    elevator.goingUpIndicator(false);
                    elevator.goingDownIndicator(false);
                    elevator.state = elevatorState.IDLE;
                }

            };

            elevator.prioritizeDestinationQueue = function () {
                // Keeps the destination queue sorted based on the current elevator state.
                elevator.destinationQueue = _.uniq(elevator.destinationQueue);
                elevator.destinationQueue.sort();
                if (elevator.state == elevatorState.GOING_DOWN){
                    elevator.destinationQueue.reverse();
                }
                elevator.checkDestinationQueue();
            };

            elevator.pushToDestinationQueue = function (floorNum) {
                elevator.destinationQueue.push(floorNum);
                elevator.prioritizeDestinationQueue();
            };

            elevator.on("idle", function() {
                var currentFloor = elevator.currentFloor();
                var upFloor = upFloors[0];
                var downFloor = downFloors[0];
                if (upFloor !== undefined && downFloor === undefined) {
                    elevator.setState(elevatorState.GOING_UP);
                    elevator.goToFloor(upFloor);
                } else if (upFloor === undefined && downFloor !== undefined) {
                    elevator.setState(elevatorState.GOING_DOWN);
                    elevator.goToFloor(downFloor);
                } else if (upFloor !== undefined && downFloor !== undefined) {
                    if (distanceTo(currentFloor, upFloor) >= distanceTo(currentFloor, downFloor)) {
                        elevator.setState(elevatorState.GOING_DOWN);
                        elevator.goToFloor(downFloor);
                    } else {
                        elevator.setState(elevatorState.GOING_UP);
                        elevator.goToFloor(upFloor);
                    }
                } else {
                    elevator.setState(elevatorState.IDLE);
                    elevator.goToFloor(currentFloor);
                }
            });

            elevator.on("stopped_at_floor", function(floorNum) {
                console.log('Event: stopped_at_floor');
                console.log("upFloors queue: " + upFloors);
                console.log("downFloors queue: " + downFloors);
                console.log("Elevator " + elevator.id + " destination queue: " + elevator.destinationQueue);
                console.log("Elevator " + elevator.id + " state: " + elevator.state);

                var currentFloor = elevator.currentFloor();
                var upIndex = upFloors.indexOf(currentFloor);
                if (upIndex > -1) {
                    upFloors.splice(upIndex, 1);
                    elevator.setState(elevatorState.GOING_UP);
                    return
                }

                var downIndex = downFloors.indexOf(currentFloor);
                if (downIndex > -1) {
                    downFloors.splice(downIndex, 1);
                    elevator.setState(elevatorState.GOING_DOWN);
                    return
                }
            });

            elevator.on("passing_floor", function(floorNum, direction) {
                if (elevator.state === elevatorState.GOING_UP) {
                    var index = upFloors.indexOf(floorNum);
                    if (index > -1){
                        upFloors.splice(index, 1);
                        elevator.goToFloor(floorNum, true);
                    }
                } else if (elevator.state === elevatorState.GOING_DOWN) {
                    var index = downFloors.indexOf(floorNum);
                    if (index > -1){
                        downFloors.splice(index, 1);
                        elevator.goToFloor(floorNum, true);
                    }
                }
            });

            elevator.on("floor_button_pressed", function(floorNum) {
                elevator.pushToDestinationQueue(floorNum);
            });
        });

        floors.forEach(function (floor) {
            floor.on("up_button_pressed", function() {
                updateFloorButtonState(direction.UP, floor.floorNum());
            });
            floor.on("down_button_pressed", function() {
                updateFloorButtonState(direction.DOWN, floor.floorNum());
            });
        });
    },
    update: function(dt, elevators, floors) {}
}
<commit_msg>when the elevator decides to go to one of these floors at idle, remove it from the shared state<commit_after>// Solution for elevator saga
{
    init: function (elevators, floors) {
        var direction = {
            UP: "up",
            DOWN: "down",
        };
        Object.freeze(direction);

        var elevatorState = {
            GOING_UP: "goingUp",
            GOING_DOWN: "goingDown",
            IDLE: "idle"
        };
        Object.freeze(elevatorState);

        // TODO: Implement a sortedSet. For now I'll just make sure to call _.uniq and sort()
        var upFloors = [];
        var downFloors = [];

        var updateFloorButtonState = function (dir, floorNum){
            if (dir === direction.UP){
                upFloors.push(floorNum);
                upFloors = _.uniq(upFloors);
                upFloors.sort();
            } else if (dir === direction.DOWN){
                downFloors.push(floorNum)
                downFloors = _.uniq(downFloors);
                downFloors.sort();
                downFloors.reverse();
            }
        }

        var distanceTo = function (from, to) {
            return Math.abs(from - to);
        }

        elevators.forEach(function (elevator, index) {
            elevator.state = elevatorState.IDLE;
            elevator.id = index;

            elevator.setState = function (state) {
                console.log("Setting elevator " + elevator.id + " state: " + state);
                if (state === elevatorState.GOING_UP) {
                    elevator.goingUpIndicator(true);
                    elevator.goingDownIndicator(false);
                    elevator.state = elevatorState.GOING_UP;
                } else if (state === elevatorState.GOING_DOWN) {
                    elevator.goingUpIndicator(false);
                    elevator.goingDownIndicator(true);
                    elevator.state = elevatorState.GOING_DOWN;
                } else {
                    elevator.goingUpIndicator(false);
                    elevator.goingDownIndicator(false);
                    elevator.state = elevatorState.IDLE;
                }

            };

            elevator.prioritizeDestinationQueue = function () {
                // Keeps the destination queue sorted based on the current elevator state.
                elevator.destinationQueue = _.uniq(elevator.destinationQueue);
                elevator.destinationQueue.sort();
                if (elevator.state == elevatorState.GOING_DOWN){
                    elevator.destinationQueue.reverse();
                }
                elevator.checkDestinationQueue();
            };

            elevator.pushToDestinationQueue = function (floorNum) {
                elevator.destinationQueue.push(floorNum);
                elevator.prioritizeDestinationQueue();
            };

            elevator.on("idle", function() {
                var currentFloor = elevator.currentFloor();
                var upFloor = upFloors[0];
                var downFloor = downFloors[0];
                if (upFloor !== undefined && downFloor === undefined) {
                    elevator.setState(elevatorState.GOING_UP);
                    elevator.goToFloor(upFloors.shift());
                } else if (upFloor === undefined && downFloor !== undefined) {
                    elevator.setState(elevatorState.GOING_DOWN);
                    elevator.goToFloor(downFloors.shift());
                } else if (upFloor !== undefined && downFloor !== undefined) {
                    if (distanceTo(currentFloor, upFloor) >= distanceTo(currentFloor, downFloor)) {
                        elevator.setState(elevatorState.GOING_DOWN);
                        elevator.goToFloor(downFloors.shift());
                    } else {
                        elevator.setState(elevatorState.GOING_UP);
                        elevator.goToFloor(upFloors.shift());
                    }
                } else {
                    elevator.setState(elevatorState.IDLE);
                    elevator.goToFloor(currentFloor);
                }
            });

            elevator.on("stopped_at_floor", function(floorNum) {
                console.log('Event: stopped_at_floor');
                console.log("upFloors queue: " + upFloors);
                console.log("downFloors queue: " + downFloors);
                console.log("Elevator " + elevator.id + " destination queue: " + elevator.destinationQueue);
                console.log("Elevator " + elevator.id + " state: " + elevator.state);

                var currentFloor = elevator.currentFloor();
                var upIndex = upFloors.indexOf(currentFloor);
                if (upIndex > -1) {
                    upFloors.splice(upIndex, 1);
                    elevator.setState(elevatorState.GOING_UP);
                    return
                }

                var downIndex = downFloors.indexOf(currentFloor);
                if (downIndex > -1) {
                    downFloors.splice(downIndex, 1);
                    elevator.setState(elevatorState.GOING_DOWN);
                    return
                }
            });

            elevator.on("passing_floor", function(floorNum, direction) {
                if (elevator.state === elevatorState.GOING_UP) {
                    var index = upFloors.indexOf(floorNum);
                    if (index > -1){
                        upFloors.splice(index, 1);
                        elevator.goToFloor(floorNum, true);
                    }
                } else if (elevator.state === elevatorState.GOING_DOWN) {
                    var index = downFloors.indexOf(floorNum);
                    if (index > -1){
                        downFloors.splice(index, 1);
                        elevator.goToFloor(floorNum, true);
                    }
                }
            });

            elevator.on("floor_button_pressed", function(floorNum) {
                elevator.pushToDestinationQueue(floorNum);
            });
        });

        floors.forEach(function (floor) {
            floor.on("up_button_pressed", function() {
                updateFloorButtonState(direction.UP, floor.floorNum());
            });
            floor.on("down_button_pressed", function() {
                updateFloorButtonState(direction.DOWN, floor.floorNum());
            });
        });
    },
    update: function(dt, elevators, floors) {}
}
<|endoftext|>


<commit_before>var http         = require('http'),
    b64          = require('./base64'),
    query        = require('querystring'),
    Parser       = require('./parser'),
    EventEmitter = require('events').EventEmitter;

// process.mixin is gone, a function for replacement
function extend(a, b) {
  Object.keys(b).forEach(function (key) {
    a[key] = b[key];
  });
  return a;
}

// Creates a streaming connection with twitter, and pushes any incoming
// statuses to a tweet event.
//
// options - optional Object that specifies custom configuration values.
//
// Valid option keys:
//
// port      - Integer of the streaming api connection port.  Defaults to 80.
// host      - String of the streaming api host.  Defaults to 'stream.twitter.com'.
// path      - String of the base path for the request.
// action    - String part of the URL that specifies what to query for.
// track     - Array of keywords to filter.  See track()
// following - Array of userIDs to filter.  See follow()
// locations - Array of lat/long tuples.  See location()
// params    - Extra HTTP params Object to send with the request.
// user      - String Twitter login name or email.
// password  - String Twitter password.
//
// Returns TwitterNode instance.
var TwitterNode = exports.TwitterNode = function(options) {
  EventEmitter.call(this);
  if(!options) options = {};
  var self           = this;
  this.port          = options.port      || 80;
  this.host          = options.host      || 'stream.twitter.com';
  this.path          = options.path      || '/1/statuses/';
  this.action        = options.action    || 'filter';
  this.trackKeywords = options.track     || [];
  this.following     = options.follow    || [];
  this.locations     = options.locations || [];
  this.params        = options.params    || {};
  this.user          = options.user;
  this.password      = options.password;
  this.headers       = { "User-Agent": 'Twitter-Node' };
  this.debug         = false;
  this.parser        = new Parser();
  this.parser.addListener('object', processJSONObject(this));
  this.parser.addListener('error', function (error) {
    self.emit('error', new Error('TwitterNode parser error: ' + error.message));
  });
  if (options.headers) {
    extend(this.headers, options.headers);
  }
}

TwitterNode.prototype = Object.create(EventEmitter.prototype);

// Track the following keyword.  If called multiple times, all words are sent
// as a comma-separated parameter to Twitter.
//
// See: http://apiwiki.twitter.com/Streaming-API-Documentation#track
//
// word - String word to track.
//
// Returns nothing.
TwitterNode.prototype.track = function track(word) {
  this.trackKeywords.push(word);
  return this;
};

// Follow the given twitter user (specified by their userID, not screen name)
// If called multiple times, all userIDs are sent as a comma-separated
// parameter to Twitter.
//
// See: http://apiwiki.twitter.com/Streaming-API-Documentation#follow
//
// userID - Integer userID to track.
//
// Returns nothing.
TwitterNode.prototype.follow = function follow(userId) {
  this.following.push(userId);
  return this;
};

// Match tweets in the given bounding box.
//
// See: http://apiwiki.twitter.com/Streaming-API-Documentation#locations
//
// Example: location(-122.75, 36.8, -121.75, 37.8) // SF
//
// lng1, lat1 - southwest corner of the bounding box.
// lng2, lat2 - northeast corner.
//
// Returns nothing.
TwitterNode.prototype.location = function location(lng1, lat1, lng2, lat2) {
  this.locations.push(lng1, lat1, lng2, lat2)
  return this;
};

TwitterNode.prototype.stream = function stream() {
  if (this._clientResponse && this._clientResponse.connection) {
    this._clientResponse.socket.end();
  }

  if (this.buildParams() === '') return;

  var client  = this._createClient(this.port, this.host),
      headers = extend({}, this.headers),
      twit    = this,
      request;

  headers['Host'] = this.host;

  if (this.user) {
    headers['Authorization'] = basicAuth(this.user, this.password);
  }

  request = client.request("GET", this.requestUrl(), headers);

  request.addListener('response', function(response) {
    twit._clientResponse = response;

    response.addListener('data', function(chunk) {
      console.log('data');
      twit._receive(chunk);
    });

    response.addListener('end', function() {
      twit.emit('end', this);
      twit.emit('close', this);
    });
  });
  request.end();
  return this;
};

// UTILITY METHODS

// Passes the received data to the streaming JSON parser.
//
// chunk - String data received from the HTTP stream.
//
// Returns nothing.
TwitterNode.prototype._receive = function(chunk) {
  this.parser.receive(chunk);
  return this;
};

// Creates the HTTP client object for the stream connection.  Override this
// to pass in your own client if needed.
//
// port - Integer port number to connect to.
// host - String host name to connect to.
//
// returns Http Client instance.
TwitterNode.prototype._createClient = function(port, host) {
  return http.createClient(this.port, this.host);
};

// Builds the URL for the streaming request.
//
// Returns a String absolute URL.
TwitterNode.prototype.requestUrl = function() {
  return this.path + this.action + ".json" + this.buildParams();
};

// Builds the GET params for the streaming request.
//
// Returns URI encoded string: "?track=LOST"
TwitterNode.prototype.buildParams = function() {
  var options = {};
  extend(options, this.params);
  if (this.trackKeywords.length > 0) options.track = this.trackKeywords.join(",");
  if (this.following.length > 0)     options.follow = this.following.join(",");
  if (this.locations.length > 0)     options.locations = this.locations.join(",");
  if (options.track || options.follow || options.locations) {
    return "?" + query.stringify(options);
  }
  return "";
};

// Base64 encodes the given username and password.
//
// user - String Twitter screen name or email.
// pass - String password.
//
// Returns a Basic Auth header fit for HTTP.
var basicAuth = function basicAuth(user, pass) {
  return "Basic " + b64.encode(user + ":" + pass);
};

// Creates a callback for the object Event of the JSON Parser.
//
// twit - an instance of this TwitterNode.
//
// Returns a function to be passed to the addListener call on the parser.
var processJSONObject = function processJSONObject(twit) {
  return function(tweet) {
    if (tweet.limit) {
      twit.emit('limit', tweet.limit);
    } else if (tweet['delete']) {
      twit.emit('delete', tweet['delete']);
    } else {
      twit.emit('tweet', tweet);
    }
  };
};
<commit_msg>Sneaky sneaky console.log being sneaky<commit_after>var http         = require('http'),
    b64          = require('./base64'),
    query        = require('querystring'),
    Parser       = require('./parser'),
    EventEmitter = require('events').EventEmitter;

// process.mixin is gone, a function for replacement
function extend(a, b) {
  Object.keys(b).forEach(function (key) {
    a[key] = b[key];
  });
  return a;
}

// Creates a streaming connection with twitter, and pushes any incoming
// statuses to a tweet event.
//
// options - optional Object that specifies custom configuration values.
//
// Valid option keys:
//
// port      - Integer of the streaming api connection port.  Defaults to 80.
// host      - String of the streaming api host.  Defaults to 'stream.twitter.com'.
// path      - String of the base path for the request.
// action    - String part of the URL that specifies what to query for.
// track     - Array of keywords to filter.  See track()
// following - Array of userIDs to filter.  See follow()
// locations - Array of lat/long tuples.  See location()
// params    - Extra HTTP params Object to send with the request.
// user      - String Twitter login name or email.
// password  - String Twitter password.
//
// Returns TwitterNode instance.
var TwitterNode = exports.TwitterNode = function(options) {
  EventEmitter.call(this);
  if(!options) options = {};
  var self           = this;
  this.port          = options.port      || 80;
  this.host          = options.host      || 'stream.twitter.com';
  this.path          = options.path      || '/1/statuses/';
  this.action        = options.action    || 'filter';
  this.trackKeywords = options.track     || [];
  this.following     = options.follow    || [];
  this.locations     = options.locations || [];
  this.params        = options.params    || {};
  this.user          = options.user;
  this.password      = options.password;
  this.headers       = { "User-Agent": 'Twitter-Node' };
  this.debug         = false;
  this.parser        = new Parser();
  this.parser.addListener('object', processJSONObject(this));
  this.parser.addListener('error', function (error) {
    self.emit('error', new Error('TwitterNode parser error: ' + error.message));
  });
  if (options.headers) {
    extend(this.headers, options.headers);
  }
}

TwitterNode.prototype = Object.create(EventEmitter.prototype);

// Track the following keyword.  If called multiple times, all words are sent
// as a comma-separated parameter to Twitter.
//
// See: http://apiwiki.twitter.com/Streaming-API-Documentation#track
//
// word - String word to track.
//
// Returns nothing.
TwitterNode.prototype.track = function track(word) {
  this.trackKeywords.push(word);
  return this;
};

// Follow the given twitter user (specified by their userID, not screen name)
// If called multiple times, all userIDs are sent as a comma-separated
// parameter to Twitter.
//
// See: http://apiwiki.twitter.com/Streaming-API-Documentation#follow
//
// userID - Integer userID to track.
//
// Returns nothing.
TwitterNode.prototype.follow = function follow(userId) {
  this.following.push(userId);
  return this;
};

// Match tweets in the given bounding box.
//
// See: http://apiwiki.twitter.com/Streaming-API-Documentation#locations
//
// Example: location(-122.75, 36.8, -121.75, 37.8) // SF
//
// lng1, lat1 - southwest corner of the bounding box.
// lng2, lat2 - northeast corner.
//
// Returns nothing.
TwitterNode.prototype.location = function location(lng1, lat1, lng2, lat2) {
  this.locations.push(lng1, lat1, lng2, lat2)
  return this;
};

TwitterNode.prototype.stream = function stream() {
  if (this._clientResponse && this._clientResponse.connection) {
    this._clientResponse.socket.end();
  }

  if (this.buildParams() === '') return;

  var client  = this._createClient(this.port, this.host),
      headers = extend({}, this.headers),
      twit    = this,
      request;

  headers['Host'] = this.host;

  if (this.user) {
    headers['Authorization'] = basicAuth(this.user, this.password);
  }

  request = client.request("GET", this.requestUrl(), headers);

  request.addListener('response', function(response) {
    twit._clientResponse = response;

    response.addListener('data', function(chunk) {
      twit._receive(chunk);
    });

    response.addListener('end', function() {
      twit.emit('end', this);
      twit.emit('close', this);
    });
  });
  request.end();
  return this;
};

// UTILITY METHODS

// Passes the received data to the streaming JSON parser.
//
// chunk - String data received from the HTTP stream.
//
// Returns nothing.
TwitterNode.prototype._receive = function(chunk) {
  this.parser.receive(chunk);
  return this;
};

// Creates the HTTP client object for the stream connection.  Override this
// to pass in your own client if needed.
//
// port - Integer port number to connect to.
// host - String host name to connect to.
//
// returns Http Client instance.
TwitterNode.prototype._createClient = function(port, host) {
  return http.createClient(this.port, this.host);
};

// Builds the URL for the streaming request.
//
// Returns a String absolute URL.
TwitterNode.prototype.requestUrl = function() {
  return this.path + this.action + ".json" + this.buildParams();
};

// Builds the GET params for the streaming request.
//
// Returns URI encoded string: "?track=LOST"
TwitterNode.prototype.buildParams = function() {
  var options = {};
  extend(options, this.params);
  if (this.trackKeywords.length > 0) options.track = this.trackKeywords.join(",");
  if (this.following.length > 0)     options.follow = this.following.join(",");
  if (this.locations.length > 0)     options.locations = this.locations.join(",");
  if (options.track || options.follow || options.locations) {
    return "?" + query.stringify(options);
  }
  return "";
};

// Base64 encodes the given username and password.
//
// user - String Twitter screen name or email.
// pass - String password.
//
// Returns a Basic Auth header fit for HTTP.
var basicAuth = function basicAuth(user, pass) {
  return "Basic " + b64.encode(user + ":" + pass);
};

// Creates a callback for the object Event of the JSON Parser.
//
// twit - an instance of this TwitterNode.
//
// Returns a function to be passed to the addListener call on the parser.
var processJSONObject = function processJSONObject(twit) {
  return function(tweet) {
    if (tweet.limit) {
      twit.emit('limit', tweet.limit);
    } else if (tweet['delete']) {
      twit.emit('delete', tweet['delete']);
    } else {
      twit.emit('tweet', tweet);
    }
  };
};
<|endoftext|>


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

var headers = {
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept',
    'Access-Control-Request-Method': '*',
    'Access-Control-Allow-Methods': '*',
    'Content-Type': 'image/svg+xml'
};

var style = "svg {  \
  font: 10px sans-serif;    \
  fill:rgb(50%, 50%, 50%);  \
}   \
    \
.axis path, \
.axis line {    \
  fill: none;   \
  stroke: rgb(50%, 50%, 50%); \
  shape-rendering: crispEdges;  \
}   \
    \
.x.axis path {  \
  display: none;    \
}   \
    \
.line { \
  fill: none;   \
  stroke: steelblue;    \
  stroke-width: 1.5px;  \
}   \
.xtick { \
  transform: rotate(-35deg);  \
  text-anchor: end; \
}   \
";

module.exports = function (res, dataPath ) {

var document = require( 'jsdom' ).jsdom();
var margin = {top: 10, right: 100, bottom: 50, left: 40},
        width = 888 - margin.left - margin.right,
        height = 200 - margin.top - margin.bottom;

var parseDate = d3.time.format("%Y-%m-%d").parse;

var x = d3.time.scale()
    .range([0, width]);

var y = d3.scale.linear()
    .range([height, 0]);

var color = d3.scale.category10();

var xAxis = d3.svg.axis()
    .scale(x)
    .tickFormat(d3.time.format("%d %b %y"))
    .orient("bottom");

var yAxis = d3.svg.axis()
    .scale(y)
    .tickFormat(function(v){
        if (v >= 10000000000000) {
            return (v / 1000000000000).toFixed(0) + "Tn";
        }
        if (v >= 1000000000000) {
            return (v / 1000000000000).toFixed(1) + "Tn";
        }
        if (v >= 10000000000) {
            return (v / 1000000000).toFixed(0) + "Bn";
        }
        if (v >= 1000000000) {
            return (v / 1000000000).toFixed(1) + "Bn";
        }
        if (v >= 10000000) {
            return (v / 1000000).toFixed(0) + "M";
        }
        if (v >= 1000000) {
            return (v / 1000000).toFixed(1) + "M";
        }
        if (v >= 1000) {
            return (v / 1000).toFixed(0) + "K";
        }
        return v;
    })
    .orient("left");

var line = d3.svg.line()
    .defined(function(d) { return d.value != 0; })
    .x(function(d) { return x(d.date); })
    .y(function(d) { return y(d.value); });

var root = d3.select( document.body )
  .append( "svg" )
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom);

root.append("defs")
   .append("style")
   .text(style);

var svg = root.append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

d3.csv(dataPath, function(error, data) {
  if (error) {
	res.statusCode = 500;
	res.end(error.statusText);
    return;
  };

  color.domain(d3.keys(data[0]).filter(function(key) { return key !== "date"; }));

  data.forEach(function(d) {
    d.date = parseDate(d.date);
  });

  var types = color.domain().map(function(name) {
    return {
      name: name,
      values: data.map(function(d) {
        return {date: d.date, value: +d[name]||0};
      })
    };
  });

  var xDomain = d3.extent(data, function(d) { return d.date; });
  xDomain[1] = new Date();

  x.domain(xDomain);

  y.domain([
    d3.min(types, function(c) { return d3.min(c.values, function(v) { return v.value; }); }),
    d3.max(types, function(c) { return d3.max(c.values, function(v) { return v.value; }); })
  ]);

  svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis)
      .selectAll("text")
      .style("text-anchor", "end")
      .attr("dx", "-.5em")
      .attr("dy", ".125em")
      .attr("class", "xtick");

  svg.append("g")
      .attr("class", "y axis")
      .call(yAxis)
    .append("text")
      .attr("transform", "rotate(-90)")
      .attr("y", 6)
      .attr("dy", ".71em")
      .style("text-anchor", "end")
      .text("RPS");

  var type = svg.selectAll(".type")
      .data(types)
    .enter().append("g")
      .attr("class", "type");

  type.append("path")
      .attr("class", "line")
      .attr("d", function(d) { return line(d.values); })
      .style("stroke", function(d) { return color(d.name); })
    .append("title")
      .text(function(d) { return d.name; });

var point = type.append("g")
            .attr("class", "line-point");

    point.selectAll('circle')
        .data(function(d){
                return d.values
                    .filter(function(c) { return c.value != 0; })
        })
        .enter()
      .append('circle')
        .attr("cx", function(d) { return x(d.date) })
        .attr("cy", function(d) { return y(d.value) })
        .attr("r", 3)
        .style("fill", "white")
        .style("stroke", function(d) { return color(this.parentNode.__data__.name); })
    .append("title")
      .text(function(d) {
          return this.parentNode.parentNode.__data__.name;
          });

    type.append("text")
      .datum(labelInfo)
      .attr("transform", function(d) { return "translate(" + x(d.date) + "," + y(d.value) + ")"; })
      .attr("x", 3)
      .attr("dy", ".35em")
      .text(function(d) { return d.name; });
/*
var legend = svg.append("g")
  .attr("class","legend")
  .attr("transform","translate(50,30)")
  .style("font-size","12px")
  .call(d3.legend)
*/
    headers["Cache-Control"] = "public, max-age=30";
    headers["Expires"] = (new Date(Date.now() + 30000)).toUTCString();

  	res.writeHead( 200, headers );

	var svgObject = d3.select( document.body ).select( "svg" ).attr( 'xmlns', 'http://www.w3.org/2000/svg' );

	res.end( svgObject[0][0].outerHTML  );
});

function labelInfo(d) {
    var maxDate = d3.max(d.values,
        function(v) {
            return v.value > 0 ? v.date : new Date(0);
        }
    );
    var maxValue = d3.max(d.values,
        function(v) {
            return (v.date == maxDate) ? v.value : 0;
        }
    );

    var v = {
                name: d.name,
                value: maxValue,
                date: maxDate
            };
    return v;
}

};<commit_msg>don't zero line non-zero<commit_after>var d3 = require( 'd3' );

var headers = {
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept',
    'Access-Control-Request-Method': '*',
    'Access-Control-Allow-Methods': '*',
    'Content-Type': 'image/svg+xml'
};

var style = "svg {  \
  font: 10px sans-serif;    \
  fill:rgb(50%, 50%, 50%);  \
}   \
    \
.axis path, \
.axis line {    \
  fill: none;   \
  stroke: rgb(50%, 50%, 50%); \
  shape-rendering: crispEdges;  \
}   \
    \
.x.axis path {  \
  display: none;    \
}   \
    \
.line { \
  fill: none;   \
  stroke: steelblue;    \
  stroke-width: 1.5px;  \
}   \
.xtick { \
  transform: rotate(-35deg);  \
  text-anchor: end; \
}   \
";

module.exports = function (res, dataPath ) {

var document = require( 'jsdom' ).jsdom();
var margin = {top: 10, right: 100, bottom: 50, left: 40},
        width = 888 - margin.left - margin.right,
        height = 200 - margin.top - margin.bottom;

var parseDate = d3.time.format("%Y-%m-%d").parse;

var x = d3.time.scale()
    .range([0, width]);

var y = d3.scale.linear()
    .range([height, 0]);

var color = d3.scale.category10();

var xAxis = d3.svg.axis()
    .scale(x)
    .tickFormat(d3.time.format("%d %b %y"))
    .orient("bottom");

var yAxis = d3.svg.axis()
    .scale(y)
    .tickFormat(function(v){
        if (v >= 10000000000000) {
            return (v / 1000000000000).toFixed(0) + "Tn";
        }
        if (v >= 1000000000000) {
            return (v / 1000000000000).toFixed(1) + "Tn";
        }
        if (v >= 10000000000) {
            return (v / 1000000000).toFixed(0) + "Bn";
        }
        if (v >= 1000000000) {
            return (v / 1000000000).toFixed(1) + "Bn";
        }
        if (v >= 10000000) {
            return (v / 1000000).toFixed(0) + "M";
        }
        if (v >= 1000000) {
            return (v / 1000000).toFixed(1) + "M";
        }
        if (v >= 1000) {
            return (v / 1000).toFixed(0) + "K";
        }
        return v;
    })
    .orient("left");

var line = d3.svg.line()
    .defined(function(d) { return d.value != 0; })
    .x(function(d) { return x(d.date); })
    .y(function(d) { return y(d.value); });

var root = d3.select( document.body )
  .append( "svg" )
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom);

root.append("defs")
   .append("style")
   .text(style);

var svg = root.append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

d3.csv(dataPath, function(error, data) {
  if (error) {
	res.statusCode = 500;
	res.end(error.statusText);
    return;
  };

  color.domain(d3.keys(data[0]).filter(function(key) { return key !== "date"; }));

  data.forEach(function(d) {
    d.date = parseDate(d.date);
  });

  var types = color.domain().map(function(name) {
    return {
      name: name,
      values: data.map(function(d) {
        return {date: d.date, value: +d[name]||0};
      })
    };
  });

  var xDomain = d3.extent(data, function(d) { return d.date; });
  xDomain[1] = new Date();

  x.domain(xDomain);

  y.domain([
    d3.min(types, function(c) { return d3.min(c.values, function(v) { return v.value; }) / 1.25; }),
    d3.max(types, function(c) { return d3.max(c.values, function(v) { return v.value; }); })
  ]);

  svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis)
      .selectAll("text")
      .style("text-anchor", "end")
      .attr("dx", "-.5em")
      .attr("dy", ".125em")
      .attr("class", "xtick");

  svg.append("g")
      .attr("class", "y axis")
      .call(yAxis)
    .append("text")
      .attr("transform", "rotate(-90)")
      .attr("y", 6)
      .attr("dy", ".71em")
      .style("text-anchor", "end")
      .text("RPS");

  var type = svg.selectAll(".type")
      .data(types)
    .enter().append("g")
      .attr("class", "type");

  type.append("path")
      .attr("class", "line")
      .attr("d", function(d) { return line(d.values); })
      .style("stroke", function(d) { return color(d.name); })
    .append("title")
      .text(function(d) { return d.name; });

var point = type.append("g")
            .attr("class", "line-point");

    point.selectAll('circle')
        .data(function(d){
                return d.values
                    .filter(function(c) { return c.value != 0; })
        })
        .enter()
      .append('circle')
        .attr("cx", function(d) { return x(d.date) })
        .attr("cy", function(d) { return y(d.value) })
        .attr("r", 3)
        .style("fill", "white")
        .style("stroke", function(d) { return color(this.parentNode.__data__.name); })
    .append("title")
      .text(function(d) {
          return this.parentNode.parentNode.__data__.name;
          });

    type.append("text")
      .datum(labelInfo)
      .attr("transform", function(d) { return "translate(" + x(d.date) + "," + y(d.value) + ")"; })
      .attr("x", 3)
      .attr("dy", ".35em")
      .text(function(d) { return d.name; });

    headers["Cache-Control"] = "public, max-age=30";
    headers["Expires"] = (new Date(Date.now() + 30000)).toUTCString();

  	res.writeHead( 200, headers );

	var svgObject = d3.select( document.body ).select( "svg" ).attr( 'xmlns', 'http://www.w3.org/2000/svg' );

	res.end( svgObject[0][0].outerHTML  );
});

function labelInfo(d) {
    var maxDate = d3.max(d.values,
        function(v) {
            return v.value > 0 ? v.date : new Date(0);
        }
    );
    var maxValue = d3.max(d.values,
        function(v) {
            return (v.date == maxDate) ? v.value : 0;
        }
    );

    var v = {
                name: d.name,
                value: maxValue,
                date: maxDate
            };
    return v;
}

};<|endoftext|>


<commit_before>const Watchpack2 = require('./Watchpack2')
const childProcess = require('child_process')
const killer = require('killer')

class WatchpackFork extends Watchpack2 {
  constructor (options) {
    let {
      fork,
      restartAfterAggregation
    } = options

    if (typeof fork === 'string') {
      fork = {modulePath: fork}
    }

    fork = Object.assign({
      args: process.argv.slice(2)
    }, fork)

    if (restartAfterAggregation) {
      restartAfterAggregation = true
    }

    super(options)

    this.fork = fork

    if (restartAfterAggregation) {
      this.on('aggregated', () => {
        this.close(() => this.watch())
      })
    }
  }

  close (callback) {
    const done = () => {
      this.child = undefined

      callback && callback()
    }

    return super.close(() => {
      if (!this.child) {
        return done()
      }

      killer(this.child.pid, done)
    })
  }

  watch (callback) {
    return super.watch(() => {
      if (!this.child) {
        const {
          modulePath,
          args,
          options
        } = this.fork

        this.child = childProcess.fork(modulePath, args, options)
      }

      callback && callback()
    })
  }
}

module.exports = WatchpackFork
<commit_msg>Fix option restartAfterAggregation<commit_after>const Watchpack2 = require('./Watchpack2')
const childProcess = require('child_process')
const killer = require('killer')

class WatchpackFork extends Watchpack2 {
  constructor (options) {
    let {
      fork,
      restartAfterAggregation
    } = options

    if (typeof fork === 'string') {
      fork = {modulePath: fork}
    }

    fork = Object.assign({
      args: process.argv.slice(2)
    }, fork)

    super(options)

    this.fork = fork

    if (restartAfterAggregation) {
      this.on('aggregated', () => {
        this.close(() => this.watch())
      })
    }
  }

  close (callback) {
    const done = () => {
      this.child = undefined

      callback && callback()
    }

    return super.close(() => {
      if (!this.child) {
        return done()
      }

      killer(this.child.pid, done)
    })
  }

  watch (callback) {
    return super.watch(() => {
      if (!this.child) {
        const {
          modulePath,
          args,
          options
        } = this.fork

        this.child = childProcess.fork(modulePath, args, options)
      }

      callback && callback()
    })
  }
}

module.exports = WatchpackFork
<|endoftext|>


<commit_before>"use strict";

const url = require('url');

const debug = require('debug')('cardinal:queued-media');
const https = require('follow-redirects').https;

const Types = require('./types');
const Utils = require('./utils');

let logger = null;

class QueuedMedia {
  constructor(musicPlayer, record) {
    this.musicPlayer = musicPlayer;
    this.type = record.type;
    this.ownerId = record.ownerId;
    this.guildId = record.guildId;

    this.id = '';
    this.title = record.info.title || '';
    this.url = '';
    this.duration = 0;
    this.stream = null;
    this.time = null;

    if (this.type === Types.YTDL) {
      this.id = record.info.video_id;
      this.duration = record.info.length_seconds;
      this.formats = record.formats;
      this.formatIndex = 0;

      const format = this.formats[this.formatIndex];
      this.encoding = format.audioEncoding;
      this.url = format.url;
    } else if (this.type === Types.LOCAL) {
      this.format = record.info.format;
      this.encoding = record.info.encoding;
      this.url = record.info.url;
    } else {
      throw new Error(`unknown type: ${this.type}`);
    }

    this.play = this.play.bind(this);
    this.stopPlaying = this.stopPlaying.bind(this);
    this.printString = this.printString.bind(this);
  }

  static initialize(container) {
    logger = container.get('logger');
  }

  hookEncoderEvents() {
    this.encoder.once('end', () => {
      logger.debug('encoder end', this.id || this.url, this.encoding);
      this.donePlaying();
    });
    this.encoder.once('unpipe', () => {
      logger.debug('encoder unpipe', this.id || this.url, this.encoding);
    });
    this.encoder.once('error', (err) => {
      logger.debug('encoder error', this.id || this.url, this.encoding, err);
    });
  }

  hookPlayEvents() {
    this.stream = this.encoder.play();

    this.stream.resetTimestamp();
    this.stream.removeAllListeners('timestamp');
    this.stream.on('timestamp', (time) => {
      // logger.debug('stream timestamp', this.id || this.url, this.encoding, time);
      this.time = time;
    });
    this.stream.once('end', () => {
      logger.debug('stream end', this.id || this.url, this.encoding);
    });
    this.stream.once('unpipe', () => {
      logger.debug('stream unpipe', this.id || this.url, this.encoding);
    });
  }

  play(voiceConnection) {
    if (this.type === Types.YTDL) {
      return this.playHTTPS(voiceConnection);
    } else if (this.type === Types.LOCAL) {
      return this.playLocal(voiceConnection);
    }
  }

  playHTTPS(voiceConnection, retry) {
    if (this.encoding === 'opus') {
      this.playOpusHTTPS(voiceConnection);
    } else {
      logger.debug(`playHTTPS: ${this.id} ${this.encoding}`);
      logger.debug('audio is not opus, using ffmpeg');

      this.encoder = voiceConnection.createExternalEncoder({
        type: 'ffmpeg',
        source: this.url,
        format: 'opus',
        outputArgs: ['-ab', '64000'],
        debug: true,
      });

      this.hookEncoderEvents();
      this.hookPlayEvents();
    }
  }

  playLocal(voiceConnection) {
    logger.debug(`playLocal: ${this.url} ${this.encoding}`);

    if (this.encoding === 'opus') {
      this.encoder = voiceConnection.createExternalEncoder({
        type: 'WebmOpusPlayer',
        source: this.url,
      });
    } else {
      this.encoder = voiceConnection.createExternalEncoder({
        type: 'ffmpeg',
        source: this.url,
        format: 'opus',
        debug: true,
      });
    }

    this.hookEncoderEvents();
    this.hookPlayEvents();
  }

  playOpusHTTPS(voiceConnection, retry) {
    logger.debug(`playOpusHTTPS: ${this.id} ${this.encoding}`);

    const parsed = url.parse(this.url);
    //parsed.rejectUnauthorized = false;

    const req = https.get(parsed);

    req.once('response', (res) => {
      logger.debug(`have response: ${res.statusCode}`);

      if (res.statusCode === 302 && this.type === Types.YTDL && (this.formatIndex + 1) !== this.formats.length) {
        logger.debug(`damn youtube 302`);

        this.formatIndex++;

        const format = this.formats[this.formatIndex];
        this.encoding = format.audioEncoding;
        this.url = format.url;

        this.play(voiceConnection);
        return;
      } else if (res.statusCode === 302 && !retry) {
        logger.debug(`redirect playing ${this.id}: status code ${res.statusCode}`);
        setTimeout(() => this.playOpusHTTPS(voiceConnection, true), 1000);
        return;
      } else if (res.statusCode !== 200) {
        logger.debug(`error playing ${this.id}: status code ${res.statusCode}`);
        this.donePlaying();
        return;
      }

      this.encoder = voiceConnection.createExternalEncoder({
        type: 'WebmOpusPlayer',
        source: res,
        debug: true,
      });

      this.hookEncoderEvents();
      this.hookPlayEvents();
      this.stream.once('unpipe', () => res.destroy());
    });

    req.on('error', (err) => {
      logger.debug('request error', this.id, err);
      this.donePlaying();
    });
  }

  stopPlaying() {
    logger.debug('stopPlaying', this.id || this.url, this.encoding);

    if (this.stream) {
      this.stream.unpipeAll();
      this.stream = null;
    }

    if (this.encoder) {
      this.encoder.stop();
      this.encoder.destroy();
      this.encoder = null;
    }
  }

  donePlaying() {
    logger.debug('donePlaying', this.id || this.url, this.encoding);
    this.stopPlaying();
    this.musicPlayer.queuedDonePlaying(this);
  }

  printString() {
    const time = this.time ? `${Utils.formatTime(this.time | 0)}/` : '';
    const title = this.title ? `**${this.title}**` : '';

    if (this.type === Types.YTDL) {
      const length = Utils.formatTime(this.duration);

      return `(${time}${length}) \`[${this.encoding}]\` ${title} (${this.id}) (<@${this.ownerId}>)`;
    }
    return `NON-YTDL \`[${this.encoding}]\` ${title} - ${this.url}`;
  }
};

module.exports = QueuedMedia;
<commit_msg>MusicPlayer: don't stop playing when encoder finishes<commit_after>"use strict";

const url = require('url');

const debug = require('debug')('cardinal:queued-media');
const https = require('follow-redirects').https;

const Types = require('./types');
const Utils = require('./utils');

let logger = null;

class QueuedMedia {
  constructor(musicPlayer, record) {
    this.musicPlayer = musicPlayer;
    this.type = record.type;
    this.ownerId = record.ownerId;
    this.guildId = record.guildId;

    this.id = '';
    this.title = record.info.title || '';
    this.url = '';
    this.duration = 0;
    this.stream = null;
    this.time = null;

    if (this.type === Types.YTDL) {
      this.id = record.info.video_id;
      this.duration = record.info.length_seconds;
      this.formats = record.formats;
      this.formatIndex = 0;

      const format = this.formats[this.formatIndex];
      this.encoding = format.audioEncoding;
      this.url = format.url;
    } else if (this.type === Types.LOCAL) {
      this.format = record.info.format;
      this.encoding = record.info.encoding;
      this.url = record.info.url;
    } else {
      throw new Error(`unknown type: ${this.type}`);
    }

    this.play = this.play.bind(this);
    this.stopPlaying = this.stopPlaying.bind(this);
    this.printString = this.printString.bind(this);
  }

  static initialize(container) {
    logger = container.get('logger');
  }

  hookEncoderEvents() {
    this.encoder.once('end', () => {
      logger.debug('encoder end', this.id || this.url, this.encoding);
      //this.donePlaying();
    });
    this.encoder.once('unpipe', () => {
      logger.debug('encoder unpipe', this.id || this.url, this.encoding);
    });
    this.encoder.once('error', (err) => {
      logger.debug('encoder error', this.id || this.url, this.encoding, err);
    });
  }

  hookPlayEvents() {
    this.stream = this.encoder.play();

    this.stream.resetTimestamp();
    this.stream.removeAllListeners('timestamp');
    this.stream.on('timestamp', (time) => {
      // logger.debug('stream timestamp', this.id || this.url, this.encoding, time);
      this.time = time;
    });
    this.stream.once('end', () => {
      logger.debug('stream end', this.id || this.url, this.encoding);
    });
    this.stream.once('unpipe', () => {
      logger.debug('stream unpipe', this.id || this.url, this.encoding);
    });
  }

  play(voiceConnection) {
    if (this.type === Types.YTDL) {
      return this.playHTTPS(voiceConnection);
    } else if (this.type === Types.LOCAL) {
      return this.playLocal(voiceConnection);
    }
  }

  playHTTPS(voiceConnection, retry) {
    if (this.encoding === 'opus') {
      this.playOpusHTTPS(voiceConnection);
    } else {
      logger.debug(`playHTTPS: ${this.id} ${this.encoding}`);
      logger.debug('audio is not opus, using ffmpeg');

      this.encoder = voiceConnection.createExternalEncoder({
        type: 'ffmpeg',
        source: this.url,
        format: 'opus',
        outputArgs: ['-ab', '64000'],
        debug: true,
      });

      this.hookEncoderEvents();
      this.hookPlayEvents();
    }
  }

  playLocal(voiceConnection) {
    logger.debug(`playLocal: ${this.url} ${this.encoding}`);

    if (this.encoding === 'opus') {
      this.encoder = voiceConnection.createExternalEncoder({
        type: 'WebmOpusPlayer',
        source: this.url,
      });
    } else {
      this.encoder = voiceConnection.createExternalEncoder({
        type: 'ffmpeg',
        source: this.url,
        format: 'opus',
        debug: true,
      });
    }

    this.hookEncoderEvents();
    this.hookPlayEvents();
  }

  playOpusHTTPS(voiceConnection, retry) {
    logger.debug(`playOpusHTTPS: ${this.id} ${this.encoding}`);

    const parsed = url.parse(this.url);
    //parsed.rejectUnauthorized = false;

    const req = https.get(parsed);

    req.once('response', (res) => {
      logger.debug(`have response: ${res.statusCode}`);

      if (res.statusCode === 302 && this.type === Types.YTDL && (this.formatIndex + 1) !== this.formats.length) {
        logger.debug(`damn youtube 302`);

        this.formatIndex++;

        const format = this.formats[this.formatIndex];
        this.encoding = format.audioEncoding;
        this.url = format.url;

        this.play(voiceConnection);
        return;
      } else if (res.statusCode === 302 && !retry) {
        logger.debug(`redirect playing ${this.id}: status code ${res.statusCode}`);
        setTimeout(() => this.playOpusHTTPS(voiceConnection, true), 1000);
        return;
      } else if (res.statusCode !== 200) {
        logger.debug(`error playing ${this.id}: status code ${res.statusCode}`);
        this.donePlaying();
        return;
      }

      this.encoder = voiceConnection.createExternalEncoder({
        type: 'WebmOpusPlayer',
        source: res,
        debug: true,
      });

      this.hookEncoderEvents();
      this.hookPlayEvents();
      this.stream.once('unpipe', () => res.destroy());
    });

    req.on('error', (err) => {
      logger.debug('request error', this.id, err);
      this.donePlaying();
    });
  }

  stopPlaying() {
    logger.debug('stopPlaying', this.id || this.url, this.encoding);

    if (this.stream) {
      this.stream.unpipeAll();
      this.stream = null;
    }

    if (this.encoder) {
      this.encoder.stop();
      this.encoder.destroy();
      this.encoder = null;
    }
  }

  donePlaying() {
    logger.debug('donePlaying', this.id || this.url, this.encoding);
    this.stopPlaying();
    this.musicPlayer.queuedDonePlaying(this);
  }

  printString() {
    const time = this.time ? `${Utils.formatTime(this.time | 0)}/` : '';
    const title = this.title ? `**${this.title}**` : '';

    if (this.type === Types.YTDL) {
      const length = Utils.formatTime(this.duration);

      return `(${time}${length}) \`[${this.encoding}]\` ${title} (${this.id}) (<@${this.ownerId}>)`;
    }
    return `NON-YTDL \`[${this.encoding}]\` ${title} - ${this.url}`;
  }
};

module.exports = QueuedMedia;
<|endoftext|>